| /* | |
| * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. | |
| * | |
| * Licensed under the Apache License 2.0 (the "License"). You may not use | |
| * this file except in compliance with the License. You can obtain a copy | |
| * in the file LICENSE in the source distribution or at | |
| * https://www.openssl.org/source/license.html | |
| */ | |
| #include "internal/e_os.h" | |
| #include "internal/cryptlib.h" | |
| #include "internal/mem_alloc_utils.h" | |
| #include "crypto/cryptlib.h" | |
| #include <stdlib.h> | |
| void *ossl_malloc_align(size_t num, size_t alignment, void **freeptr, | |
| const char *file, int line) | |
| { | |
| size_t alloc_bytes; | |
| void *ret; | |
| *freeptr = NULL; | |
| /* Ensure that alignment is a power of two no larger than 65536 */ | |
| if (alignment == 0 || (alignment & (alignment - 1)) != 0 | |
| || alignment > 65536) { | |
| ossl_report_alloc_err_inv(file, line); | |
| return NULL; | |
| } | |
| /* | |
| * Note: Windows supports an _aligned_malloc call, but we choose | |
| * not to use it here, because allocations from that function | |
| * require that they be freed via _aligned_free. Given that | |
| * we can't differentiate plain malloc blocks from blocks obtained | |
| * via _aligned_malloc, just avoid its use entirely | |
| */ | |
| if (ossl_unlikely(!ossl_size_add(num, alignment, &alloc_bytes, file, line))) | |
| return NULL; | |
| /* | |
| * Step 1: Allocate an amount of memory that is <alignment> | |
| * bytes bigger than requested | |
| */ | |
| *freeptr = CRYPTO_malloc(alloc_bytes, file, line); | |
| if (*freeptr == NULL) | |
| return NULL; | |
| /* | |
| * Step 2: Add <alignment - 1> bytes to the pointer | |
| * This will cross the alignment boundary that is | |
| * requested | |
| */ | |
| ret = (void *)((char *)*freeptr + (alignment - 1)); | |
| /* | |
| * Step 3: Use the alignment as a mask to translate the | |
| * least significant bits of the allocation at the alignment | |
| * boundary to 0. ret now holds a pointer to the memory | |
| * buffer at the requested alignment | |
| * NOTE: It is a documented requirement that alignment be a | |
| * power of 2, which is what allows this to work | |
| */ | |
| ret = (void *)((uintptr_t)ret & (uintptr_t)(~(alignment - 1))); | |
| return ret; | |
| } |