Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package aws-c-s3 for openSUSE:Factory checked in at 2026-04-11 22:26:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/aws-c-s3 (Old) and /work/SRC/openSUSE:Factory/.aws-c-s3.new.21863 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "aws-c-s3" Sat Apr 11 22:26:52 2026 rev:38 rq:1346081 version:0.12.2 Changes: -------- --- /work/SRC/openSUSE:Factory/aws-c-s3/aws-c-s3.changes 2026-04-09 16:25:07.071433123 +0200 +++ /work/SRC/openSUSE:Factory/.aws-c-s3.new.21863/aws-c-s3.changes 2026-04-11 22:32:33.083549369 +0200 @@ -1,0 +2,8 @@ +Fri Apr 10 08:53:14 UTC 2026 - John Paul Adrian Glaubitz <[email protected]> + +- Update to version 0.12.2 + * Better checksumming support by @DmitriyMusatkin in (#623) +- from version 0.12.1 + * Fix the try-trim logic by @TingDaoK in (#621) + +------------------------------------------------------------------- Old: ---- v0.12.0.tar.gz New: ---- v0.12.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ aws-c-s3.spec ++++++ --- /var/tmp/diff_new_pack.Ya7aeT/_old 2026-04-11 22:32:33.623571456 +0200 +++ /var/tmp/diff_new_pack.Ya7aeT/_new 2026-04-11 22:32:33.623571456 +0200 @@ -19,7 +19,7 @@ %define library_version 1.0.0 %define library_soversion 0unstable Name: aws-c-s3 -Version: 0.12.0 +Version: 0.12.2 Release: 0 Summary: AWS Cross-Platform, C99 wrapper for cryptography primitives License: Apache-2.0 ++++++ v0.12.0.tar.gz -> v0.12.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/include/aws/s3/private/s3_checksums.h new/aws-c-s3-0.12.2/include/aws/s3/private/s3_checksums.h --- old/aws-c-s3-0.12.0/include/aws/s3/private/s3_checksums.h 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/include/aws/s3/private/s3_checksums.h 2026-04-02 20:58:10.000000000 +0200 @@ -14,11 +14,15 @@ /* List to check the checksum algorithm to use based on the priority. */ static const enum aws_s3_checksum_algorithm s_checksum_algo_priority_list[] = { + AWS_SCA_XXHASH3_128, + AWS_SCA_XXHASH3_64, AWS_SCA_CRC64NVME, AWS_SCA_CRC32C, AWS_SCA_CRC32, - AWS_SCA_SHA1, + AWS_SCA_XXHASH64, + AWS_SCA_SHA512, AWS_SCA_SHA256, + AWS_SCA_SHA1, }; AWS_STATIC_ASSERT(AWS_ARRAY_SIZE(s_checksum_algo_priority_list) == (AWS_SCA_END - AWS_SCA_INIT + 1)); @@ -36,6 +40,7 @@ bool good; union { struct aws_hash *hash; + struct aws_xxhash *xxhash; uint32_t crc_val_32bit; uint64_t crc_val_64bit; } impl; @@ -58,6 +63,10 @@ bool crc32; bool sha1; bool sha256; + bool sha512; + bool xxhash64; + bool xxhash3_64; + bool xxhash3_128; } response_checksum_algorithms; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/include/aws/s3/s3_client.h new/aws-c-s3-0.12.2/include/aws/s3/s3_client.h --- old/aws-c-s3-0.12.0/include/aws/s3/s3_client.h 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/include/aws/s3/s3_client.h 2026-04-02 20:58:10.000000000 +0200 @@ -283,7 +283,11 @@ AWS_SCA_SHA1, AWS_SCA_SHA256, AWS_SCA_CRC64NVME, - AWS_SCA_END = AWS_SCA_CRC64NVME, + AWS_SCA_SHA512, + AWS_SCA_XXHASH64, + AWS_SCA_XXHASH3_64, + AWS_SCA_XXHASH3_128, + AWS_SCA_END = AWS_SCA_XXHASH3_128, }; enum aws_s3_checksum_location { @@ -724,7 +728,7 @@ * * The list of algorithms for user to pick up when validate the checksum. Client will pick up the algorithm from the * list with the priority based on performance, and the algorithm sent by server. The priority based on performance - * is [CRC64NVME, CRC32C, CRC32, SHA1, SHA256]. + * is [XXHASH3_128, XXHASH3_64, CRC64NVME, CRC32C, CRC32, XXHASH64, SHA512, SHA256, SHA1]. * * If the response checksum was validated by client, the result will indicate which algorithm was picked. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/source/s3_checksums.c new/aws-c-s3-0.12.2/source/s3_checksums.c --- old/aws-c-s3-0.12.0/source/s3_checksums.c 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/source/s3_checksums.c 2026-04-02 20:58:10.000000000 +0200 @@ -2,17 +2,28 @@ #include "aws/s3/private/s3_util.h" #include <aws/cal/hash.h> #include <aws/checksums/crc.h> +#include <aws/checksums/xxhash.h> #include <aws/http/request_response.h> #define AWS_CRC32_LEN sizeof(uint32_t) #define AWS_CRC32C_LEN sizeof(uint32_t) #define AWS_CRC64_LEN sizeof(uint64_t) +enum { + AWS_XXHASH64_LEN = 8, + AWS_XXHASH3_64_LEN = 8, + AWS_XXHASH3_128_LEN = 16, +}; + static const struct aws_byte_cursor s_crc64nvme_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CRC64NVME"); static const struct aws_byte_cursor s_crc32c_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CRC32C"); static const struct aws_byte_cursor s_crc32_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("CRC32"); static const struct aws_byte_cursor s_sha1_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SHA1"); static const struct aws_byte_cursor s_sha256_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SHA256"); +static const struct aws_byte_cursor s_sha512_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SHA512"); +static const struct aws_byte_cursor s_xxhash64_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("XXHASH64"); +static const struct aws_byte_cursor s_xxhash3_64_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("XXHASH3"); +static const struct aws_byte_cursor s_xxhash3_128_algorithm_value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("XXHASH128"); static const struct aws_byte_cursor s_crc64nvme_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-crc64nvme"); @@ -22,6 +33,14 @@ static const struct aws_byte_cursor s_sha1_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-sha1"); static const struct aws_byte_cursor s_sha256_header_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-sha256"); +static const struct aws_byte_cursor s_sha512_header_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-sha512"); +static const struct aws_byte_cursor s_xxhash64_header_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-xxhash64"); +static const struct aws_byte_cursor s_xxhash3_64_header_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-xxhash3"); +static const struct aws_byte_cursor s_xxhash3_128_header_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-checksum-xxhash128"); static const struct aws_byte_cursor s_crc64nvme_completed_part_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumCRC64NVME"); @@ -32,6 +51,14 @@ static const struct aws_byte_cursor s_sha1_completed_part_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumSHA1"); static const struct aws_byte_cursor s_sha256_completed_part_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumSHA256"); +static const struct aws_byte_cursor s_sha512_completed_part_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumSHA512"); +static const struct aws_byte_cursor s_xxhash64_completed_part_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumXXHASH64"); +static const struct aws_byte_cursor s_xxhash3_64_completed_part_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumXXHASH3"); +static const struct aws_byte_cursor s_xxhash3_128_completed_part_name = + AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("ChecksumXXHASH128"); static const struct aws_byte_cursor s_empty_cursor = { .len = 0, .ptr = NULL, @@ -49,6 +76,14 @@ return AWS_SHA1_LEN; case AWS_SCA_SHA256: return AWS_SHA256_LEN; + case AWS_SCA_SHA512: + return AWS_SHA512_LEN; + case AWS_SCA_XXHASH64: + return AWS_XXHASH64_LEN; + case AWS_SCA_XXHASH3_64: + return AWS_XXHASH3_64_LEN; + case AWS_SCA_XXHASH3_128: + return AWS_XXHASH3_128_LEN; default: return 0; } @@ -66,6 +101,14 @@ return s_sha1_header_name; case AWS_SCA_SHA256: return s_sha256_header_name; + case AWS_SCA_SHA512: + return s_sha512_header_name; + case AWS_SCA_XXHASH64: + return s_xxhash64_header_name; + case AWS_SCA_XXHASH3_64: + return s_xxhash3_64_header_name; + case AWS_SCA_XXHASH3_128: + return s_xxhash3_128_header_name; default: return s_empty_cursor; } @@ -83,6 +126,14 @@ return s_sha1_algorithm_value; case AWS_SCA_SHA256: return s_sha256_algorithm_value; + case AWS_SCA_SHA512: + return s_sha512_algorithm_value; + case AWS_SCA_XXHASH64: + return s_xxhash64_algorithm_value; + case AWS_SCA_XXHASH3_64: + return s_xxhash3_64_algorithm_value; + case AWS_SCA_XXHASH3_128: + return s_xxhash3_128_algorithm_value; default: return s_empty_cursor; } @@ -100,26 +151,49 @@ return s_sha1_completed_part_name; case AWS_SCA_SHA256: return s_sha256_completed_part_name; + case AWS_SCA_SHA512: + return s_sha512_completed_part_name; + case AWS_SCA_XXHASH64: + return s_xxhash64_completed_part_name; + case AWS_SCA_XXHASH3_64: + return s_xxhash3_64_completed_part_name; + case AWS_SCA_XXHASH3_128: + return s_xxhash3_128_completed_part_name; default: return s_empty_cursor; } } -void s3_hash_destroy(struct aws_s3_checksum *checksum) { +static void s_hash_destroy(struct aws_s3_checksum *checksum) { struct aws_hash *hash = checksum->impl.hash; aws_hash_destroy(hash); aws_mem_release(checksum->allocator, checksum); } -int s3_hash_update(struct aws_s3_checksum *checksum, const struct aws_byte_cursor *to_checksum) { +static int s_hash_update(struct aws_s3_checksum *checksum, const struct aws_byte_cursor *to_checksum) { return aws_hash_update(checksum->impl.hash, to_checksum); } -int s3_hash_finalize(struct aws_s3_checksum *checksum, struct aws_byte_buf *output) { +static int s_hash_finalize(struct aws_s3_checksum *checksum, struct aws_byte_buf *output) { checksum->good = false; return aws_hash_finalize(checksum->impl.hash, output, 0); } +static void s_xxhash_destroy(struct aws_s3_checksum *checksum) { + struct aws_xxhash *hash = checksum->impl.xxhash; + aws_xxhash_destroy(hash); + aws_mem_release(checksum->allocator, checksum); +} + +static int s_xxhash_update(struct aws_s3_checksum *checksum, const struct aws_byte_cursor *to_checksum) { + return aws_xxhash_update(checksum->impl.xxhash, *to_checksum); +} + +static int s_xxhash_finalize(struct aws_s3_checksum *checksum, struct aws_byte_buf *output) { + checksum->good = false; + return aws_xxhash_finalize(checksum->impl.xxhash, output); +} + static int s_crc_finalize_helper(struct aws_s3_checksum *checksum, struct aws_byte_buf *out) { AWS_PRECONDITION(aws_byte_buf_is_valid(out)); @@ -180,9 +254,15 @@ } static struct aws_checksum_vtable hash_vtable = { - .update = s3_hash_update, - .finalize = s3_hash_finalize, - .destroy = s3_hash_destroy, + .update = s_hash_update, + .finalize = s_hash_finalize, + .destroy = s_hash_destroy, +}; + +static struct aws_checksum_vtable s_xxhash_vtable = { + .update = s_xxhash_update, + .finalize = s_xxhash_finalize, + .destroy = s_xxhash_destroy, }; static struct aws_checksum_vtable crc32_vtable = { @@ -217,6 +297,27 @@ return checksum; } +typedef struct aws_xxhash *(aws_xxhash_new_fn)(struct aws_allocator *allocator, uint64_t seed); + +struct aws_s3_checksum *s_aws_xxhash_new( + struct aws_allocator *allocator, + aws_xxhash_new_fn hash_fn, + size_t digest_size) { + struct aws_s3_checksum *checksum = aws_mem_calloc(allocator, 1, sizeof(struct aws_s3_checksum)); + struct aws_xxhash *hash = hash_fn(allocator, 0); + if (!hash) { + aws_mem_release(allocator, checksum); + aws_raise_error(aws_last_error_or_unknown()); + return NULL; + } + checksum->impl.xxhash = hash; + checksum->allocator = allocator; + checksum->vtable = &s_xxhash_vtable; + checksum->good = true; + checksum->digest_size = digest_size; + return checksum; +} + static struct aws_s3_checksum *s_crc32_checksum_new(struct aws_allocator *allocator) { struct aws_s3_checksum *checksum = aws_mem_calloc(allocator, 1, sizeof(struct aws_s3_checksum)); checksum->vtable = &crc32_vtable; @@ -266,9 +367,22 @@ case AWS_SCA_SHA256: checksum = aws_hash_new(allocator, aws_sha256_new); break; + case AWS_SCA_SHA512: + checksum = aws_hash_new(allocator, aws_sha512_new); + break; + case AWS_SCA_XXHASH64: + checksum = s_aws_xxhash_new(allocator, aws_xxhash64_new, AWS_XXHASH64_LEN); + break; + case AWS_SCA_XXHASH3_64: + checksum = s_aws_xxhash_new(allocator, aws_xxhash3_64_new, AWS_XXHASH3_64_LEN); + break; + case AWS_SCA_XXHASH3_128: + checksum = s_aws_xxhash_new(allocator, aws_xxhash3_128_new, AWS_XXHASH3_128_LEN); + break; default: return NULL; } + if (checksum != NULL) { checksum->algorithm = algorithm; } @@ -320,6 +434,14 @@ return aws_sha1_compute(allocator, input, output, 0); case AWS_SCA_SHA256: return aws_sha256_compute(allocator, input, output, 0); + case AWS_SCA_SHA512: + return aws_sha512_compute(allocator, input, output, 0); + case AWS_SCA_XXHASH64: + return aws_xxhash64_compute(0, *input, output); + case AWS_SCA_XXHASH3_64: + return aws_xxhash3_64_compute(0, *input, output); + case AWS_SCA_XXHASH3_128: + return aws_xxhash3_128_compute(0, *input, output); case AWS_SCA_CRC64NVME: return s_checksum_compute_fn(allocator, input, output, s_crc64nvme_checksum_new); case AWS_SCA_CRC32: @@ -466,6 +588,18 @@ case AWS_SCA_SHA256: internal_config->response_checksum_algorithms.sha256 = true; break; + case AWS_SCA_SHA512: + internal_config->response_checksum_algorithms.sha512 = true; + break; + case AWS_SCA_XXHASH64: + internal_config->response_checksum_algorithms.xxhash64 = true; + break; + case AWS_SCA_XXHASH3_64: + internal_config->response_checksum_algorithms.xxhash3_64 = true; + break; + case AWS_SCA_XXHASH3_128: + internal_config->response_checksum_algorithms.xxhash3_128 = true; + break; default: break; } @@ -477,6 +611,10 @@ internal_config->response_checksum_algorithms.crc32c = true; internal_config->response_checksum_algorithms.sha1 = true; internal_config->response_checksum_algorithms.sha256 = true; + internal_config->response_checksum_algorithms.sha512 = true; + internal_config->response_checksum_algorithms.xxhash64 = true; + internal_config->response_checksum_algorithms.xxhash3_64 = true; + internal_config->response_checksum_algorithms.xxhash3_128 = true; } /* After applying settings from config, check the message header to override the corresponding settings. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/source/s3_default_buffer_pool.c new/aws-c-s3-0.12.2/source/s3_default_buffer_pool.c --- old/aws-c-s3-0.12.0/source/s3_default_buffer_pool.c 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/source/s3_default_buffer_pool.c 2026-04-02 20:58:10.000000000 +0200 @@ -434,26 +434,27 @@ if (ticket->reserved_from == AWS_S3_BUFFER_POOL_RESERVED_FROM_SPECIAL) { struct aws_hash_element *elem = NULL; aws_hash_table_find(&buffer_pool->special_blocks, (void *)ticket->size, &elem); - /* TODO: the lifetime between the ticket and the special block, let's assume the block will always be - * available first. */ - AWS_FATAL_ASSERT(elem != NULL); - special_list = elem->value; + if (elem) { + special_list = elem->value; - bool found = false; - for (size_t i = 0; i < aws_array_list_length(&special_list->blocks); ++i) { - struct s3_buffer_pool_block *block; - aws_array_list_get_at_ptr(&special_list->blocks, (void **)&block, i); - if (block->block_ptr == ticket->ptr) { - /* Make sure the block is marked as used. */ - AWS_FATAL_ASSERT(block->alloc_bit_mask == UINT16_MAX); - block->alloc_bit_mask = 0; - found = true; - break; + bool found = false; + for (size_t i = 0; i < aws_array_list_length(&special_list->blocks); ++i) { + struct s3_buffer_pool_block *block; + aws_array_list_get_at_ptr(&special_list->blocks, (void **)&block, i); + if (block->block_ptr == ticket->ptr) { + /* Make sure the block is marked as used. */ + if (block->alloc_bit_mask == UINT16_MAX) { + block->alloc_bit_mask = 0; + found = true; + break; + } + } + } + /* Make sure we do find where the ticket buffer from the list. */ + if (found) { + buffer_pool->special_blocks_used -= ticket->size; } } - /* Make sure we do find where the ticket buffer from the list. */ - AWS_FATAL_ASSERT(found); - buffer_pool->special_blocks_used -= ticket->size; } else if (ticket->reserved_from == AWS_S3_BUFFER_POOL_RESERVED_FROM_PRIMARY) { size_t chunks_used = ticket->size / buffer_pool->chunk_size; @@ -557,37 +558,31 @@ static bool s_should_trim_for_reserve_synced( bool from_special, size_t to_reserve, - struct aws_s3_default_buffer_pool *buffer_pool) { + struct aws_s3_default_buffer_pool *buffer_pool, + size_t overall_taken) { if (from_special || to_reserve <= buffer_pool->primary_size_cutoff) { /* Only trim when it will be allocated from secondary, which is directly from malloc. */ return false; } - /* The tracked usage SHOULD NOT overflow. */ - size_t total_allocated = - buffer_pool->primary_allocated + buffer_pool->secondary_used + buffer_pool->special_blocks_allocated; + size_t total_allocation_needs = 0; - if (aws_add_size_checked(total_allocated, to_reserve, &total_allocation_needs)) { - /* Will overflow, trim it. */ - return true; + if (aws_add_size_checked(overall_taken, to_reserve, &total_allocation_needs)) { + /* Will overflow, ignores it, which should not happen. */ + return false; } if (total_allocation_needs < buffer_pool->mem_limit) { /* No need to trim as we still have space to allocate the new block. */ return false; } - size_t primary_overallocation = 0; - int overflow = 0; - overflow |= - aws_sub_size_checked(buffer_pool->primary_allocated, buffer_pool->primary_used, &primary_overallocation); - overflow |= aws_sub_size_checked(primary_overallocation, buffer_pool->primary_reserved, &primary_overallocation); - size_t special_overallocation = 0; - overflow |= aws_sub_size_checked( - buffer_pool->special_blocks_allocated, buffer_pool->special_blocks_used, &special_overallocation); - overflow |= - aws_sub_size_checked(special_overallocation, buffer_pool->special_blocks_reserved, &special_overallocation); - /* The already allocated should be reasonable and not cause overflow. Otherwise, bugs in the code. */ - AWS_FATAL_ASSERT(!overflow); - /* Use max if overflow */ + size_t primary_overallocation = aws_sub_size_saturating(buffer_pool->primary_allocated, buffer_pool->primary_used); + /* Reserved can be more tha allocated */ + primary_overallocation = aws_sub_size_saturating(primary_overallocation, buffer_pool->primary_reserved); + size_t special_overallocation = + aws_sub_size_saturating(buffer_pool->special_blocks_allocated, buffer_pool->special_blocks_used); + /* Reserved can be more tha allocated */ + special_overallocation = aws_sub_size_saturating(special_overallocation, buffer_pool->special_blocks_reserved); + size_t total_overallocation = aws_add_size_saturating(special_overallocation, primary_overallocation); if (total_overallocation < to_reserve) { /* If the overallocation is less than the new block, trim it won't help, skip trimming. */ @@ -616,7 +611,7 @@ * the blocks, trim the blocks in hopes we can free up enough memory. * TODO: something smarter, like partial trim? */ - if (s_should_trim_for_reserve_synced(from_special, meta.size, buffer_pool)) { + if (s_should_trim_for_reserve_synced(from_special, meta.size, buffer_pool, overall_taken)) { s_buffer_pool_trim_synced(buffer_pool); overall_taken = buffer_pool->primary_used + buffer_pool->primary_reserved + buffer_pool->secondary_used + buffer_pool->secondary_reserved + buffer_pool->special_blocks_reserved + @@ -627,7 +622,7 @@ const size_t max_impact_of_forced_on_limit = (size_t)(buffer_pool->mem_limit * (s_max_impact_of_forced_buffers_on_memory_limit_as_percentage / 100.0)); if (buffer_pool->forced_used > max_impact_of_forced_on_limit) { - overall_taken -= buffer_pool->forced_used - max_impact_of_forced_on_limit; + overall_taken = (overall_taken - buffer_pool->forced_used) + max_impact_of_forced_on_limit; } if ((meta.size + overall_taken) <= buffer_pool->mem_limit) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/source/s3_meta_request.c new/aws-c-s3-0.12.2/source/s3_meta_request.c --- old/aws-c-s3-0.12.0/source/s3_meta_request.c 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/source/s3_meta_request.c 2026-04-02 20:58:10.000000000 +0200 @@ -2863,6 +2863,14 @@ return meta_request->checksum_config.response_checksum_algorithms.sha1; case AWS_SCA_SHA256: return meta_request->checksum_config.response_checksum_algorithms.sha256; + case AWS_SCA_SHA512: + return meta_request->checksum_config.response_checksum_algorithms.sha512; + case AWS_SCA_XXHASH64: + return meta_request->checksum_config.response_checksum_algorithms.xxhash64; + case AWS_SCA_XXHASH3_64: + return meta_request->checksum_config.response_checksum_algorithms.xxhash3_64; + case AWS_SCA_XXHASH3_128: + return meta_request->checksum_config.response_checksum_algorithms.xxhash3_128; default: return false; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/tests/CMakeLists.txt new/aws-c-s3-0.12.2/tests/CMakeLists.txt --- old/aws-c-s3-0.12.0/tests/CMakeLists.txt 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/tests/CMakeLists.txt 2026-04-02 20:58:10.000000000 +0200 @@ -285,6 +285,20 @@ add_net_test_case(sha256_test_oneshot) add_net_test_case(sha256_test_invalid_state) +add_net_test_case(sha512_nist_test_case_1) +add_net_test_case(sha512_nist_test_case_2) +add_net_test_case(sha512_nist_test_case_3) +add_net_test_case(sha512_nist_test_case_4) +add_net_test_case(sha512_nist_test_case_5) +add_net_test_case(sha512_nist_test_case_6) +add_net_test_case(sha512_test_invalid_buffer) +add_net_test_case(sha512_test_oneshot) +add_net_test_case(sha512_test_invalid_state) + +add_net_test_case(xxhash64_test_piping) +add_net_test_case(xxhash3_64_test_piping) +add_net_test_case(xxhash3_128_test_piping) + add_test_case(crc64nvme_nist_test_case_1) add_test_case(crc64nvme_nist_test_case_2) add_test_case(crc64nvme_nist_test_case_3) @@ -448,6 +462,7 @@ add_test_case(test_s3_buffer_pool_special_size_mixed) add_test_case(test_s3_buffer_pool_special_size_trim) add_test_case(test_s3_buffer_pool_reserve_tiny_chunks) +add_test_case(test_s3_buffer_pool_trim_reserved_but_unallocated) add_net_test_case(client_update_upload_part_timeout) add_net_test_case(client_meta_request_override_part_size) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/tests/s3_checksums_sha512_tests.c new/aws-c-s3-0.12.2/tests/s3_checksums_sha512_tests.c --- old/aws-c-s3-0.12.0/tests/s3_checksums_sha512_tests.c 1970-01-01 01:00:00.000000000 +0100 +++ new/aws-c-s3-0.12.2/tests/s3_checksums_sha512_tests.c 2026-04-02 20:58:10.000000000 +0200 @@ -0,0 +1,235 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include "aws/s3/private/s3_checksums.h" +#include <aws/cal/hash.h> +#include <aws/common/byte_buf.h> +#include <aws/testing/aws_test_harness.h> + +#include <s3_checksums_test_case_helper.h> +/* + * these are the NIST test vectors, as compiled here: + * https://www.di-mgt.com.au/sha_testvectors.html + */ + +static int s_sha512_nist_test_case_1_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abc"); + uint8_t expected[] = {0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, + 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, + 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, + 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, + 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + + return s_verify_checksum_test_case(allocator, &input, &expected_buf, aws_checksum_new, AWS_SCA_SHA512); +} + +AWS_TEST_CASE(sha512_nist_test_case_1, s_sha512_nist_test_case_1_fn) + +static int s_sha512_nist_test_case_2_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str(""); + uint8_t expected[] = { + 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e, + }; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + + return s_verify_checksum_test_case(allocator, &input, &expected_buf, aws_checksum_new, AWS_SCA_SHA512); +} + +AWS_TEST_CASE(sha512_nist_test_case_2, s_sha512_nist_test_case_2_fn) + +static int s_sha512_nist_test_case_3_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + struct aws_byte_cursor input = + aws_byte_cursor_from_c_str("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + uint8_t expected[] = { + 0x20, 0x4a, 0x8f, 0xc6, 0xdd, 0xa8, 0x2f, 0x0a, 0x0c, 0xed, 0x7b, 0xeb, 0x8e, 0x08, 0xa4, 0x16, + 0x57, 0xc1, 0x6e, 0xf4, 0x68, 0xb2, 0x28, 0xa8, 0x27, 0x9b, 0xe3, 0x31, 0xa7, 0x03, 0xc3, 0x35, + 0x96, 0xfd, 0x15, 0xc1, 0x3b, 0x1b, 0x07, 0xf9, 0xaa, 0x1d, 0x3b, 0xea, 0x57, 0x78, 0x9c, 0xa0, + 0x31, 0xad, 0x85, 0xc7, 0xa7, 0x1d, 0xd7, 0x03, 0x54, 0xec, 0x63, 0x12, 0x38, 0xca, 0x34, 0x45, + }; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + + return s_verify_checksum_test_case(allocator, &input, &expected_buf, aws_checksum_new, AWS_SCA_SHA512); +} + +AWS_TEST_CASE(sha512_nist_test_case_3, s_sha512_nist_test_case_3_fn) + +static int s_sha512_nist_test_case_4_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abcdefghbcdefghicdefghijdefghijkefghijklfghij" + "klmghijklmnhijklmnoijklmnopjklmnopqklm" + "nopqrlmnopqrsmnopqrstnopqrstu"); + uint8_t expected[] = { + 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09, + }; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + + return s_verify_checksum_test_case(allocator, &input, &expected_buf, aws_checksum_new, AWS_SCA_SHA512); +} + +AWS_TEST_CASE(sha512_nist_test_case_4, s_sha512_nist_test_case_4_fn) + +static int s_sha512_nist_test_case_5_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + aws_s3_library_init(allocator); + + struct aws_s3_checksum *checksum = aws_checksum_new(allocator, AWS_SCA_SHA512); + ASSERT_NOT_NULL(checksum); + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("a"); + + for (size_t i = 0; i < 1000000; ++i) { + ASSERT_SUCCESS(aws_checksum_update(checksum, &input)); + } + + uint8_t output[AWS_SHA512_LEN] = {0}; + struct aws_byte_buf output_buf = aws_byte_buf_from_empty_array(output, sizeof(output)); + ASSERT_SUCCESS(aws_checksum_finalize(checksum, &output_buf)); + + uint8_t expected[] = { + 0xe7, 0x18, 0x48, 0x3d, 0x0c, 0xe7, 0x69, 0x64, 0x4e, 0x2e, 0x42, 0xc7, 0xbc, 0x15, 0xb4, 0x63, + 0x8e, 0x1f, 0x98, 0xb1, 0x3b, 0x20, 0x44, 0x28, 0x56, 0x32, 0xa8, 0x03, 0xaf, 0xa9, 0x73, 0xeb, + 0xde, 0x0f, 0xf2, 0x44, 0x87, 0x7e, 0xa6, 0x0a, 0x4c, 0xb0, 0x43, 0x2c, 0xe5, 0x77, 0xc3, 0x1b, + 0xeb, 0x00, 0x9c, 0x5c, 0x2c, 0x49, 0xaa, 0x2e, 0x4e, 0xad, 0xb2, 0x17, 0xad, 0x8c, 0xc0, 0x9b, + }; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + ASSERT_BIN_ARRAYS_EQUALS(expected_buf.ptr, expected_buf.len, output_buf.buffer, output_buf.len); + + aws_checksum_destroy(checksum); + + aws_s3_library_clean_up(); + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(sha512_nist_test_case_5, s_sha512_nist_test_case_5_fn) + +static int s_sha512_nist_test_case_6_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + aws_s3_library_init(allocator); + + struct aws_s3_checksum *checksum = aws_checksum_new(allocator, AWS_SCA_SHA512); + ASSERT_NOT_NULL(checksum); + struct aws_byte_cursor input = + aws_byte_cursor_from_c_str("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"); + + for (size_t i = 0; i < 16777216; ++i) { + ASSERT_SUCCESS(aws_checksum_update(checksum, &input)); + } + + uint8_t output[AWS_SHA512_LEN] = {0}; + struct aws_byte_buf output_buf = aws_byte_buf_from_empty_array(output, sizeof(output)); + ASSERT_SUCCESS(aws_checksum_finalize(checksum, &output_buf)); + + uint8_t expected[] = { + 0xb4, 0x7c, 0x93, 0x34, 0x21, 0xea, 0x2d, 0xb1, 0x49, 0xad, 0x6e, 0x10, 0xfc, 0xe6, 0xc7, 0xf9, + 0x3d, 0x07, 0x52, 0x38, 0x01, 0x80, 0xff, 0xd7, 0xf4, 0x62, 0x9a, 0x71, 0x21, 0x34, 0x83, 0x1d, + 0x77, 0xbe, 0x60, 0x91, 0xb8, 0x19, 0xed, 0x35, 0x2c, 0x29, 0x67, 0xa2, 0xe2, 0xd4, 0xfa, 0x50, + 0x50, 0x72, 0x3c, 0x96, 0x30, 0x69, 0x1f, 0x1a, 0x05, 0xa7, 0x28, 0x1d, 0xbe, 0x6c, 0x10, 0x86, + }; + + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + ASSERT_BIN_ARRAYS_EQUALS(expected_buf.ptr, expected_buf.len, output_buf.buffer, output_buf.len); + + aws_checksum_destroy(checksum); + + aws_s3_library_clean_up(); + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(sha512_nist_test_case_6, s_sha512_nist_test_case_6_fn) + +static int s_sha512_test_invalid_buffer_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + aws_s3_library_init(allocator); + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abcdefghbcdefghicdefghijdefghijkefghijklfghij" + "klmghijklmnhijklmnoijklmnopjklmnopqklm" + "nopqrlmnopqrsmnopqrstnopqrstu"); + uint8_t output[AWS_SHA512_LEN] = {0}; + struct aws_byte_buf output_buf = aws_byte_buf_from_array(output, sizeof(output)); + output_buf.len = 1; + + ASSERT_ERROR(AWS_ERROR_SHORT_BUFFER, aws_checksum_compute(allocator, AWS_SCA_SHA512, &input, &output_buf)); + + aws_s3_library_clean_up(); + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(sha512_test_invalid_buffer, s_sha512_test_invalid_buffer_fn) + +static int s_sha512_test_oneshot_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + aws_s3_library_init(allocator); + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abcdefghbcdefghicdefghijdefghijkefghijklfghij" + "klmghijklmnhijklmnoijklmnopjklmnopqklm" + "nopqrlmnopqrsmnopqrstnopqrstu"); + uint8_t expected[] = { + 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09, + }; + + uint8_t output[AWS_SHA512_LEN] = {0}; + struct aws_byte_buf output_buf = aws_byte_buf_from_array(output, sizeof(output)); + output_buf.len = 0; + + ASSERT_SUCCESS(aws_checksum_compute(allocator, AWS_SCA_SHA512, &input, &output_buf)); + ASSERT_BIN_ARRAYS_EQUALS(expected, sizeof(expected), output_buf.buffer, output_buf.len); + + aws_s3_library_clean_up(); + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(sha512_test_oneshot, s_sha512_test_oneshot_fn) + +static int s_sha512_test_invalid_state_fn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + aws_s3_library_init(allocator); + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abcdefghbcdefghicdefghijdefghijkefghijklfghij" + "klmghijklmnhijklmnoijklmnopjklmnopqklm" + "nopqrlmnopqrsmnopqrstnopqrstu"); + + struct aws_s3_checksum *checksum = aws_checksum_new(allocator, AWS_SCA_SHA512); + ASSERT_NOT_NULL(checksum); + + uint8_t output[AWS_SHA512_LEN] = {0}; + struct aws_byte_buf output_buf = aws_byte_buf_from_empty_array(output, sizeof(output)); + + ASSERT_SUCCESS(aws_checksum_update(checksum, &input)); + ASSERT_SUCCESS(aws_checksum_finalize(checksum, &output_buf)); + ASSERT_ERROR(AWS_ERROR_INVALID_STATE, aws_checksum_update(checksum, &input)); + ASSERT_ERROR(AWS_ERROR_INVALID_STATE, aws_checksum_finalize(checksum, &output_buf)); + + aws_checksum_destroy(checksum); + + aws_s3_library_clean_up(); + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(sha512_test_invalid_state, s_sha512_test_invalid_state_fn) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/tests/s3_checksums_xxhash_tests.c new/aws-c-s3-0.12.2/tests/s3_checksums_xxhash_tests.c --- old/aws-c-s3-0.12.0/tests/s3_checksums_xxhash_tests.c 1970-01-01 01:00:00.000000000 +0100 +++ new/aws-c-s3-0.12.2/tests/s3_checksums_xxhash_tests.c 2026-04-02 20:58:10.000000000 +0200 @@ -0,0 +1,48 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include "aws/s3/private/s3_checksums.h" +#include <aws/cal/hash.h> +#include <aws/common/byte_buf.h> +#include <aws/testing/aws_test_harness.h> + +#include <s3_checksums_test_case_helper.h> +/* + * There is no standard test vectors for xxhash. + * Just test that piping is correct. + */ + +AWS_TEST_CASE(xxhash64_test_piping, s_xxhash64_test_piping) +static int s_xxhash64_test_piping(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abc"); + uint8_t expected[] = {0x44, 0xbc, 0x2c, 0xf5, 0xad, 0x77, 0x09, 0x99}; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + + return s_verify_checksum_test_case(allocator, &input, &expected_buf, aws_checksum_new, AWS_SCA_XXHASH64); +} + +AWS_TEST_CASE(xxhash3_64_test_piping, s_xxhash3_64_test_piping) +static int s_xxhash3_64_test_piping(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abc"); + uint8_t expected[] = {0x78, 0xaf, 0x5f, 0x94, 0x89, 0x2f, 0x39, 0x50}; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + + return s_verify_checksum_test_case(allocator, &input, &expected_buf, aws_checksum_new, AWS_SCA_XXHASH3_64); +} + +AWS_TEST_CASE(xxhash3_128_test_piping, s_xxhash3_128_test_piping) +static int s_xxhash3_128_test_piping(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + struct aws_byte_cursor input = aws_byte_cursor_from_c_str("abc"); + uint8_t expected[] = { + 0x06, 0xb0, 0x5a, 0xb6, 0x73, 0x3a, 0x61, 0x85, 0x78, 0xaf, 0x5f, 0x94, 0x89, 0x2f, 0x39, 0x50}; + struct aws_byte_cursor expected_buf = aws_byte_cursor_from_array(expected, sizeof(expected)); + + return s_verify_checksum_test_case(allocator, &input, &expected_buf, aws_checksum_new, AWS_SCA_XXHASH3_128); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/tests/s3_data_plane_tests.c new/aws-c-s3-0.12.2/tests/s3_data_plane_tests.c --- old/aws-c-s3-0.12.0/tests/s3_data_plane_tests.c 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/tests/s3_data_plane_tests.c 2026-04-02 20:58:10.000000000 +0200 @@ -4105,6 +4105,7 @@ for (size_t i = 0; i < AWS_ARRAY_SIZE(s_checksum_algo_priority_list); i++) { enum aws_s3_checksum_algorithm algorithm = s_checksum_algo_priority_list[i]; + char object_path_sprintf_buffer[128] = ""; snprintf( object_path_sprintf_buffer, @@ -4156,6 +4157,7 @@ }; ASSERT_SUCCESS(aws_s3_tester_send_meta_request_with_options(&tester, &get_options, NULL)); + aws_byte_buf_clean_up(&path_buf); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aws-c-s3-0.12.0/tests/s3_default_buffer_pool_tests.c new/aws-c-s3-0.12.2/tests/s3_default_buffer_pool_tests.c --- old/aws-c-s3-0.12.0/tests/s3_default_buffer_pool_tests.c 2026-03-23 18:14:51.000000000 +0100 +++ new/aws-c-s3-0.12.2/tests/s3_default_buffer_pool_tests.c 2026-04-02 20:58:10.000000000 +0200 @@ -679,3 +679,72 @@ return 0; } AWS_TEST_CASE(test_s3_buffer_pool_reserve_tiny_chunks, s_test_s3_buffer_pool_reserve_tiny_chunks) + +/* + * Regression test for s_should_trim_for_reserve_synced when buffers are reserved but not yet claimed. + * + * When tickets are reserved but never claimed, primary_allocated stays 0 while primary_reserved > 0. + * The overallocation calculation (primary_allocated - primary_used - primary_reserved) must not + * underflow -- it should saturate to 0. This also verifies that a subsequent secondary reserve + * still succeeds (i.e. the function correctly returns false / no crash). + */ +static int s_test_s3_buffer_pool_trim_reserved_but_unallocated(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + const size_t chunk_size = MB_TO_BYTES(8); + const size_t mem_limit = GB_TO_BYTES(1); + struct aws_s3_buffer_pool *buffer_pool = aws_s3_default_buffer_pool_new( + allocator, + (struct aws_s3_buffer_pool_config){ + .part_size = chunk_size, + .memory_limit = mem_limit, + }); + ASSERT_NOT_NULL(buffer_pool); + + /* Reserve primary-sized tickets WITHOUT claiming them. + * This leaves primary_reserved > 0 but primary_allocated == 0. */ + const size_t num_reserved = 50; + struct aws_future_s3_buffer_ticket *reserved_futures[50]; + struct aws_s3_buffer_ticket *reserved_tickets[50]; + for (size_t i = 0; i < num_reserved; ++i) { + reserved_futures[i] = aws_s3_default_buffer_pool_reserve( + buffer_pool, (struct aws_s3_buffer_pool_reserve_meta){.size = chunk_size}); + ASSERT_TRUE(aws_future_s3_buffer_ticket_is_done(reserved_futures[i])); + ASSERT_INT_EQUALS(aws_future_s3_buffer_ticket_get_error(reserved_futures[i]), AWS_OP_SUCCESS); + reserved_tickets[i] = aws_future_s3_buffer_ticket_get_result_by_move(reserved_futures[i]); + ASSERT_NOT_NULL(reserved_tickets[i]); + /* Intentionally do NOT call aws_s3_buffer_ticket_claim() -- ticket stays in reserve stage. */ + } + + /* Sanity check: reserved > 0, allocated == 0 */ + struct aws_s3_default_buffer_pool_usage_stats stats = aws_s3_default_buffer_pool_get_usage(buffer_pool); + ASSERT_TRUE(stats.primary_reserved > 0); + ASSERT_UINT_EQUALS(0, stats.primary_allocated); + + /* Now reserve a large secondary buffer. This triggers s_should_trim_for_reserve_synced. + * The overallocation calculation must saturate to 0 (not crash/underflow). + * The reserve must succeed since mem_limit is not exhausted. */ + struct aws_future_s3_buffer_ticket *secondary_future = aws_s3_default_buffer_pool_reserve( + buffer_pool, + (struct aws_s3_buffer_pool_reserve_meta){ + .size = MB_TO_BYTES(800), + }); + ASSERT_NOT_NULL(secondary_future); + /* Release all the reserved ones. */ + for (size_t i = 0; i < num_reserved; ++i) { + aws_s3_buffer_ticket_release(reserved_tickets[i]); + aws_future_s3_buffer_ticket_release(reserved_futures[i]); + } + ASSERT_TRUE(aws_future_s3_buffer_ticket_is_done(secondary_future)); + ASSERT_INT_EQUALS(aws_future_s3_buffer_ticket_get_error(secondary_future), AWS_OP_SUCCESS); + struct aws_s3_buffer_ticket *secondary_ticket = aws_future_s3_buffer_ticket_get_result_by_move(secondary_future); + ASSERT_NOT_NULL(secondary_ticket); + struct aws_byte_buf buf = aws_s3_buffer_ticket_claim(secondary_ticket); + ASSERT_NOT_NULL(buf.buffer); + + /* Cleanup */ + aws_s3_buffer_ticket_release(secondary_ticket); + aws_future_s3_buffer_ticket_release(secondary_future); + aws_s3_default_buffer_pool_destroy(buffer_pool); + return 0; +} +AWS_TEST_CASE(test_s3_buffer_pool_trim_reserved_but_unallocated, s_test_s3_buffer_pool_trim_reserved_but_unallocated)
