diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/restricted/aws/aws-c-common/source/allocator.c | |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/restricted/aws/aws-c-common/source/allocator.c')
| -rw-r--r-- | contrib/restricted/aws/aws-c-common/source/allocator.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/contrib/restricted/aws/aws-c-common/source/allocator.c b/contrib/restricted/aws/aws-c-common/source/allocator.c new file mode 100644 index 00000000000..6ffb5315094 --- /dev/null +++ b/contrib/restricted/aws/aws-c-common/source/allocator.c @@ -0,0 +1,312 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include <aws/common/assert.h> +#include <aws/common/common.h> +#include <aws/common/logging.h> +#include <aws/common/math.h> + +#include <stdarg.h> +#include <stdlib.h> + +#ifdef _WIN32 +# include <Windows.h> +#endif + +#ifdef __MACH__ +# include <CoreFoundation/CoreFoundation.h> +#endif + +/* turn off unused named parameter warning on msvc.*/ +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4100) +#endif + +bool aws_allocator_is_valid(const struct aws_allocator *alloc) { + /* An allocator must define mem_acquire and mem_release. All other fields are optional */ + return alloc && AWS_OBJECT_PTR_IS_READABLE(alloc) && alloc->mem_acquire && alloc->mem_release; +} + +static void *s_default_malloc(struct aws_allocator *allocator, size_t size) { + (void)allocator; + return malloc(size); +} + +static void s_default_free(struct aws_allocator *allocator, void *ptr) { + (void)allocator; + free(ptr); +} + +static void *s_default_realloc(struct aws_allocator *allocator, void *ptr, size_t oldsize, size_t newsize) { + (void)allocator; + (void)oldsize; + return realloc(ptr, newsize); +} + +static void *s_default_calloc(struct aws_allocator *allocator, size_t num, size_t size) { + (void)allocator; + return calloc(num, size); +} + +static struct aws_allocator default_allocator = { + .mem_acquire = s_default_malloc, + .mem_release = s_default_free, + .mem_realloc = s_default_realloc, + .mem_calloc = s_default_calloc, +}; + +struct aws_allocator *aws_default_allocator(void) { + return &default_allocator; +} + +void *aws_mem_acquire(struct aws_allocator *allocator, size_t size) { + AWS_FATAL_PRECONDITION(allocator != NULL); + AWS_FATAL_PRECONDITION(allocator->mem_acquire != NULL); + /* Protect against https://wiki.sei.cmu.edu/confluence/display/c/MEM04-C.+Beware+of+zero-length+allocations */ + AWS_FATAL_PRECONDITION(size != 0); + + void *mem = allocator->mem_acquire(allocator, size); + if (!mem) { + aws_raise_error(AWS_ERROR_OOM); + } + return mem; +} + +void *aws_mem_calloc(struct aws_allocator *allocator, size_t num, size_t size) { + AWS_FATAL_PRECONDITION(allocator != NULL); + AWS_FATAL_PRECONDITION(allocator->mem_calloc || allocator->mem_acquire); + /* Protect against https://wiki.sei.cmu.edu/confluence/display/c/MEM04-C.+Beware+of+zero-length+allocations */ + AWS_FATAL_PRECONDITION(num != 0 && size != 0); + + /* Defensive check: never use calloc with size * num that would overflow + * https://wiki.sei.cmu.edu/confluence/display/c/MEM07-C.+Ensure+that+the+arguments+to+calloc%28%29%2C+when+multiplied%2C+do+not+wrap + */ + size_t required_bytes; + if (aws_mul_size_checked(num, size, &required_bytes)) { + return NULL; + } + + /* If there is a defined calloc, use it */ + if (allocator->mem_calloc) { + void *mem = allocator->mem_calloc(allocator, num, size); + if (!mem) { + aws_raise_error(AWS_ERROR_OOM); + } + return mem; + } + + /* Otherwise, emulate calloc */ + void *mem = allocator->mem_acquire(allocator, required_bytes); + if (!mem) { + aws_raise_error(AWS_ERROR_OOM); + return NULL; + } + memset(mem, 0, required_bytes); + AWS_POSTCONDITION(mem != NULL); + return mem; +} + +#define AWS_ALIGN_ROUND_UP(value, alignment) (((value) + ((alignment)-1)) & ~((alignment)-1)) + +void *aws_mem_acquire_many(struct aws_allocator *allocator, size_t count, ...) { + + enum { S_ALIGNMENT = sizeof(intmax_t) }; + + va_list args_size; + va_start(args_size, count); + va_list args_allocs; + va_copy(args_allocs, args_size); + + size_t total_size = 0; + for (size_t i = 0; i < count; ++i) { + + /* Ignore the pointer argument for now */ + va_arg(args_size, void **); + + size_t alloc_size = va_arg(args_size, size_t); + total_size += AWS_ALIGN_ROUND_UP(alloc_size, S_ALIGNMENT); + } + va_end(args_size); + + void *allocation = NULL; + + if (total_size > 0) { + + allocation = aws_mem_acquire(allocator, total_size); + if (!allocation) { + aws_raise_error(AWS_ERROR_OOM); + goto cleanup; + } + + uint8_t *current_ptr = allocation; + + for (size_t i = 0; i < count; ++i) { + + void **out_ptr = va_arg(args_allocs, void **); + + size_t alloc_size = va_arg(args_allocs, size_t); + alloc_size = AWS_ALIGN_ROUND_UP(alloc_size, S_ALIGNMENT); + + *out_ptr = current_ptr; + current_ptr += alloc_size; + } + } + +cleanup: + va_end(args_allocs); + return allocation; +} + +#undef AWS_ALIGN_ROUND_UP + +void aws_mem_release(struct aws_allocator *allocator, void *ptr) { + AWS_FATAL_PRECONDITION(allocator != NULL); + AWS_FATAL_PRECONDITION(allocator->mem_release != NULL); + + if (ptr != NULL) { + allocator->mem_release(allocator, ptr); + } +} + +int aws_mem_realloc(struct aws_allocator *allocator, void **ptr, size_t oldsize, size_t newsize) { + AWS_FATAL_PRECONDITION(allocator != NULL); + AWS_FATAL_PRECONDITION(allocator->mem_realloc || allocator->mem_acquire); + AWS_FATAL_PRECONDITION(allocator->mem_release); + + /* Protect against https://wiki.sei.cmu.edu/confluence/display/c/MEM04-C.+Beware+of+zero-length+allocations */ + if (newsize == 0) { + aws_mem_release(allocator, *ptr); + *ptr = NULL; + return AWS_OP_SUCCESS; + } + + if (allocator->mem_realloc) { + void *newptr = allocator->mem_realloc(allocator, *ptr, oldsize, newsize); + if (!newptr) { + return aws_raise_error(AWS_ERROR_OOM); + } + *ptr = newptr; + return AWS_OP_SUCCESS; + } + + /* Since the allocator doesn't support realloc, we'll need to emulate it (inefficiently). */ + if (oldsize >= newsize) { + return AWS_OP_SUCCESS; + } + + void *newptr = allocator->mem_acquire(allocator, newsize); + if (!newptr) { + return aws_raise_error(AWS_ERROR_OOM); + } + + memcpy(newptr, *ptr, oldsize); + memset((uint8_t *)newptr + oldsize, 0, newsize - oldsize); + + aws_mem_release(allocator, *ptr); + + *ptr = newptr; + + return AWS_OP_SUCCESS; +} + +/* Wraps a CFAllocator around aws_allocator. For Mac only. */ +#ifdef __MACH__ + +static CFStringRef s_cf_allocator_description = CFSTR("CFAllocator wrapping aws_allocator."); + +/* note we don't have a standard specification stating sizeof(size_t) == sizeof(void *) so we have some extra casts */ +static void *s_cf_allocator_allocate(CFIndex alloc_size, CFOptionFlags hint, void *info) { + (void)hint; + + struct aws_allocator *allocator = info; + + void *mem = aws_mem_acquire(allocator, (size_t)alloc_size + sizeof(size_t)); + + if (!mem) { + return NULL; + } + + size_t allocation_size = (size_t)alloc_size + sizeof(size_t); + memcpy(mem, &allocation_size, sizeof(size_t)); + return (void *)((uint8_t *)mem + sizeof(size_t)); +} + +static void s_cf_allocator_deallocate(void *ptr, void *info) { + struct aws_allocator *allocator = info; + + void *original_allocation = (uint8_t *)ptr - sizeof(size_t); + + aws_mem_release(allocator, original_allocation); +} + +static void *s_cf_allocator_reallocate(void *ptr, CFIndex new_size, CFOptionFlags hint, void *info) { + (void)hint; + + struct aws_allocator *allocator = info; + AWS_ASSERT(allocator->mem_realloc); + + void *original_allocation = (uint8_t *)ptr - sizeof(size_t); + size_t original_size = 0; + memcpy(&original_size, original_allocation, sizeof(size_t)); + + if (aws_mem_realloc(allocator, &original_allocation, original_size, (size_t)new_size)) { + return NULL; + } + + size_t new_allocation_size = (size_t)new_size; + memcpy(original_allocation, &new_allocation_size, sizeof(size_t)); + + return (void *)((uint8_t *)original_allocation + sizeof(size_t)); +} + +static CFStringRef s_cf_allocator_copy_description(const void *info) { + (void)info; + + return s_cf_allocator_description; +} + +static CFIndex s_cf_allocator_preferred_size(CFIndex size, CFOptionFlags hint, void *info) { + (void)hint; + (void)info; + + return size + sizeof(size_t); +} + +CFAllocatorRef aws_wrapped_cf_allocator_new(struct aws_allocator *allocator) { + CFAllocatorRef cf_allocator = NULL; + + CFAllocatorReallocateCallBack reallocate_callback = NULL; + + if (allocator->mem_realloc) { + reallocate_callback = s_cf_allocator_reallocate; + } + + CFAllocatorContext context = { + .allocate = s_cf_allocator_allocate, + .copyDescription = s_cf_allocator_copy_description, + .deallocate = s_cf_allocator_deallocate, + .reallocate = reallocate_callback, + .info = allocator, + .preferredSize = s_cf_allocator_preferred_size, + .release = NULL, + .retain = NULL, + .version = 0, + }; + + cf_allocator = CFAllocatorCreate(NULL, &context); + + if (!cf_allocator) { + aws_raise_error(AWS_ERROR_OOM); + } + + return cf_allocator; +} + +void aws_wrapped_cf_allocator_destroy(CFAllocatorRef allocator) { + CFRelease(allocator); +} + +#endif /*__MACH__ */ |
