Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package aws-c-common for openSUSE:Factory checked in at 2026-08-05 19:07:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/aws-c-common (Old) and /work/SRC/openSUSE:Factory/.aws-c-common.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "aws-c-common" Wed Aug 5 19:07:41 2026 rev:34 rq:1369462 version:0.14.4 Changes: -------- --- /work/SRC/openSUSE:Factory/aws-c-common/aws-c-common.changes 2026-07-21 22:59:49.016518765 +0200 +++ /work/SRC/openSUSE:Factory/.aws-c-common.new.16738/aws-c-common.changes 2026-08-05 19:07:43.911783432 +0200 @@ -1,0 +2,9 @@ +Tue Aug 4 08:55:27 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 0.14.4 + * aws_file_get_last_modified_epoch by @TingDaoK in (#1258) +- from version 0.14.3 + * Add HWASan suppression support by @antonio2368 in (#1256) + * Fix windows nonascii env by @kai-ion in (#1260) + +------------------------------------------------------------------- Old: ---- v0.14.2.tar.gz New: ---- v0.14.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ aws-c-common.spec ++++++ --- /var/tmp/diff_new_pack.PSWVsp/_old 2026-08-05 19:07:44.551805550 +0200 +++ /var/tmp/diff_new_pack.PSWVsp/_new 2026-08-05 19:07:44.555805688 +0200 @@ -19,7 +19,7 @@ %define library_version 1.0.0 %define library_soversion 1 Name: aws-c-common -Version: 0.14.2 +Version: 0.14.4 Release: 0 Summary: Core C99 package for AWS SDK for C License: Apache-2.0 ++++++ v0.14.2.tar.gz -> v0.14.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/include/aws/common/file.h new/aws-c-common-0.14.4/include/aws/common/file.h --- old/aws-c-common-0.14.2/include/aws/common/file.h 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/include/aws/common/file.h 2026-07-21 19:03:28.000000000 +0200 @@ -308,6 +308,32 @@ AWS_COMMON_API bool aws_file_direct_io_is_supported(void); +/* + * Gets the last modification time of an open file as nanoseconds since unix epoch. + * + * Unix flavors use fstat with nanosecond-precision fields (st_mtim on Linux/FreeBSD, + * st_mtimespec on Apple). Windows uses GetFileTime on the HANDLE queried from the + * libc FILE pointer (100-nanosecond FILETIME precision). + * + * Platform timestamp-visibility guarantees differ: + * - POSIX: st_mtime/st_mtim is updated by write(2) itself (see inode(7): + * https://man7.org/linux/man-pages/man7/inode.7.html). Callers using buffered stdio + * writes must fflush() or fclose() first so write(2) actually happens; once it has, + * a subsequent stat()/fstat() sees the new timestamp immediately, no fsync needed + * (fsync(2) confirms fdatasync() skips flushing st_mtime for this reason: + * https://man7.org/linux/man-pages/man2/fsync.2.html). + * - Windows: the last write time is only guaranteed correct once all write handles are + * closed; FlushFileBuffers() does not help. See "File Times": + * https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times + * + * As a result, if a file was written to and you need to observe that write in its + * updated timestamp, close the write handle first, then open a new handle and call + * this function on that new handle. Calling this function on the (now-closed) write + * handle is not valid on any platform, since a closed FILE* cannot be used at all. + */ +AWS_COMMON_API +int aws_file_get_last_modified_epoch(FILE *file, uint64_t *last_modified_ns); + AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_COMMON_FILE_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/include/aws/common/macros.h new/aws-c-common-0.14.4/include/aws/common/macros.h --- old/aws-c-common-0.14.2/include/aws/common/macros.h 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/include/aws/common/macros.h 2026-07-21 19:03:28.000000000 +0200 @@ -114,6 +114,20 @@ #endif #if defined(__has_feature) +# if __has_feature(hwaddress_sanitizer) +# define AWS_SUPPRESS_HWASAN __attribute__((no_sanitize("hwaddress"))) +# endif +#elif defined(__SANITIZE_HWADDRESS__) +# if defined(__GNUC__) +# define AWS_SUPPRESS_HWASAN __attribute__((no_sanitize("hwaddress"))) +# endif +#endif + +#if !defined(AWS_SUPPRESS_HWASAN) +# define AWS_SUPPRESS_HWASAN +#endif + +#if defined(__has_feature) # if __has_feature(thread_sanitizer) # define AWS_SUPPRESS_TSAN __attribute__((no_sanitize("thread"))) # endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/include/aws/common/private/lookup3.inl new/aws-c-common-0.14.4/include/aws/common/private/lookup3.inl --- old/aws-c-common-0.14.2/include/aws/common/private/lookup3.inl 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/include/aws/common/private/lookup3.inl 2026-07-21 19:03:28.000000000 +0200 @@ -496,8 +496,8 @@ * the key. *pc is better mixed than *pb, so use *pc first. If you want * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". */ -/* AddressSanitizer hates this implementation, even though it's innocuous */ -AWS_SUPPRESS_ASAN static void hashlittle2( +/* AddressSanitizer and HWAddressSanitizer hate this implementation, even though it's innocuous */ +AWS_SUPPRESS_ASAN AWS_SUPPRESS_HWASAN static void hashlittle2( const void *key, /* the key to hash */ size_t length, /* length of the key */ uint32_t *pc, /* IN: primary initval, OUT: primary hash */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/source/allocator_sba.c new/aws-c-common-0.14.4/source/allocator_sba.c --- old/aws-c-common-0.14.2/source/allocator_sba.c 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/source/allocator_sba.c 2026-07-21 19:03:28.000000000 +0200 @@ -406,7 +406,9 @@ return aws_mem_acquire(sba->allocator, size); } -AWS_SUPPRESS_ASAN AWS_SUPPRESS_TSAN static void s_sba_free(struct small_block_allocator *sba, void *addr) { +AWS_SUPPRESS_ASAN AWS_SUPPRESS_HWASAN AWS_SUPPRESS_TSAN static void s_sba_free( + struct small_block_allocator *sba, + void *addr) { if (!addr) { return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/source/posix/file.c new/aws-c-common-0.14.4/source/posix/file.c --- old/aws-c-common-0.14.2/source/posix/file.c 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/source/posix/file.c 2026-07-21 19:03:28.000000000 +0200 @@ -2,6 +2,9 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ + +#define _GNU_SOURCE /* NOLINT(bugprone-reserved-identifier) */ + #include <aws/common/environment.h> #include <aws/common/file.h> #include <aws/common/logging.h> @@ -308,3 +311,30 @@ return AWS_OP_SUCCESS; } + +int aws_file_get_last_modified_epoch(FILE *file, uint64_t *last_modified_ns) { + + struct stat file_stats; + + int fd = fileno(file); + if (fd == -1) { + return aws_raise_error(AWS_ERROR_INVALID_FILE_HANDLE); + } + + if (fstat(fd, &file_stats)) { + int errno_value = errno; /* Always cache errno before potential side-effect */ + return aws_translate_and_raise_io_error(errno_value); + } + +#if defined(AWS_OS_APPLE) + uint64_t secs = (uint64_t)file_stats.st_mtimespec.tv_sec; + uint64_t nsecs = (uint64_t)file_stats.st_mtimespec.tv_nsec; +#else + uint64_t secs = (uint64_t)file_stats.st_mtim.tv_sec; + uint64_t nsecs = (uint64_t)file_stats.st_mtim.tv_nsec; +#endif + + *last_modified_ns = secs * (uint64_t)1000000000 + nsecs; + + return AWS_OP_SUCCESS; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/source/windows/environment.c new/aws-c-common-0.14.4/source/windows/environment.c --- old/aws-c-common-0.14.2/source/windows/environment.c 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/source/windows/environment.c 2026-07-21 19:03:28.000000000 +0200 @@ -10,36 +10,61 @@ struct aws_string *aws_get_env(struct aws_allocator *allocator, const char *name) { #ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4996) -#endif + /* + * On Windows, environment variables are natively stored as wide (UTF-16) + * strings. The narrow getenv()/_dupenv_s() APIs return values in the active + * ANSI code page, which is a lossy compatibility layer. Downstream code + * (aws_fopen_safe) assumes all strings are UTF-8, so reading through the + * narrow API produces encoding mismatches for non-ASCII values. + * + * We use _wdupenv_s to read the authoritative wide value, then convert to + * UTF-8 for consistent handling throughout the SDK. + */ + + /* Convert variable name to wide (env var names are ASCII, which is valid UTF-8) */ + struct aws_byte_cursor name_cursor = aws_byte_cursor_from_c_str(name); + struct aws_wstring *w_name = aws_string_convert_to_wchar_from_byte_cursor(allocator, &name_cursor); + if (!w_name) { + return NULL; + } + + /* Read value as wide characters using _wdupenv_s */ + wchar_t *w_value = NULL; + size_t w_value_len = 0; + errno_t err = _wdupenv_s(&w_value, &w_value_len, aws_wstring_c_str(w_name)); + aws_wstring_destroy(w_name); + + if (err != 0 || w_value == NULL || w_value_len == 0) { + free(w_value); + return NULL; + } + + /* Convert wide value to UTF-8 */ + struct aws_string *result = aws_string_convert_from_wchar_c_str(allocator, w_value); + free(w_value); + + return result; +#else const char *value = getenv(name); -#ifdef _MSC_VER -# pragma warning(pop) -#endif if (value == NULL) { return NULL; } return aws_string_new_from_c_str(allocator, value); +#endif } struct aws_string *aws_get_env_nonempty(struct aws_allocator *allocator, const char *name) { -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4996) -#endif - const char *value = getenv(name); -#ifdef _MSC_VER -# pragma warning(pop) -#endif - - if (value == NULL || value[0] == '\0') { + struct aws_string *value = aws_get_env(allocator, name); + if (value == NULL) { return NULL; } - - return aws_string_new_from_c_str(allocator, value); + if (value->len == 0) { + aws_string_destroy(value); + return NULL; + } + return value; } int aws_get_environment_value( @@ -47,26 +72,7 @@ const struct aws_string *variable_name, struct aws_string **value_out) { -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4996) -#endif - - const char *value = getenv(aws_string_c_str(variable_name)); - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - - if (value == NULL) { - *value_out = NULL; - return AWS_OP_SUCCESS; - } - - *value_out = aws_string_new_from_c_str(allocator, value); - if (*value_out == NULL) { - return aws_raise_error(AWS_ERROR_ENVIRONMENT_GET); - } + *value_out = aws_get_env(allocator, aws_string_c_str(variable_name)); return AWS_OP_SUCCESS; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/source/windows/file.c new/aws-c-common-0.14.4/source/windows/file.c --- old/aws-c-common-0.14.2/source/windows/file.c 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/source/windows/file.c 2026-07-21 19:03:28.000000000 +0200 @@ -544,3 +544,43 @@ return AWS_OP_SUCCESS; } + +int aws_file_get_last_modified_epoch(FILE *file, uint64_t *last_modified_ns) { + if (file == NULL) { + return aws_raise_error(AWS_ERROR_INVALID_FILE_HANDLE); + } + + int fd = _fileno(file); + if (fd == -1) { + return aws_raise_error(AWS_ERROR_INVALID_FILE_HANDLE); + } + + HANDLE os_file = (HANDLE)_get_osfhandle(fd); + if (os_file == INVALID_HANDLE_VALUE) { + int errno_value = errno; /* Always cache errno before potential side-effect */ + return aws_translate_and_raise_io_error(errno_value); + } + + FILETIME last_write_time; + if (!GetFileTime(os_file, NULL /*creation*/, NULL /*access*/, &last_write_time)) { + return aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE); + } + + /* + * FILETIME is 100-nanosecond intervals since January 1, 1601 UTC. + * Convert to nanoseconds since unix epoch (January 1, 1970 UTC). + * The difference is 11644473600 seconds = 116444736000000000 hundred-nanos. + * See aws_sys_clock_get_ticks() in clock.c for the same conversion. + */ + ULARGE_INTEGER int_conv; + int_conv.LowPart = last_write_time.dwLowDateTime; + int_conv.HighPart = last_write_time.dwHighDateTime; + + static const uint64_t WINDOWS_TICK = 10000000; + static const uint64_t EC_TO_UNIX_EPOCH = 11644473600LL; + static const uint64_t FILE_TIME_TO_NS = 100; + + *last_modified_ns = (int_conv.QuadPart - (WINDOWS_TICK * EC_TO_UNIX_EPOCH)) * FILE_TIME_TO_NS; + + return AWS_OP_SUCCESS; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/tests/CMakeLists.txt new/aws-c-common-0.14.4/tests/CMakeLists.txt --- old/aws-c-common-0.14.2/tests/CMakeLists.txt 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/tests/CMakeLists.txt 2026-07-21 19:03:28.000000000 +0200 @@ -415,6 +415,7 @@ add_test_case(test_environment_functions) add_test_case(test_env_functions) +add_test_case(test_env_non_ascii_path) add_test_case(short_argument_parse) add_test_case(long_argument_parse) @@ -534,6 +535,7 @@ add_test_case(test_file_path_read_from_offset) add_test_case(test_file_path_read_from_offset_direct_io_chunking) add_test_case(test_file_path_write_to_offset_direct_io) +add_test_case(test_file_get_last_modified_epoch) add_test_case(test_json_parse_from_string) add_test_case(test_json_parse_to_string) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/tests/environment_test.c new/aws-c-common-0.14.4/tests/environment_test.c --- old/aws-c-common-0.14.2/tests/environment_test.c 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/tests/environment_test.c 2026-07-21 19:03:28.000000000 +0200 @@ -82,3 +82,33 @@ } AWS_TEST_CASE(test_env_functions, s_test_env_functions_fn) + +static int s_test_env_non_ascii_path_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; +#ifdef AWS_OS_WINDOWS + /* Set a non-ASCII environment variable. The value 0xE9 is 'é' in the + * ANSI code page (CP-1252), simulating a Windows user whose USERPROFILE + * contains accented characters. */ + AWS_STATIC_STRING_FROM_LITERAL(s_var_name, "AWS_TEST_NONASCII_VAR"); + struct aws_string *ansi_value = aws_string_new_from_c_str(allocator, "C:\\Users\\hom\xE9"); + aws_set_environment_value(s_var_name, ansi_value); + aws_string_destroy(ansi_value); + + /* Read it back through aws_get_env */ + struct aws_string *value = aws_get_env(allocator, "AWS_TEST_NONASCII_VAR"); + ASSERT_NOT_NULL(value); + + /* The value should be valid UTF-8. U+00E9 in UTF-8 is the two bytes 0xC3 0xA9. */ + const char *expected_utf8 = "C:\\Users\\hom\xC3\xA9"; + ASSERT_TRUE(strcmp(aws_string_c_str(value), expected_utf8) == 0); + aws_string_destroy(value); + + /* Clean up */ + aws_unset_environment_value(s_var_name); +#else + (void)allocator; +#endif + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(test_env_non_ascii_path, s_test_env_non_ascii_path_fn) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-common-0.14.2/tests/file_test.c new/aws-c-common-0.14.4/tests/file_test.c --- old/aws-c-common-0.14.2/tests/file_test.c 2026-07-09 18:53:07.000000000 +0200 +++ new/aws-c-common-0.14.4/tests/file_test.c 2026-07-21 19:03:28.000000000 +0200 @@ -4,10 +4,12 @@ */ #include <aws/common/allocator.h> +#include <aws/common/clock.h> #include <aws/common/device_random.h> #include <aws/common/file.h> #include <aws/common/string.h> #include <aws/common/system_info.h> +#include <aws/common/thread.h> #include <aws/testing/aws_test_harness.h> @@ -1038,3 +1040,61 @@ } AWS_TEST_CASE(test_file_path_write_to_offset_direct_io, s_test_file_path_write_to_offset_direct_io) + +static int s_test_file_get_last_modified_epoch_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + const char *file_path_cstr = "last_modified_test.txt"; + struct aws_string *file_path = aws_string_new_from_c_str(allocator, file_path_cstr); + + /* Create a file and write something */ + FILE *file = aws_fopen(file_path_cstr, "w"); + ASSERT_NOT_NULL(file); + fprintf(file, "hello"); + fclose(file); /* must close the write handle: on Windows the last write time is only + guaranteed correct once all writing handles are closed (see doc comment + on aws_file_get_last_modified_epoch) */ + + /* Get last modified time on a fresh handle */ + file = aws_fopen(file_path_cstr, "r"); + ASSERT_NOT_NULL(file); + + uint64_t first_modified_ns = 0; + ASSERT_SUCCESS(aws_file_get_last_modified_epoch(file, &first_modified_ns)); + fclose(file); + + /* Verify it's less than current time */ + uint64_t now_ns = 0; + ASSERT_SUCCESS(aws_sys_clock_get_ticks(&now_ns)); + ASSERT_TRUE(first_modified_ns <= now_ns); + ASSERT_TRUE(first_modified_ns > 0); + + /* Sleep to ensure filesystem timestamp advances */ + aws_thread_current_sleep((uint64_t)1000000000); /* 1 second */ + + /* Modify the file */ + file = aws_fopen(file_path_cstr, "w"); + ASSERT_NOT_NULL(file); + fprintf(file, "world"); + fclose(file); /* close write handle before re-querying, same reason as above */ + + /* Get last modified time again on a fresh handle */ + file = aws_fopen(file_path_cstr, "r"); + ASSERT_NOT_NULL(file); + + uint64_t second_modified_ns = 0; + ASSERT_SUCCESS(aws_file_get_last_modified_epoch(file, &second_modified_ns)); + fclose(file); + + /* Second modification time must be strictly later than first */ + ASSERT_TRUE(second_modified_ns > first_modified_ns); + ASSERT_TRUE(second_modified_ns > now_ns); + + /* Cleanup */ + remove(file_path_cstr); + aws_string_destroy(file_path); + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(test_file_get_last_modified_epoch, s_test_file_get_last_modified_epoch_fn)
