From e74159486b78735171f22718ce48ae94359d1d98 Mon Sep 17 00:00:00 2001 From: Daan Date: Tue, 25 Apr 2023 10:21:34 -0700 Subject: [PATCH 1/7] remove deprecated from description (issue #737) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 295becb2..019664b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ option(MI_DEBUG_TSAN "Build with thread sanitizer (needs clang)" OFF) option(MI_DEBUG_UBSAN "Build with undefined-behavior sanitizer (needs clang++)" OFF) option(MI_SKIP_COLLECT_ON_EXIT "Skip collecting memory on program exit" OFF) option(MI_NO_PADDING "Force no use of padding even in DEBUG mode etc." OFF) -option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version (deprecated)" OFF) +option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) # deprecated options option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) From d7a72c4912943e8aaf135e465ca5ea229ea96646 Mon Sep 17 00:00:00 2001 From: daanx Date: Fri, 19 May 2023 09:12:46 -0700 Subject: [PATCH 2/7] fix thread data leak; issue #748 --- src/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/init.c b/src/init.c index c9aa4b0f..fe885a5b 100644 --- a/src/init.c +++ b/src/init.c @@ -175,9 +175,9 @@ mi_heap_t* _mi_heap_main_get(void) { // note: in x64 in release build `sizeof(mi_thread_data_t)` is under 4KiB (= OS page size). typedef struct mi_thread_data_s { - mi_heap_t heap; // must come first due to cast in `_mi_heap_done` + mi_heap_t heap; // must come first due to cast in `_mi_heap_done` mi_tld_t tld; - mi_memid_t memid; + mi_memid_t memid; // must come last due to zero'ing } mi_thread_data_t; @@ -223,7 +223,7 @@ static mi_thread_data_t* mi_thread_data_zalloc(void) { } if (td != NULL && !is_zero) { - _mi_memzero_aligned(td, sizeof(*td)); + _mi_memzero_aligned(td, offsetof(mi_thread_data_t,memid)); } return td; } From 4a85f32f8ec9cd04be357378c65bcc50e8c31636 Mon Sep 17 00:00:00 2001 From: daanx Date: Fri, 19 May 2023 10:24:39 -0700 Subject: [PATCH 3/7] add libc.c source file --- CMakeLists.txt | 1 + ide/vs2017/mimalloc-override.vcxproj | 1 + ide/vs2017/mimalloc-override.vcxproj.filters | 3 + ide/vs2017/mimalloc.vcxproj | 1 + ide/vs2017/mimalloc.vcxproj.filters | 3 + ide/vs2019/mimalloc-override.vcxproj | 1 + ide/vs2019/mimalloc-override.vcxproj.filters | 3 + ide/vs2019/mimalloc.vcxproj | 1 + ide/vs2019/mimalloc.vcxproj.filters | 3 + ide/vs2022/mimalloc-override.vcxproj | 1 + ide/vs2022/mimalloc-override.vcxproj.filters | 3 + ide/vs2022/mimalloc.vcxproj | 1 + ide/vs2022/mimalloc.vcxproj.filters | 3 + include/mimalloc/internal.h | 4 +- src/arena.c | 2 +- src/options.c | 66 +------------------- src/static.c | 1 + 17 files changed, 31 insertions(+), 67 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 019664b4..1387e0db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ set(mi_sources src/bitmap.c src/heap.c src/init.c + src/libc.c src/options.c src/os.c src/page.c diff --git a/ide/vs2017/mimalloc-override.vcxproj b/ide/vs2017/mimalloc-override.vcxproj index 3d5c1f75..6d20eb57 100644 --- a/ide/vs2017/mimalloc-override.vcxproj +++ b/ide/vs2017/mimalloc-override.vcxproj @@ -238,6 +238,7 @@ + diff --git a/ide/vs2017/mimalloc-override.vcxproj.filters b/ide/vs2017/mimalloc-override.vcxproj.filters index 70f84d59..1adafcfa 100644 --- a/ide/vs2017/mimalloc-override.vcxproj.filters +++ b/ide/vs2017/mimalloc-override.vcxproj.filters @@ -91,5 +91,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/ide/vs2017/mimalloc.vcxproj b/ide/vs2017/mimalloc.vcxproj index 46eb05d8..ece9a14d 100644 --- a/ide/vs2017/mimalloc.vcxproj +++ b/ide/vs2017/mimalloc.vcxproj @@ -227,6 +227,7 @@ + diff --git a/ide/vs2017/mimalloc.vcxproj.filters b/ide/vs2017/mimalloc.vcxproj.filters index 0c2bd522..8359e0e4 100644 --- a/ide/vs2017/mimalloc.vcxproj.filters +++ b/ide/vs2017/mimalloc.vcxproj.filters @@ -62,6 +62,9 @@ Source Files + + Source Files + diff --git a/ide/vs2019/mimalloc-override.vcxproj b/ide/vs2019/mimalloc-override.vcxproj index 1c5c61b7..a84a5178 100644 --- a/ide/vs2019/mimalloc-override.vcxproj +++ b/ide/vs2019/mimalloc-override.vcxproj @@ -238,6 +238,7 @@ + diff --git a/ide/vs2019/mimalloc-override.vcxproj.filters b/ide/vs2019/mimalloc-override.vcxproj.filters index 370c8ab3..046e5603 100644 --- a/ide/vs2019/mimalloc-override.vcxproj.filters +++ b/ide/vs2019/mimalloc-override.vcxproj.filters @@ -52,6 +52,9 @@ Source Files + + Source Files + diff --git a/ide/vs2019/mimalloc.vcxproj b/ide/vs2019/mimalloc.vcxproj index 0e2eb312..0076b1db 100644 --- a/ide/vs2019/mimalloc.vcxproj +++ b/ide/vs2019/mimalloc.vcxproj @@ -219,6 +219,7 @@ + true diff --git a/ide/vs2019/mimalloc.vcxproj.filters b/ide/vs2019/mimalloc.vcxproj.filters index 21f9c517..98f29289 100644 --- a/ide/vs2019/mimalloc.vcxproj.filters +++ b/ide/vs2019/mimalloc.vcxproj.filters @@ -55,6 +55,9 @@ Source Files + + Source Files + diff --git a/ide/vs2022/mimalloc-override.vcxproj b/ide/vs2022/mimalloc-override.vcxproj index e2c7f71d..df2a0816 100644 --- a/ide/vs2022/mimalloc-override.vcxproj +++ b/ide/vs2022/mimalloc-override.vcxproj @@ -240,6 +240,7 @@ + true diff --git a/ide/vs2022/mimalloc-override.vcxproj.filters b/ide/vs2022/mimalloc-override.vcxproj.filters index 0f105c1a..dd69c827 100644 --- a/ide/vs2022/mimalloc-override.vcxproj.filters +++ b/ide/vs2022/mimalloc-override.vcxproj.filters @@ -55,6 +55,9 @@ Sources + + Sources + diff --git a/ide/vs2022/mimalloc.vcxproj b/ide/vs2022/mimalloc.vcxproj index a02a8393..11da11c3 100644 --- a/ide/vs2022/mimalloc.vcxproj +++ b/ide/vs2022/mimalloc.vcxproj @@ -219,6 +219,7 @@ + true diff --git a/ide/vs2022/mimalloc.vcxproj.filters b/ide/vs2022/mimalloc.vcxproj.filters index b3cdb3b3..bb5c8ce9 100644 --- a/ide/vs2022/mimalloc.vcxproj.filters +++ b/ide/vs2022/mimalloc.vcxproj.filters @@ -55,6 +55,9 @@ Sources + + Sources + diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 4dabe8ba..03b6dbaa 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -189,14 +189,14 @@ bool _mi_free_delayed_block(mi_block_t* block); void _mi_free_generic(const mi_segment_t* segment, mi_page_t* page, bool is_local, void* p) mi_attr_noexcept; // for runtime integration void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size); -// option.c, c primitives +// libc.c, c primitives char _mi_toupper(char c); int _mi_strnicmp(const char* s, const char* t, size_t n); void _mi_strlcpy(char* dest, const char* src, size_t dest_size); void _mi_strlcat(char* dest, const char* src, size_t dest_size); size_t _mi_strlen(const char* s); size_t _mi_strnlen(const char* s, size_t max_len); - +bool _mi_getenv(const char* name, char* result, size_t result_size); #if MI_DEBUG>1 bool _mi_page_is_valid(mi_page_t* page); diff --git a/src/arena.c b/src/arena.c index be1a9ebe..7ddbea7f 100644 --- a/src/arena.c +++ b/src/arena.c @@ -812,7 +812,7 @@ int mi_reserve_os_memory_ex(size_t size, bool commit, bool allow_large, bool exc const bool is_large = memid.is_pinned; // todo: use separate is_large field? if (!mi_manage_os_memory_ex2(start, size, is_large, -1 /* numa node */, exclusive, memid, arena_id)) { _mi_os_free_ex(start, size, commit, memid, &_mi_stats_main); - _mi_verbose_message("failed to reserve %zu k memory\n", _mi_divide_up(size, 1024)); + _mi_verbose_message("failed to reserve %zu KiB memory\n", _mi_divide_up(size, 1024)); return ENOMEM; } _mi_verbose_message("reserved %zu KiB memory%s\n", _mi_divide_up(size, 1024), is_large ? " (in large os pages)" : ""); diff --git a/src/options.c b/src/options.c index f52af8b8..8605cbb8 100644 --- a/src/options.c +++ b/src/options.c @@ -435,68 +435,6 @@ void _mi_error_message(int err, const char* fmt, ...) { // -------------------------------------------------------- // Initialize options by checking the environment // -------------------------------------------------------- -char _mi_toupper(char c) { - if (c >= 'a' && c <= 'z') return (c - 'a' + 'A'); - else return c; -} - -int _mi_strnicmp(const char* s, const char* t, size_t n) { - if (n == 0) return 0; - for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) { - if (_mi_toupper(*s) != _mi_toupper(*t)) break; - } - return (n == 0 ? 0 : *s - *t); -} - -void _mi_strlcpy(char* dest, const char* src, size_t dest_size) { - if (dest==NULL || src==NULL || dest_size == 0) return; - // copy until end of src, or when dest is (almost) full - while (*src != 0 && dest_size > 1) { - *dest++ = *src++; - dest_size--; - } - // always zero terminate - *dest = 0; -} - -void _mi_strlcat(char* dest, const char* src, size_t dest_size) { - if (dest==NULL || src==NULL || dest_size == 0) return; - // find end of string in the dest buffer - while (*dest != 0 && dest_size > 1) { - dest++; - dest_size--; - } - // and catenate - _mi_strlcpy(dest, src, dest_size); -} - -size_t _mi_strlen(const char* s) { - if (s==NULL) return 0; - size_t len = 0; - while(s[len] != 0) { len++; } - return len; -} - -size_t _mi_strnlen(const char* s, size_t max_len) { - if (s==NULL) return 0; - size_t len = 0; - while(s[len] != 0 && len < max_len) { len++; } - return len; -} - -#ifdef MI_NO_GETENV -static bool mi_getenv(const char* name, char* result, size_t result_size) { - MI_UNUSED(name); - MI_UNUSED(result); - MI_UNUSED(result_size); - return false; -} -#else -static bool mi_getenv(const char* name, char* result, size_t result_size) { - if (name==NULL || result == NULL || result_size < 64) return false; - return _mi_prim_getenv(name,result,result_size); -} -#endif // TODO: implement ourselves to reduce dependencies on the C runtime #include // strtol @@ -509,11 +447,11 @@ static void mi_option_init(mi_option_desc_t* desc) { char buf[64+1]; _mi_strlcpy(buf, "mimalloc_", sizeof(buf)); _mi_strlcat(buf, desc->name, sizeof(buf)); - bool found = mi_getenv(buf, s, sizeof(s)); + bool found = _mi_getenv(buf, s, sizeof(s)); if (!found && desc->legacy_name != NULL) { _mi_strlcpy(buf, "mimalloc_", sizeof(buf)); _mi_strlcat(buf, desc->legacy_name, sizeof(buf)); - found = mi_getenv(buf, s, sizeof(s)); + found = _mi_getenv(buf, s, sizeof(s)); if (found) { _mi_warning_message("environment option \"mimalloc_%s\" is deprecated -- use \"mimalloc_%s\" instead.\n", desc->legacy_name, desc->name); } diff --git a/src/static.c b/src/static.c index bc05dd72..bf025eb7 100644 --- a/src/static.c +++ b/src/static.c @@ -27,6 +27,7 @@ terms of the MIT license. A copy of the license can be found in the file #include "bitmap.c" #include "heap.c" #include "init.c" +#include "libc.c" #include "options.c" #include "os.c" #include "page.c" // includes page-queue.c From e10467f6735934b5127aaf0630d9006dfaf45010 Mon Sep 17 00:00:00 2001 From: daanx Date: Fri, 19 May 2023 11:57:10 -0700 Subject: [PATCH 4/7] add libc primitives to reduce dependencies --- include/mimalloc/internal.h | 5 +- src/libc.c | 247 ++++++++++++++++++++++++++++++++++++ src/options.c | 10 +- src/prim/unix/prim.c | 4 +- src/stats.c | 9 +- 5 files changed, 261 insertions(+), 14 deletions(-) create mode 100644 src/libc.c diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 03b6dbaa..40401736 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -189,7 +189,10 @@ bool _mi_free_delayed_block(mi_block_t* block); void _mi_free_generic(const mi_segment_t* segment, mi_page_t* page, bool is_local, void* p) mi_attr_noexcept; // for runtime integration void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size); -// libc.c, c primitives +// "libc.c" +#include +void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args); +void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...); char _mi_toupper(char c); int _mi_strnicmp(const char* s, const char* t, size_t n); void _mi_strlcpy(char* dest, const char* src, size_t dest_size); diff --git a/src/libc.c b/src/libc.c new file mode 100644 index 00000000..8a429c09 --- /dev/null +++ b/src/libc.c @@ -0,0 +1,247 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2023, Microsoft Research, Daan Leijen +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +// -------------------------------------------------------- +// This module defines various std libc functions to reduce +// the dependency on libc, and also prevent errors caused +// by some libc implementations when called before `main` +// executes (due to malloc redirection) +// -------------------------------------------------------- + +#include "mimalloc.h" +#include "mimalloc/internal.h" +#include "mimalloc/prim.h" // mi_prim_getenv + +char _mi_toupper(char c) { + if (c >= 'a' && c <= 'z') return (c - 'a' + 'A'); + else return c; +} + +int _mi_strnicmp(const char* s, const char* t, size_t n) { + if (n == 0) return 0; + for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) { + if (_mi_toupper(*s) != _mi_toupper(*t)) break; + } + return (n == 0 ? 0 : *s - *t); +} + +void _mi_strlcpy(char* dest, const char* src, size_t dest_size) { + if (dest==NULL || src==NULL || dest_size == 0) return; + // copy until end of src, or when dest is (almost) full + while (*src != 0 && dest_size > 1) { + *dest++ = *src++; + dest_size--; + } + // always zero terminate + *dest = 0; +} + +void _mi_strlcat(char* dest, const char* src, size_t dest_size) { + if (dest==NULL || src==NULL || dest_size == 0) return; + // find end of string in the dest buffer + while (*dest != 0 && dest_size > 1) { + dest++; + dest_size--; + } + // and catenate + _mi_strlcpy(dest, src, dest_size); +} + +size_t _mi_strlen(const char* s) { + if (s==NULL) return 0; + size_t len = 0; + while(s[len] != 0) { len++; } + return len; +} + +size_t _mi_strnlen(const char* s, size_t max_len) { + if (s==NULL) return 0; + size_t len = 0; + while(s[len] != 0 && len < max_len) { len++; } + return len; +} + +#ifdef MI_NO_GETENV +bool _mi_getenv(const char* name, char* result, size_t result_size) { + MI_UNUSED(name); + MI_UNUSED(result); + MI_UNUSED(result_size); + return false; +} +#else +bool _mi_getenv(const char* name, char* result, size_t result_size) { + if (name==NULL || result == NULL || result_size < 64) return false; + return _mi_prim_getenv(name,result,result_size); +} +#endif + +// -------------------------------------------------------- +// Define our own limited `_vsnprintf` +// -------------------------------------------------------- + +static void mi_outc(char c, char** out, char* end) { + char* p = *out; + if (p >= end) return; + *p = c; + *out = p + 1; +} + +static void mi_outs(const char* s, char** out, char* end) { + if (s == NULL) return; + char* p = *out; + while (*s != 0 && p < end) { + *p++ = *s++; + } + *out = p; +} + +static void mi_out_fill(char fill, size_t len, char** out, char* end) { + char* p = *out; + for (size_t i = 0; i < len && p < end; i++) { + *p++ = fill; + } + *out = p; +} + +static void mi_out_alignright(char fill, char* start, size_t len, size_t extra, char* end) { + if (len == 0 || extra == 0) return; + if (start + len + extra >= end) return; + // move `len` characters to the right (in reverse since it can overlap) + for (size_t i = 1; i <= len; i++) { + start[len + extra - i] = start[len - i]; + } + // and fill the start + for (size_t i = 0; i < extra; i++) { + start[i] = fill; + } +} + + +static void mi_out_num(uintptr_t x, size_t base, char prefix, char** out, char* end) +{ + if (x == 0 || base == 0 || base > 16) { + if (prefix != 0) { mi_outc(prefix, out, end); } + mi_outc('0',out,end); + } + else { + // output digits in reverse + char* start = *out; + while (x > 0) { + char digit = (char)(x % base); + mi_outc((digit <= 9 ? '0' + digit : 'A' + digit - 10),out,end); + x = x / base; + } + if (prefix != 0) { + mi_outc(prefix, out, end); + } + size_t len = *out - start; + // and reverse in-place + for (size_t i = 0; i < (len / 2); i++) { + char c = start[len - i - 1]; + start[len - i - 1] = start[i]; + start[i] = c; + } + } +} + + +#define MI_NEXTC() c = *in; if (c==0) break; in++; + +void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { + if (buf == NULL || bufsize == 0 || fmt == NULL) return; + buf[bufsize - 1] = 0; + char* const end = buf + (bufsize - 1); + const char* in = fmt; + char* out = buf; + while (true) { + if (out >= end) break; + char c; + MI_NEXTC(); + if (c != '%') { + mi_outc(c,&out,end); + } + else { + MI_NEXTC(); + char fill = ' '; + size_t width = 0; + char numtype = 'd'; + char numplus = 0; + bool alignright = true; + if (c == '+' || c == ' ') { numplus = c; MI_NEXTC(); } + if (c == '-') { alignright = false; MI_NEXTC(); } + if (c == '0') { fill = '0'; MI_NEXTC(); } + if (c >= '1' && c <= '9') { + width = (c - '0'); MI_NEXTC(); + while (c >= '0' && c <= '9') { + width = (10 * width) + (c - '0'); MI_NEXTC(); + } + if (c == 0) break; // extra check due to while + } + if (c == 'z' || c == 'l') { numtype = c; MI_NEXTC(); } + + char* const start = out; + if (c == 's') { + // string + const char* s = va_arg(args, const char*); + mi_outs(s, &out, end); + } + else if (c == 'p' || c == 'x' || c == 'u') { + // unsigned + uintptr_t x = 0; + if (c == 'x' || c == 'u') { + if (numtype == 'z') x = va_arg(args, size_t); + else x = va_arg(args, unsigned long); + } + else if (c == 'p') { + x = va_arg(args, uintptr_t); + mi_outs("0x", &out, end); + if (width == 0) { + width = 2 * sizeof(void*); + fill = '0'; + } + } + mi_out_num(x, (c == 'x' || c == 'p' ? 16 : 10), numplus, &out, end); + } + else if (c == 'i' || c == 'd') { + // signed + long x = va_arg(args, long); + char pre = 0; + if (x < 0) { + pre = '-'; + x = -x; + } + else if (numplus != 0) { + pre = numplus; + } + mi_out_num((size_t)x, 10, pre, &out, end); + } + else if (c >= ' ' && c < '~') { + mi_outc(c, &out, end); + } + + // fill & align + mi_assert_internal(out <= end); + mi_assert_internal(out >= start); + const size_t len = out - start; + if (len < width) { + mi_out_fill(fill, width - len, &out, end); + if (alignright && out <= end) { + mi_out_alignright(fill, start, len, width - len, end); + } + } + } + } + mi_assert_internal(out <= end); + *out = 0; +} + +void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + _mi_vsnprintf(buf, buflen, fmt, args); + va_end(args); +} diff --git a/src/options.c b/src/options.c index 8605cbb8..b6a3c829 100644 --- a/src/options.c +++ b/src/options.c @@ -9,9 +9,9 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc/atomic.h" #include "mimalloc/prim.h" // mi_prim_out_stderr -#include // FILE +#include // stdin/stdout #include // abort -#include + static long mi_max_error_count = 16; // stop outputting errors after this (use < 0 for no limit) @@ -312,12 +312,12 @@ void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* me } // Define our own limited `fprintf` that avoids memory allocation. -// We do this using `snprintf` with a limited buffer. +// We do this using `_mi_vsnprintf` with a limited buffer. static void mi_vfprintf( mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args ) { char buf[512]; if (fmt==NULL) return; if (!mi_recurse_enter()) return; - vsnprintf(buf,sizeof(buf)-1,fmt,args); + _mi_vsnprintf(buf, sizeof(buf)-1, fmt, args); mi_recurse_exit(); _mi_fputs(out,arg,prefix,buf); } @@ -332,7 +332,7 @@ void _mi_fprintf( mi_output_fun* out, void* arg, const char* fmt, ... ) { static void mi_vfprintf_thread(mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args) { if (prefix != NULL && _mi_strnlen(prefix,33) <= 32 && !_mi_is_main_thread()) { char tprefix[64]; - snprintf(tprefix, sizeof(tprefix), "%sthread 0x%llx: ", prefix, (unsigned long long)_mi_thread_id()); + _mi_snprintf(tprefix, sizeof(tprefix), "%sthread 0x%zx: ", prefix, (size_t)_mi_thread_id()); mi_vfprintf(out, arg, tprefix, fmt, args); } else { diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index b64f0173..54bf57b2 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -476,8 +476,6 @@ int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bo #if defined(__linux__) -#include // snprintf - size_t _mi_prim_numa_node(void) { #if defined(MI_HAS_SYSCALL_H) && defined(SYS_getcpu) unsigned long node = 0; @@ -495,7 +493,7 @@ size_t _mi_prim_numa_node_count(void) { unsigned node = 0; for(node = 0; node < 256; node++) { // enumerate node entries -- todo: it there a more efficient way to do this? (but ensure there is no allocation) - snprintf(buf, 127, "/sys/devices/system/node/node%u", node + 1); + _mi_snprintf(buf, 127, "/sys/devices/system/node/node%u", node + 1); if (mi_prim_access(buf,R_OK) != 0) break; } return (node+1); diff --git a/src/stats.c b/src/stats.c index a8eac648..33a11fc3 100644 --- a/src/stats.c +++ b/src/stats.c @@ -9,7 +9,6 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc/atomic.h" #include "mimalloc/prim.h" -#include // snprintf #include // memset #if defined(_MSC_VER) && (_MSC_VER < 1920) @@ -146,7 +145,7 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* const int64_t pos = (n < 0 ? -n : n); if (pos < base) { if (n!=1 || suffix[0] != 'B') { // skip printing 1 B for the unit column - snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix)); + _mi_snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix)); } } else { @@ -158,8 +157,8 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* const long whole = (long)(tens/10); const long frac1 = (long)(tens%10); char unitdesc[8]; - snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix); - snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc); + _mi_snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix); + _mi_snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc); } _mi_fprintf(out, arg, (fmt==NULL ? "%12s" : fmt), buf); } @@ -255,7 +254,7 @@ static void mi_stats_print_bins(const mi_stat_count_t* bins, size_t max, const c if (bins[i].allocated > 0) { found = true; int64_t unit = _mi_bin_size((uint8_t)i); - snprintf(buf, 64, "%s %3lu", fmt, (long)i); + _mi_snprintf(buf, 64, "%s %3lu", fmt, (long)i); mi_stat_print(&bins[i], buf, unit, out, arg); } } From 7fda289cbd67306c844a3d850f386d0aabf40609 Mon Sep 17 00:00:00 2001 From: daanx Date: Fri, 19 May 2023 12:07:07 -0700 Subject: [PATCH 5/7] small fixes --- src/libc.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/libc.c b/src/libc.c index 8a429c09..17948736 100644 --- a/src/libc.c +++ b/src/libc.c @@ -80,7 +80,16 @@ bool _mi_getenv(const char* name, char* result, size_t result_size) { #endif // -------------------------------------------------------- -// Define our own limited `_vsnprintf` +// Define our own limited `_mi_vsnprintf` and `_mi_snprintf` +// This is mostly to avoid calling these when libc is not yet +// initialized (and to reduce dependencies) +// +// format: d i, p x u, s +// prec: z l +// width: 10 +// align-left: - +// fill: 0 +// plus: + // -------------------------------------------------------- static void mi_outc(char c, char** out, char* end) { @@ -208,16 +217,18 @@ void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { } else if (c == 'i' || c == 'd') { // signed - long x = va_arg(args, long); + intptr_t x = 0; + if (numtype == 'z') x = va_arg(args, intptr_t ); + else x = va_arg(args, long); char pre = 0; if (x < 0) { pre = '-'; - x = -x; + if (x > INTPTR_MIN) { x = -x; } } else if (numplus != 0) { pre = numplus; } - mi_out_num((size_t)x, 10, pre, &out, end); + mi_out_num((uintptr_t)x, 10, pre, &out, end); } else if (c >= ' ' && c < '~') { mi_outc(c, &out, end); From c1218883a4b6b6e2684219d587f7df76e869a2be Mon Sep 17 00:00:00 2001 From: daanx Date: Fri, 19 May 2023 17:47:44 -0700 Subject: [PATCH 6/7] more format specifiers for _mi_vsnprintf --- src/libc.c | 41 ++++++++++++++++++++++++++++------------- src/options.c | 2 +- src/stats.c | 2 +- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/libc.c b/src/libc.c index 17948736..f1412722 100644 --- a/src/libc.c +++ b/src/libc.c @@ -85,7 +85,7 @@ bool _mi_getenv(const char* name, char* result, size_t result_size) { // initialized (and to reduce dependencies) // // format: d i, p x u, s -// prec: z l +// prec: z l ll L // width: 10 // align-left: - // fill: 0 @@ -171,7 +171,9 @@ void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { char c; MI_NEXTC(); if (c != '%') { - mi_outc(c,&out,end); + if ((c >= ' ' && c <= '~') || c=='\n' || c=='\r' || c=='\t') { // output visible ascii or standard control only + mi_outc(c, &out, end); + } } else { MI_NEXTC(); @@ -190,9 +192,13 @@ void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { } if (c == 0) break; // extra check due to while } - if (c == 'z' || c == 'l') { numtype = c; MI_NEXTC(); } + if (c == 'z' || c == 't' || c == 'L') { numtype = c; MI_NEXTC(); } + else if (c == 'l') { + numtype = c; MI_NEXTC(); + if (c == 'l') { numtype = 'L'; MI_NEXTC(); } + } - char* const start = out; + char* start = out; if (c == 's') { // string const char* s = va_arg(args, const char*); @@ -202,24 +208,31 @@ void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { // unsigned uintptr_t x = 0; if (c == 'x' || c == 'u') { - if (numtype == 'z') x = va_arg(args, size_t); - else x = va_arg(args, unsigned long); + if (numtype == 'z') x = va_arg(args, size_t); + else if (numtype == 't') x = va_arg(args, uintptr_t); // unsigned ptrdiff_t + else if (numtype == 'L') x = va_arg(args, unsigned long long); + else x = va_arg(args, unsigned long); } else if (c == 'p') { x = va_arg(args, uintptr_t); mi_outs("0x", &out, end); - if (width == 0) { - width = 2 * sizeof(void*); - fill = '0'; - } + start = out; + width = (width >= 2 ? width - 2 : 0); + } + if (width == 0 && (c == 'x' || c == 'p')) { + if (c == 'p') { width = 2 * (x <= UINT32_MAX ? 4 : ((x >> 16) <= UINT32_MAX ? 6 : sizeof(void*))); } + if (width == 0) { width = 2; } + fill = '0'; } mi_out_num(x, (c == 'x' || c == 'p' ? 16 : 10), numplus, &out, end); } else if (c == 'i' || c == 'd') { // signed intptr_t x = 0; - if (numtype == 'z') x = va_arg(args, intptr_t ); - else x = va_arg(args, long); + if (numtype == 'z') x = va_arg(args, intptr_t ); + else if (numtype == 't') x = va_arg(args, ptrdiff_t); + else if (numtype == 'L') x = va_arg(args, long long); + else x = va_arg(args, long); char pre = 0; if (x < 0) { pre = '-'; @@ -230,7 +243,9 @@ void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) { } mi_out_num((uintptr_t)x, 10, pre, &out, end); } - else if (c >= ' ' && c < '~') { + else if (c >= ' ' && c <= '~') { + // unknown format + mi_outc('%', &out, end); mi_outc(c, &out, end); } diff --git a/src/options.c b/src/options.c index b6a3c829..bf7a5848 100644 --- a/src/options.c +++ b/src/options.c @@ -332,7 +332,7 @@ void _mi_fprintf( mi_output_fun* out, void* arg, const char* fmt, ... ) { static void mi_vfprintf_thread(mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args) { if (prefix != NULL && _mi_strnlen(prefix,33) <= 32 && !_mi_is_main_thread()) { char tprefix[64]; - _mi_snprintf(tprefix, sizeof(tprefix), "%sthread 0x%zx: ", prefix, (size_t)_mi_thread_id()); + _mi_snprintf(tprefix, sizeof(tprefix), "%sthread 0x%tx: ", prefix, (uintptr_t)_mi_thread_id()); mi_vfprintf(out, arg, tprefix, fmt, args); } else { diff --git a/src/stats.c b/src/stats.c index 33a11fc3..fa947e5d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -145,7 +145,7 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* const int64_t pos = (n < 0 ? -n : n); if (pos < base) { if (n!=1 || suffix[0] != 'B') { // skip printing 1 B for the unit column - _mi_snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix)); + _mi_snprintf(buf, len, "%lld %-3s", (long long)n, (n==0 ? "" : suffix)); } } else { From 814dac26a1b2b1745869f0275a97dda759e39425 Mon Sep 17 00:00:00 2001 From: daanx Date: Fri, 19 May 2023 18:00:46 -0700 Subject: [PATCH 7/7] add KiB to size options --- src/options.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/options.c b/src/options.c index bf7a5848..2a83fcc7 100644 --- a/src/options.c +++ b/src/options.c @@ -95,6 +95,10 @@ static mi_option_desc_t options[_mi_option_last] = static void mi_option_init(mi_option_desc_t* desc); +static bool mi_option_has_size_in_kib(mi_option_t option) { + return (option == mi_option_reserve_os_memory || option == mi_option_arena_reserve); +} + void _mi_options_init(void) { // called on process load; should not be called before the CRT is initialized! // (e.g. do not call this from process_init as that may run before CRT initialization) @@ -105,7 +109,7 @@ void _mi_options_init(void) { // if (option != mi_option_verbose) { mi_option_desc_t* desc = &options[option]; - _mi_verbose_message("option '%s': %ld\n", desc->name, desc->value); + _mi_verbose_message("option '%s': %ld %s\n", desc->name, desc->value, (mi_option_has_size_in_kib(option) ? "KiB" : "")); } } mi_max_error_count = mi_option_get(mi_option_max_errors); @@ -129,7 +133,7 @@ mi_decl_nodiscard long mi_option_get_clamp(mi_option_t option, long min, long ma } mi_decl_nodiscard size_t mi_option_get_size(mi_option_t option) { - mi_assert_internal(option == mi_option_reserve_os_memory || option == mi_option_arena_reserve); + mi_assert_internal(mi_option_has_size_in_kib(option)); long x = mi_option_get(option); return (x < 0 ? 0 : (size_t)x * MI_KiB); }