diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 402bbfab8949ef32de4ad206cb97f0594071aaf9..07125896274329cd95db96bdaf68e0c781e7a685 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -78,11 +78,15 @@ pub extern "C" fn abs(i: c_int) -> c_int { #[no_mangle] pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void { - if size % alignment != 0 { - return ptr::null_mut(); + if size % alignment == 0 { + /* The size-is-multiple-of-alignment requirement is the only + * difference between aligned_alloc() and memalign(). */ + memalign(alignment, size) + } + else { + platform::errno = errno::EINVAL; + ptr::null_mut() } - - memalign(alignment, size) } #[no_mangle] @@ -190,13 +194,19 @@ pub unsafe extern "C" fn calloc(nelem: size_t, elsize: size_t) -> *mut c_void { let size_result = nelem.checked_mul(elsize); match size_result { Some(size) => { + /* If allocation fails here, errno setting will be handled + * by malloc() */ let ptr = malloc(size); if !ptr.is_null() { intrinsics::write_bytes(ptr as *mut u8, 0, size); } ptr + }, + None => { + // For overflowing multiplication, we have to set errno here + platform::errno = errno::ENOMEM; + ptr::null_mut() } - None => core::ptr::null_mut(), } } @@ -403,12 +413,29 @@ pub extern "C" fn lrand48() -> c_long { #[no_mangle] pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void { - platform::alloc(size) + let ptr = platform::alloc(size); + if ptr.is_null() { + platform::errno = errno::ENOMEM; + } + ptr } #[no_mangle] pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_void { - platform::alloc_align(size, alignment) + /* Check if alignment is a (positive) power of two. The second + * expression will never underflow, due to Rust's lazy boolean + * operators. */ + if alignment > 0 && (alignment & (alignment - 1)) == 0 { + let ptr = platform::alloc_align(size, alignment); + if ptr.is_null() { + platform::errno = errno::ENOMEM; + } + ptr + } + else { + platform::errno = errno::EINVAL; + ptr::null_mut() + } } #[no_mangle] @@ -613,7 +640,11 @@ pub extern "C" fn random() -> c_long { #[no_mangle] pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void { - platform::realloc(ptr, size) + let ptr = platform::realloc(ptr, size); + if ptr.is_null() { + platform::errno = errno::ENOMEM; + } + ptr } #[no_mangle] diff --git a/tests/stdlib/alloc.c b/tests/stdlib/alloc.c index 2e8c710d60b1e17f04a138120b692c87420c4aa0..ccb496a1ddd4ee5593005f6aee81a7cd57918bb8 100644 --- a/tests/stdlib/alloc.c +++ b/tests/stdlib/alloc.c @@ -1,34 +1,129 @@ #include <malloc.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <stddef.h> /* for size_t */ #include <stdint.h> /* for SIZE_MAX */ #include "test_helpers.h" int main(void) { - char * ptr = (char *)malloc(256); - printf("malloc %p\n", ptr); + size_t sample_alloc_size = 256; + size_t sample_realloc_size = sample_alloc_size + 1; + + /* ensure values are mapped to variables */ + size_t max_size = SIZE_MAX; + size_t aligned_alloc_alignment = 128; + size_t aligned_alloc_goodsize = 256; + size_t aligned_alloc_badsize = 257; + int i; - for(i = 0; i < 256; i++) { - ptr[i] = (char)i; + + errno = 0; + char * ptr_malloc = (char *)malloc(sample_alloc_size); + int malloc_errno = errno; + printf("malloc : %p, errno: %d = %s\n", + ptr_malloc, malloc_errno, strerror(malloc_errno)); + for(i = 0; i < sample_alloc_size; i++) { + ptr_malloc[i] = (char)i; } - free(ptr); - - char * ptrc = (char *)calloc(256, 1); - printf("calloc %p\n", ptrc); - for(i = 0; i < 256; i++) { - ptrc[i] = (char)i; + free(ptr_malloc); + + errno = 0; + char * ptr_malloc_maxsize = (char *)malloc(max_size); + int malloc_maxsize_errno = errno; + printf("malloc (SIZE_MAX) : %p, errno: %d = %s\n", + ptr_malloc_maxsize, malloc_maxsize_errno, + strerror(malloc_maxsize_errno)); + free(ptr_malloc_maxsize); + + errno = 0; + char * ptr_calloc = (char *)calloc(sample_alloc_size, 1); + int calloc_errno = errno; + printf("calloc : %p, errno: %d = %s\n", ptr_calloc, + calloc_errno, strerror(calloc_errno)); + for(i = 0; i < sample_alloc_size; i++) { + ptr_calloc[i] = (char)i; } - free(ptrc); - - char * ptrco = (char *)calloc(SIZE_MAX, SIZE_MAX); - printf("calloc (overflowing) %p\n", ptrco); - free(ptrco); /* clean up correctly even if overflow is not handled */ - - char * ptra = (char *)memalign(256, 256); - printf("memalign %p\n", ptra); - for(i = 0; i < 256; i++) { - ptra[i] = (char)i; + free(ptr_calloc); + + errno = 0; + char * ptr_calloc_overflow = (char *)calloc(max_size, max_size); + int calloc_overflow_errno = errno; + printf("calloc (overflowing) : %p, errno: %d = %s\n", + ptr_calloc_overflow, calloc_overflow_errno, + strerror(calloc_overflow_errno)); + free(ptr_calloc_overflow); /* clean up correctly even if overflow is not handled */ + + char * ptr_realloc = (char *)malloc(sample_alloc_size); + errno = 0; + ptr_realloc = (char *)realloc(ptr_realloc, sample_realloc_size); + int realloc_errno = errno; + printf("realloc : %p, errno: %d = %s\n", + ptr_realloc, realloc_errno, strerror(realloc_errno)); + for(i = 0; i < sample_realloc_size; i++) { + ptr_realloc[i] = (char)i; + } + free(ptr_realloc); + + char * ptr_realloc_maxsize = (char *)malloc(sample_alloc_size); + errno = 0; + ptr_realloc_maxsize = (char *)realloc(ptr_realloc_maxsize, max_size); + int realloc_maxsize_errno = errno; + printf("realloc (SIZE_MAX) : %p, errno: %d = %s\n", + ptr_realloc_maxsize, realloc_maxsize_errno, + strerror(realloc_maxsize_errno)); + free(ptr_realloc_maxsize); + + errno = 0; + char * ptr_memalign = (char *)memalign(256, sample_alloc_size); + int memalign_errno = errno; + printf("memalign : %p, errno: %d = %s\n", ptr_memalign, + memalign_errno, strerror(memalign_errno)); + for(i = 0; i < sample_alloc_size; i++) { + ptr_memalign[i] = (char)i; } - free(ptra); + free(ptr_memalign); + + errno = 0; + char * ptr_memalign_maxsize = (char *)memalign(256, max_size); + int memalign_maxsize_errno = errno; + printf("memalign (SIZE_MAX) : %p, errno: %d = %s\n", + ptr_memalign_maxsize, memalign_maxsize_errno, + strerror(memalign_maxsize_errno)); + free(ptr_memalign_maxsize); + + errno = 0; + char * ptr_memalign_align0 = (char *)memalign(0, sample_alloc_size); + int memalign_align0_errno = errno; + printf("memalign (alignment 0): %p, errno: %d = %s\n", + ptr_memalign_align0, memalign_align0_errno, + strerror(memalign_align0_errno)); + free(ptr_memalign_align0); + + errno = 0; + char * ptr_memalign_align3 = (char *)memalign(3, sample_alloc_size); + int memalign_align3_errno = errno; + printf("memalign (alignment 3): %p, errno: %d = %s\n", + ptr_memalign_align3, memalign_align3_errno, + strerror(memalign_align3_errno)); + free(ptr_memalign_align3); + + errno = 0; + char * ptr_aligned_alloc_goodsize = (char *)aligned_alloc(aligned_alloc_alignment, aligned_alloc_goodsize); + int aligned_alloc_goodsize_errno = errno; + printf("aligned_alloc (size %% alignment == 0):\n"); + printf(" %p, errno: %d = %s\n", + ptr_aligned_alloc_goodsize, aligned_alloc_goodsize_errno, + strerror(aligned_alloc_goodsize_errno)); + free(ptr_aligned_alloc_goodsize); + + errno = 0; + char * ptr_aligned_alloc_badsize = (char *)aligned_alloc(aligned_alloc_alignment, aligned_alloc_badsize); + int aligned_alloc_badsize_errno = errno; + printf("aligned_alloc (size %% alignment != 0):\n"); + printf(" %p, errno: %d = %s\n", + ptr_aligned_alloc_badsize, aligned_alloc_badsize_errno, + strerror(aligned_alloc_badsize_errno)); + free(ptr_aligned_alloc_badsize); }