diff --git a/include/mimalloc/prim.h b/include/mimalloc/prim.h index 40f5d2d7..9e560696 100644 --- a/include/mimalloc/prim.h +++ b/include/mimalloc/prim.h @@ -47,7 +47,8 @@ int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_la // Commit memory. Returns error code or 0 on success. // For example, on Linux this would make the memory PROT_READ|PROT_WRITE. -int _mi_prim_commit(void* addr, size_t size); +// `is_zero` is set to true if the memory was zero initialized (e.g. on Windows) +int _mi_prim_commit(void* addr, size_t size, bool* is_zero); // Decommit memory. Returns error code or 0 on success. The `needs_recommit` result is true // if the memory would need to be re-committed. For example, on Windows this is always true, diff --git a/src/os.c b/src/os.c index f243f7a4..1b435335 100644 --- a/src/os.c +++ b/src/os.c @@ -405,12 +405,17 @@ bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats if (csize == 0) return true; // commit - int err = _mi_prim_commit(start, csize); + bool os_is_zero = false; + int err = _mi_prim_commit(start, csize, &os_is_zero); if (err != 0) { _mi_warning_message("cannot commit OS memory (error: %d (0x%x), address: %p, size: 0x%zx bytes)\n", err, err, start, csize); + return false; } - mi_assert_internal(err == 0); - return (err == 0); + if (os_is_zero && is_zero != NULL) { + *is_zero = true; + mi_assert_expensive(mi_mem_is_zero(start, csize)); + } + return true; } static bool mi_os_decommit_ex(void* addr, size_t size, bool* needs_recommit, mi_stats_t* tld_stats) { diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 4349f578..9a542d3e 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -346,8 +346,9 @@ static void unix_mprotect_hint(int err) { -int _mi_prim_commit(void* start, size_t size) { +int _mi_prim_commit(void* start, size_t size, bool* is_zero) { // commit: ensure we can access the area + *is_zero = false; int err = mprotect(start, size, (PROT_READ | PROT_WRITE)); if (err != 0) { err = errno; } unix_mprotect_hint(err); diff --git a/src/prim/wasi/prim.c b/src/prim/wasi/prim.c index bf78a258..50511f0b 100644 --- a/src/prim/wasi/prim.c +++ b/src/prim/wasi/prim.c @@ -128,8 +128,9 @@ int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_la // Commit/Reset/Protect //--------------------------------------------- -int _mi_prim_commit(void* addr, size_t size) { +int _mi_prim_commit(void* addr, size_t size, bool* is_zero) { MI_UNUSED(addr); MI_UNUSED(size); + *is_zero = false; return 0; } diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 61532737..bde48a7d 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -259,14 +259,26 @@ int _mi_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_la #pragma warning(disable:6250) // suppress warning calling VirtualFree without MEM_RELEASE (for decommit) #endif -int _mi_prim_commit(void* addr, size_t size) { +int _mi_prim_commit(void* addr, size_t size, bool* is_zero) { + *is_zero = false; + /* + // zero'ing only happens on an initial commit... but checking upfront seems expensive.. + _MEMORY_BASIC_INFORMATION meminfo; _mi_memzero_var(meminfo); + if (VirtualQuery(addr, &meminfo, size) > 0) { + if ((meminfo.State & MEM_COMMIT) == 0) { + *is_zero = true; + } + } + */ + // commit void* p = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE); - return (p != NULL ? 0 : (int)GetLastError()); + if (p == NULL) return (int)GetLastError(); + return 0; } int _mi_prim_decommit(void* addr, size_t size, bool* needs_recommit) { BOOL ok = VirtualFree(addr, size, MEM_DECOMMIT); - *needs_recommit = true; // for safetly, assume always decommitted even in the case of an error. + *needs_recommit = true; // for safety, assume always decommitted even in the case of an error. return (ok ? 0 : (int)GetLastError()); }