src: use __builtin_align_down, if available

In _test_malloc, we manually align a pointer to MALLOC_ALIGNMENT
using `& ~(MALLOC_ALIGNMENT - 1)`. However, this has two problems:

1. We're casting the pointer to `size_t`, which isn't guaranteed
   to hold a pointer. Instead, we should cast to `uintptr_t`.
2. Modifying a pointer as a integer is undefined behavior, and on
   some platforms (e.g. CHERI), this does not work.

C++11 has std::align that does this for us, but unfortunately, there
isn't a way to do this in ISO C that is guaranteed to work, except for
in Clang v10+, which has a builtin extension called
__builtin_align_down that can align pointers safely for us.

See:
https://clang.llvm.org/docs/LanguageExtensions.html#alignment-builtins
on-behalf-of: @nqminds <info@nqminds.com>

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Alois Klink 2022-12-12 18:30:46 +00:00 committed by Andreas Schneider
parent 426784f405
commit 0559ef6e8e
2 changed files with 15 additions and 4 deletions

View File

@ -1,5 +1,6 @@
include(CheckIncludeFile)
include(CheckSymbolExists)
include(CheckCSourceCompiles)
include(CheckFunctionExists)
include(CheckLibraryExists)
include(CheckTypeSize)
@ -89,6 +90,8 @@ check_function_exists(signal HAVE_SIGNAL)
check_function_exists(strsignal HAVE_STRSIGNAL)
check_function_exists(strcmp HAVE_STRCMP)
check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
# Supported by Clang v10+
check_c_source_compiles("int main(void) { int a = 1; return __builtin_align_down(&a, 8);}" HAVE_BUILTIN_ALIGN_DOWN)
if (WIN32)
check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S)

View File

@ -2327,9 +2327,16 @@ static void vcm_free_error(char *err_msg)
libc_free(err_msg);
}
/* Rounds the given pointer down to a multiple of the given alignment. */
#ifdef HAVE_BUILTIN_ALIGN_DOWN
#define ALIGN_DOWN(x, a) (__builtin_align_down((x), (a)))
#else
#define ALIGN_DOWN(x, a) ((uintptr_t)(x) & ~((a)-1))
#endif
/* Use the real malloc in this function. */
#undef malloc
void* _test_malloc(const size_t size, const char* file, const int line) {
void* _test_malloc(const size_t size, const char *file, const int line) {
char *ptr = NULL;
MallocBlockInfo block_info;
ListNode * const block_list = get_allocated_blocks_list();
@ -2344,9 +2351,10 @@ void* _test_malloc(const size_t size, const char* file, const int line) {
assert_non_null(block);
/* Calculate the returned address. */
ptr = (char*)(((size_t)block + MALLOC_GUARD_SIZE +
sizeof(struct MallocBlockInfoData) +
MALLOC_ALIGNMENT) & ~(MALLOC_ALIGNMENT - 1));
ptr = (char *)(ALIGN_DOWN((block + MALLOC_GUARD_SIZE +
sizeof(struct MallocBlockInfoData) +
MALLOC_ALIGNMENT),
MALLOC_ALIGNMENT));
/* Initialize the guard blocks. */
memset(ptr - MALLOC_GUARD_SIZE, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE);