diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index b293ee1a51dc..6e9ebc087356 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -87,6 +87,9 @@ typedef int pid_t; #include #ifdef __SANITIZE_ADDRESS__ # include +#else +# define ASAN_POISON_MEMORY_REGION(addr, size) ((void) 0) +# define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void) 0) #endif #ifndef _WIN32 @@ -890,9 +893,6 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) if (zend_mm_use_huge_pages) { zend_mm_hugepage(ptr, size); } -#ifdef __SANITIZE_ADDRESS__ - ASAN_UNPOISON_MEMORY_REGION(ptr, size); -#endif return ptr; } else { size_t offset; @@ -932,9 +932,6 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) if (zend_mm_use_huge_pages) { zend_mm_hugepage(ptr, size); } -# ifdef __SANITIZE_ADDRESS__ - ASAN_UNPOISON_MEMORY_REGION(ptr, size); -# endif #endif return ptr; } @@ -942,24 +939,33 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) static void *zend_mm_chunk_alloc(zend_mm_heap *heap, size_t size, size_t alignment) { + void *ptr; + #if ZEND_MM_STORAGE if (UNEXPECTED(heap->storage)) { - void *ptr = heap->storage->handlers.chunk_alloc(heap->storage, size, alignment); + ptr = heap->storage->handlers.chunk_alloc(heap->storage, size, alignment); ZEND_ASSERT(((uintptr_t)((char*)ptr + (alignment-1)) & (alignment-1)) == (uintptr_t)ptr); - return ptr; - } + } else #endif - return zend_mm_chunk_alloc_int(size, alignment); + { + ptr = zend_mm_chunk_alloc_int(size, alignment); + } + if (ptr != NULL) { + ASAN_UNPOISON_MEMORY_REGION(ptr, size); + } + return ptr; } static void zend_mm_chunk_free(zend_mm_heap *heap, void *addr, size_t size) { #if ZEND_MM_STORAGE if (UNEXPECTED(heap->storage)) { + ASAN_UNPOISON_MEMORY_REGION(addr, size); heap->storage->handlers.chunk_free(heap->storage, addr, size); return; } #endif + ASAN_POISON_MEMORY_REGION(addr, size); zend_mm_munmap(addr, size); } @@ -975,6 +981,7 @@ static int zend_mm_chunk_truncate(zend_mm_heap *heap, void *addr, size_t old_siz } #endif #ifndef _WIN32 + ASAN_POISON_MEMORY_REGION((char*)addr + new_size, old_size - new_size); zend_mm_munmap((char*)addr + new_size, old_size - new_size); return 1; #else @@ -1300,6 +1307,7 @@ static void *zend_mm_alloc_pages(zend_mm_heap *heap, uint32_t pages_count ZEND_F if (page_num == chunk->free_tail) { chunk->free_tail = page_num + pages_count; } + ASAN_UNPOISON_MEMORY_REGION(ZEND_MM_PAGE_ADDR(chunk, page_num), pages_count * ZEND_MM_PAGE_SIZE); return ZEND_MM_PAGE_ADDR(chunk, page_num); } @@ -1370,6 +1378,7 @@ static zend_always_inline void zend_mm_delete_chunk(zend_mm_heap *heap, zend_mm_ static zend_always_inline void zend_mm_free_pages_ex(zend_mm_heap *heap, zend_mm_chunk *chunk, uint32_t page_num, uint32_t pages_count, int free_chunk) { + ASAN_POISON_MEMORY_REGION(ZEND_MM_PAGE_ADDR(chunk, page_num), pages_count * ZEND_MM_PAGE_SIZE); chunk->free_pages += pages_count; zend_mm_bitset_reset_range(chunk->free_map, page_num, pages_count); chunk->map[page_num] = 0; @@ -1461,6 +1470,20 @@ static zend_always_inline uint32_t zend_mm_small_size_to_bin(size_t size) #define ZEND_MM_SMALL_SIZE_TO_BIN(size) zend_mm_small_size_to_bin(size) +#ifdef __SANITIZE_ADDRESS__ +static zend_always_inline void zend_mm_asan_poison_free_slot(void *ptr, uint32_t bin_num) +{ + size_t size = bin_data_size[bin_num]; +#if ZEND_DEBUG + /* Leak detection inspects the debug trailer of free slots. */ + size -= ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)); +#endif + ASAN_POISON_MEMORY_REGION(ptr, size); +} +#else +# define zend_mm_asan_poison_free_slot(ptr, bin_num) ((void) 0) +#endif + #if ZEND_MM_HEAP_PROTECTION /* We keep track of free slots by organizing them in a linked list, with the * first word of every free slot being a pointer to the next one. @@ -1507,14 +1530,18 @@ static zend_always_inline void zend_mm_set_next_free_slot(zend_mm_heap *heap, ui { ZEND_ASSERT(bin_data_size[bin_num] >= ZEND_MM_MIN_USEABLE_BIN_SIZE); + /* Free-list links live in poisoned storage, so expose them only while in use. */ + ASAN_UNPOISON_MEMORY_REGION(slot, bin_data_size[bin_num]); slot->next_free_slot = next; zend_mm_free_slot **shadow_addr = ZEND_MM_FREE_SLOT_PTR_SHADOW_ADDR(slot, bin_num); *shadow_addr = zend_mm_encode_free_slot(heap, shadow_addr, next); + zend_mm_asan_poison_free_slot(slot, bin_num); } static zend_always_inline zend_mm_free_slot *zend_mm_get_next_free_slot(zend_mm_heap *heap, uint32_t bin_num, zend_mm_free_slot* slot) { + ASAN_UNPOISON_MEMORY_REGION(slot, bin_data_size[bin_num]); zend_mm_free_slot *next = slot->next_free_slot; if (EXPECTED(next != NULL)) { zend_mm_free_slot **shadow_addr = ZEND_MM_FREE_SLOT_PTR_SHADOW_ADDR(slot, bin_num); @@ -1522,14 +1549,24 @@ static zend_always_inline zend_mm_free_slot *zend_mm_get_next_free_slot(zend_mm_ zend_mm_panic("zend_mm_heap corrupted"); } } + zend_mm_asan_poison_free_slot(slot, bin_num); return (zend_mm_free_slot*)next; } #else /* ZEND_MM_HEAP_PROTECTION */ # define zend_mm_set_next_free_slot(heap, bin_num, slot, next) do { \ - (slot)->next_free_slot = (next); \ + ASAN_UNPOISON_MEMORY_REGION(slot, bin_data_size[bin_num]); \ + (slot)->next_free_slot = (next); \ + zend_mm_asan_poison_free_slot(slot, bin_num); \ } while (0) -# define zend_mm_get_next_free_slot(heap, bin_num, slot) (slot)->next_free_slot + +static zend_always_inline zend_mm_free_slot *zend_mm_get_next_free_slot(zend_mm_heap *heap, uint32_t bin_num, zend_mm_free_slot *slot) +{ + ASAN_UNPOISON_MEMORY_REGION(slot, bin_data_size[bin_num]); + zend_mm_free_slot *next = slot->next_free_slot; + zend_mm_asan_poison_free_slot(slot, bin_num); + return next; +} #endif /* ZEND_MM_HEAP_PROTECTION */ static zend_never_inline void *zend_mm_alloc_small_slow(zend_mm_heap *heap, uint32_t bin_num ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) @@ -1588,6 +1625,7 @@ static zend_never_inline void *zend_mm_alloc_small_slow(zend_mm_heap *heap, uint dbg->size = 0; } while (0); #endif + zend_mm_asan_poison_free_slot(p, bin_num); /* return first element */ return bin; @@ -1609,6 +1647,7 @@ static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, uint32_t if (EXPECTED(heap->free_slot[bin_num] != NULL)) { zend_mm_free_slot *p = heap->free_slot[bin_num]; heap->free_slot[bin_num] = zend_mm_get_next_free_slot(heap, bin_num, p); + ASAN_UNPOISON_MEMORY_REGION(p, bin_data_size[bin_num]); return p; } else { return zend_mm_alloc_small_slow(heap, bin_num ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); @@ -1861,6 +1900,7 @@ static zend_never_inline void *zend_mm_realloc_huge(zend_mm_heap *heap, void *pt /* try to map tail right after this block */ if (zend_mm_chunk_extend(heap, ptr, old_size, new_size)) { + ASAN_UNPOISON_MEMORY_REGION((char*)ptr + old_size, new_size - old_size); #if ZEND_MM_STAT || ZEND_MM_LIMIT heap->real_size += new_size - old_size; #endif @@ -1997,6 +2037,7 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p int new_pages_count = (int)(new_size / ZEND_MM_PAGE_SIZE); int rest_pages_count = (int)((old_size - new_size) / ZEND_MM_PAGE_SIZE); + ASAN_POISON_MEMORY_REGION((char*)ptr + new_size, old_size - new_size); #if ZEND_MM_STAT heap->size -= rest_pages_count * ZEND_MM_PAGE_SIZE; #endif @@ -2019,6 +2060,7 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p /* try to allocate tail pages after this block */ if (page_num + new_pages_count <= ZEND_MM_PAGES && zend_mm_bitset_is_free_range(chunk->free_map, page_num + old_pages_count, new_pages_count - old_pages_count)) { + ASAN_UNPOISON_MEMORY_REGION((char*)ptr + old_size, new_size - old_size); #if ZEND_MM_STAT do { size_t size = heap->size + (new_size - old_size); @@ -2266,6 +2308,7 @@ ZEND_API void zend_mm_refresh_key_child(zend_mm_heap *heap) continue; } zend_mm_free_slot *next; + ASAN_UNPOISON_MEMORY_REGION(slot, bin_data_size[i]); while ((next = slot->next_free_slot)) { zend_mm_free_slot **shadow_addr = ZEND_MM_FREE_SLOT_PTR_SHADOW_ADDR(slot, i); if (UNEXPECTED(next != zend_mm_decode_free_slot_key(old_key, shadow_addr, *shadow_addr))) { @@ -2273,7 +2316,9 @@ ZEND_API void zend_mm_refresh_key_child(zend_mm_heap *heap) } zend_mm_set_next_free_slot(heap, i, slot, next); slot = next; + ASAN_UNPOISON_MEMORY_REGION(slot, bin_data_size[i]); } + zend_mm_asan_poison_free_slot(slot, i); } zend_mm_rekey_cached_chunks(heap, old_key); @@ -2775,6 +2820,8 @@ ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) p = heap->cached_chunks; while (p != NULL) { zend_mm_chunk *q = zend_mm_get_next_cached_chunk(heap, p); + ASAN_POISON_MEMORY_REGION(ZEND_MM_PAGE_ADDR(p, ZEND_MM_FIRST_PAGE), + ZEND_MM_CHUNK_SIZE - ZEND_MM_FIRST_PAGE * ZEND_MM_PAGE_SIZE); memset(p, 0, sizeof(zend_mm_chunk)); zend_mm_set_next_cached_chunk(heap, p, q); p = q; @@ -2782,6 +2829,8 @@ ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) /* reinitialize the first chunk and heap */ p = heap->main_chunk; + ASAN_POISON_MEMORY_REGION(ZEND_MM_PAGE_ADDR(p, ZEND_MM_FIRST_PAGE), + ZEND_MM_CHUNK_SIZE - ZEND_MM_FIRST_PAGE * ZEND_MM_PAGE_SIZE); p->heap = &p->heap_slot; p->next = p; p->prev = p; diff --git a/docs/source/miscellaneous/running-tests.rst b/docs/source/miscellaneous/running-tests.rst index bb2c56dcecd2..8ffbc8d6dda8 100644 --- a/docs/source/miscellaneous/running-tests.rst +++ b/docs/source/miscellaneous/running-tests.rst @@ -83,6 +83,28 @@ The test runner can run tests in parallel, by using the ``-j`` option: php run-tests.php -j24 ext/date/*.phpt +Testing the Native Allocator with AddressSanitizer +================================================== + +Build with ``--enable-address-sanitizer`` to enable AddressSanitizer (ASan). The test runner's +``--asan`` option selects the system allocator with allocation tracking. To test native ZendMM +allocation behavior instead, omit ``--asan``, set ``USE_ZEND_ALLOC=1``, and retain the +sanitizer-specific test exclusions: + +.. code:: shell + + USE_ZEND_ALLOC=1 SKIP_ASAN=1 SKIP_PERF_SENSITIVE=1 \ + sapi/cli/php run-tests.php Zend/tests + +Native ZendMM poisons freed small allocations and page runs, and unpoisons them when reused. It also +poisons storage released during request shutdown. These annotations detect accesses to freed storage +until it is reused; they do not provide a quarantine or exact requested-size bounds checking. +Allocation size-class padding remains accessible, as do the debug trailers inspected by leak +detection in debug builds. + +The ``zend_mm_asan.phpt`` test in ``ext/zend_test/tests`` checks allocator shadow state directly and +requires both ASan and ``--enable-zend-test``. + ************** Test results ************** diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 4867f2f41c69..3c2d09ccd494 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -46,6 +46,10 @@ #include +#ifdef __SANITIZE_ADDRESS__ +# include +#endif + #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) # include # include @@ -269,6 +273,124 @@ static ZEND_FUNCTION(zend_test_callback) free(p); } +#ifdef __SANITIZE_ADDRESS__ +static ZEND_FUNCTION(zend_test_asan_zend_mm) +{ + zend_long old_size, new_size; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_LONG(old_size) + Z_PARAM_LONG(new_size) + ZEND_PARSE_PARAMETERS_END(); + + if (old_size < 1) { + zend_argument_value_error(1, "must be greater than 0"); + RETURN_THROWS(); + } + if (new_size < 1) { + zend_argument_value_error(2, "must be greater than 0"); + RETURN_THROWS(); + } + + zend_mm_heap *heap = zend_mm_startup(); + char *ptr = zend_mm_alloc(heap, old_size); + bool allocated = __asan_region_is_poisoned(ptr, old_size) == NULL; + memset(ptr, 0x42, old_size); + + size_t old_capacity = zend_mm_block_size(heap, ptr); + /* Unmapped huge allocations need not retain ASan shadow state. */ + bool old_huge = old_capacity > ZEND_MM_MAX_LARGE_SIZE; + char *old_ptr = ptr; + ptr = zend_mm_realloc(heap, ptr, new_size); + size_t new_capacity = zend_mm_block_size(heap, ptr); + bool new_huge = new_capacity > ZEND_MM_MAX_LARGE_SIZE; + bool reallocated = __asan_region_is_poisoned(ptr, new_size) == NULL; + bool moved = ptr == old_ptr || old_huge || __asan_address_is_poisoned(old_ptr); + bool truncated = ptr != old_ptr || old_huge || new_capacity >= old_capacity + || __asan_address_is_poisoned(ptr + old_capacity - 1); + bool preserved = true; + for (size_t i = 0; i < (size_t) MIN(old_size, new_size); i++) { + preserved &= ptr[i] == 0x42; + } + zend_mm_free(heap, ptr); + bool released = new_huge || (__asan_address_is_poisoned(ptr) + && __asan_address_is_poisoned(ptr + new_size - 1)); + zend_mm_refresh_key_child(heap); + bool rekeyed = new_huge || __asan_address_is_poisoned(ptr); + ptr = zend_mm_alloc(heap, new_size); + bool reused = __asan_region_is_poisoned(ptr, new_size) == NULL; + zend_mm_free(heap, ptr); + zend_mm_gc(heap); + bool collected = new_huge || __asan_address_is_poisoned(ptr); + + ptr = zend_mm_realloc2(heap, NULL, old_size, 0); + memset(ptr, 0x24, old_size); + ptr = zend_mm_realloc2(heap, ptr, new_size, MIN(old_size, new_size)); + bool copied = __asan_region_is_poisoned(ptr, new_size) == NULL; + for (size_t i = 0; i < (size_t) MIN(old_size, new_size); i++) { + copied &= ptr[i] == 0x24; + } + zend_mm_free(heap, ptr); + + ptr = zend_mm_alloc(heap, old_size); + reused &= __asan_region_is_poisoned(ptr, old_size) == NULL; + zend_mm_shutdown(heap, false, true); + bool reset = old_huge || (__asan_address_is_poisoned(ptr) + && __asan_address_is_poisoned(ptr + old_size - 1)); + ptr = zend_mm_alloc(heap, old_size); + bool restarted = __asan_region_is_poisoned(ptr, old_size) == NULL; + zend_mm_free(heap, ptr); + + zend_mm_heap *orig_heap = zend_mm_set_heap(heap); + ptr = emalloc(1); + bool specialized = __asan_region_is_poisoned(ptr, 1) == NULL; + efree_size(ptr, 1); + specialized &= __asan_address_is_poisoned(ptr); + ptr = emalloc(64); + specialized &= __asan_region_is_poisoned(ptr, 64) == NULL; + efree_size(ptr, 64); + specialized &= __asan_address_is_poisoned(ptr); + ptr = emalloc(8192); + specialized &= __asan_region_is_poisoned(ptr, 8192) == NULL; + efree_size(ptr, 8192); + specialized &= __asan_address_is_poisoned(ptr); + zend_mm_set_heap(orig_heap); + + char *blocks[4]; + for (size_t i = 0; i < 4; i++) { + blocks[i] = zend_mm_alloc(heap, 1024 * 1024); + memset(blocks[i], 0x42, 1024 * 1024); + } + zend_mm_shutdown(heap, false, true); + bool cached = true; + for (size_t i = 0; i < 4; i++) { + blocks[i] = zend_mm_alloc(heap, 1024 * 1024); + cached &= __asan_region_is_poisoned(blocks[i], 1024 * 1024) == NULL; + memset(blocks[i], 0x24, 1024 * 1024); + } + for (size_t i = 0; i < 4; i++) { + zend_mm_free(heap, blocks[i]); + } + zend_mm_shutdown(heap, true, true); + + array_init(return_value); + add_assoc_bool(return_value, "allocated", allocated); + add_assoc_bool(return_value, "reallocated", reallocated); + add_assoc_bool(return_value, "moved", moved); + add_assoc_bool(return_value, "truncated", truncated); + add_assoc_bool(return_value, "preserved", preserved); + add_assoc_bool(return_value, "released", released); + add_assoc_bool(return_value, "rekeyed", rekeyed); + add_assoc_bool(return_value, "collected", collected); + add_assoc_bool(return_value, "reused", reused); + add_assoc_bool(return_value, "copied", copied); + add_assoc_bool(return_value, "reset", reset); + add_assoc_bool(return_value, "restarted", restarted); + add_assoc_bool(return_value, "specialized", specialized); + add_assoc_bool(return_value, "cached", cached); +} +#endif + /* Leak a refcounted variable */ static ZEND_FUNCTION(zend_leak_variable) { diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index db5ca629ade2..ce3b30b823aa 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -301,6 +301,10 @@ function zend_delref(mixed $variable): void {} function zend_test_erealloc_block_size(int $old_size, int $new_size): array {} +#ifdef __SANITIZE_ADDRESS__ + function zend_test_asan_zend_mm(int $old_size, int $new_size): array {} +#endif + function zend_bool(bool $param): bool {} function zend_bool_or_null(bool|null $param): bool|null {} function zend_bool_slow_zpp(bool $param): bool {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 87622c185cff..763d9a06d151 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: ea2674e5d5dbf60aa5efab31132064b52a07bddd + * Stub hash: 3e659c4bdb92db8fa5066daacdb9d9f1d1e59e7e * Has decl header: yes */ #include "zend_attributes.h" @@ -64,6 +64,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_erealloc_block_size, 0 ZEND_ARG_TYPE_INFO(0, new_size, IS_LONG, 0) ZEND_END_ARG_INFO() +#if defined(__SANITIZE_ADDRESS__) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_asan_zend_mm, 0, 2, IS_ARRAY, 0) + ZEND_ARG_TYPE_INFO(0, old_size, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, new_size, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_bool, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, param, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -463,6 +470,9 @@ static ZEND_FUNCTION(zend_leak_variable); static ZEND_FUNCTION(zend_leak_bytes); static ZEND_FUNCTION(zend_delref); static ZEND_FUNCTION(zend_test_erealloc_block_size); +#if defined(__SANITIZE_ADDRESS__) +static ZEND_FUNCTION(zend_test_asan_zend_mm); +#endif static ZEND_FUNCTION(zend_bool); static ZEND_FUNCTION(zend_bool_or_null); static ZEND_FUNCTION(zend_bool_slow_zpp); @@ -645,6 +655,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_leak_bytes, arginfo_zend_leak_bytes) ZEND_FE(zend_delref, arginfo_zend_delref) ZEND_FE(zend_test_erealloc_block_size, arginfo_zend_test_erealloc_block_size) +#if defined(__SANITIZE_ADDRESS__) + ZEND_FE(zend_test_asan_zend_mm, arginfo_zend_test_asan_zend_mm) +#endif ZEND_FE(zend_bool, arginfo_zend_bool) ZEND_FE(zend_bool_or_null, arginfo_zend_bool_or_null) ZEND_FE(zend_bool_slow_zpp, arginfo_zend_bool_slow_zpp) diff --git a/ext/zend_test/test_decl.h b/ext/zend_test/test_decl.h index db7652512c83..1c98df57ed2d 100644 --- a/ext/zend_test/test_decl.h +++ b/ext/zend_test/test_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: ea2674e5d5dbf60aa5efab31132064b52a07bddd */ + * Stub hash: 3e659c4bdb92db8fa5066daacdb9d9f1d1e59e7e */ -#ifndef ZEND_TEST_DECL_ea2674e5d5dbf60aa5efab31132064b52a07bddd_H -#define ZEND_TEST_DECL_ea2674e5d5dbf60aa5efab31132064b52a07bddd_H +#ifndef ZEND_TEST_DECL_3e659c4bdb92db8fa5066daacdb9d9f1d1e59e7e_H +#define ZEND_TEST_DECL_3e659c4bdb92db8fa5066daacdb9d9f1d1e59e7e_H typedef enum zend_enum_ZendTestUnitEnum { ZEND_ENUM_ZendTestUnitEnum_Foo = 1, @@ -27,4 +27,4 @@ typedef enum zend_enum_ZendTestEnumWithInterface { ZEND_ENUM_ZendTestEnumWithInterface_Bar = 2, } zend_enum_ZendTestEnumWithInterface; -#endif /* ZEND_TEST_DECL_ea2674e5d5dbf60aa5efab31132064b52a07bddd_H */ +#endif /* ZEND_TEST_DECL_3e659c4bdb92db8fa5066daacdb9d9f1d1e59e7e_H */ diff --git a/ext/zend_test/test_legacy_arginfo.h b/ext/zend_test/test_legacy_arginfo.h index a673b373142a..ec73482e3210 100644 --- a/ext/zend_test/test_legacy_arginfo.h +++ b/ext/zend_test/test_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: ea2674e5d5dbf60aa5efab31132064b52a07bddd + * Stub hash: 3e659c4bdb92db8fa5066daacdb9d9f1d1e59e7e * Has decl header: yes */ #include "zend_constants.h" @@ -59,6 +59,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_erealloc_block_size, 0, 0, 2) ZEND_ARG_INFO(0, new_size) ZEND_END_ARG_INFO() +#if defined(__SANITIZE_ADDRESS__) +ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_asan_zend_mm, 0, 0, 2) + ZEND_ARG_INFO(0, old_size) + ZEND_ARG_INFO(0, new_size) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_bool, 0, 0, 1) ZEND_ARG_INFO(0, param) ZEND_END_ARG_INFO() @@ -387,6 +394,9 @@ static ZEND_FUNCTION(zend_leak_variable); static ZEND_FUNCTION(zend_leak_bytes); static ZEND_FUNCTION(zend_delref); static ZEND_FUNCTION(zend_test_erealloc_block_size); +#if defined(__SANITIZE_ADDRESS__) +static ZEND_FUNCTION(zend_test_asan_zend_mm); +#endif static ZEND_FUNCTION(zend_bool); static ZEND_FUNCTION(zend_bool_or_null); static ZEND_FUNCTION(zend_bool_slow_zpp); @@ -541,6 +551,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_leak_bytes, arginfo_zend_leak_bytes) ZEND_FE(zend_delref, arginfo_zend_delref) ZEND_FE(zend_test_erealloc_block_size, arginfo_zend_test_erealloc_block_size) +#if defined(__SANITIZE_ADDRESS__) + ZEND_FE(zend_test_asan_zend_mm, arginfo_zend_test_asan_zend_mm) +#endif ZEND_FE(zend_bool, arginfo_zend_bool) ZEND_FE(zend_bool_or_null, arginfo_zend_bool_or_null) ZEND_FE(zend_bool_slow_zpp, arginfo_zend_bool_slow_zpp) diff --git a/ext/zend_test/tests/zend_mm_asan.phpt b/ext/zend_test/tests/zend_mm_asan.phpt new file mode 100644 index 000000000000..d65df42e82c9 --- /dev/null +++ b/ext/zend_test/tests/zend_mm_asan.phpt @@ -0,0 +1,26 @@ +--TEST-- +Native ZendMM ASan allocation lifetime annotations +--EXTENSIONS-- +zend_test +--SKIPIF-- + +--FILE-- + $passed) { + if (!$passed) { + echo "$oldSize -> $newSize: $check failed\n"; + } + } + } +} +echo "Done\n"; +?> +--EXPECT-- +Done