diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d62b8bca..23357bf57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(libmimalloc C CXX) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) +option(MI_CRAN_COMPLIANT "Provide support for compliance with the Comprehensive R-Archive Network (CRAN) policies" OFF) option(MI_SECURE "Use full security mitigations (like guard pages, allocation randomization, double-free mitigation, and free-list corruption detection)" OFF) option(MI_PADDING "Enable padding to detect heap block overflow (always on in DEBUG or SECURE mode, or with Valgrind/ASAN)" OFF) option(MI_OVERRIDE "Override the standard malloc interface (i.e. define entry points for 'malloc', 'free', etc)" ON) diff --git a/src/alloc-override.c b/src/alloc-override.c index 52ab69c53..a06e62a9a 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -32,7 +32,6 @@ typedef void* mi_nothrow_t; #if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__) && !MI_TRACK_ENABLED // gcc, clang: use aliasing to alias the exported function to one of our `mi_` functions #if (defined(__GNUC__) && __GNUC__ >= 9) - #pragma GCC diagnostic ignored "-Wattributes" // or we get warnings that nodiscard is ignored on a forward #define MI_FORWARD(fun) __attribute__((alias(#fun), used, visibility("default"), copy(fun))); #else #define MI_FORWARD(fun) __attribute__((alias(#fun), used, visibility("default"))); diff --git a/src/alloc.c b/src/alloc.c index cd711e73f..99d310188 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -8,6 +8,14 @@ terms of the MIT license. A copy of the license can be found in the file #define _DEFAULT_SOURCE // for realpath() on Linux #endif +#ifndef MI_CRAN_COMPLIANT +#define MI_CRAN_COMPLIANT 0 +#else +#if MI_CRAN_COMPLIANT +#include +#endif +#endif + #include "mimalloc.h" #include "mimalloc/internal.h" #include "mimalloc/atomic.h" @@ -536,10 +544,15 @@ static std_new_handler_t mi_get_new_handler(void) { static bool mi_try_new_handler(bool nothrow) { std_new_handler_t h = mi_get_new_handler(); if (h==NULL) { + #if MI_CRAN_COMPLIANT + if (!nothrow) + Rf_error("out of memory in 'new'"); // R's error mechanism + #else _mi_error_message(ENOMEM, "out of memory in 'new'"); if (!nothrow) { abort(); // cannot throw in plain C, use abort } + #endif return false; } else { diff --git a/src/options.c b/src/options.c index b07f029e6..901f3a083 100644 --- a/src/options.c +++ b/src/options.c @@ -12,7 +12,13 @@ terms of the MIT license. A copy of the license can be found in the file #include // stdin/stdout #include // abort - +#ifndef MI_CRAN_COMPLIANT +#define MI_CRAN_COMPLIANT 0 +#else +#if MI_CRAN_COMPLIANT +#include +#endif +#endif static long mi_max_error_count = 16; // stop outputting errors after this (use < 0 for no limit) static long mi_max_warning_count = 16; // stop outputting warnings after this (use < 0 for no limit) @@ -207,7 +213,13 @@ void mi_options_print(void) mi_attr_noexcept const int vermajor = MI_MALLOC_VERSION/100; const int verminor = (MI_MALLOC_VERSION%100)/10; const int verpatch = (MI_MALLOC_VERSION%10); - _mi_message("v%i.%i.%i%s%s (built on %s, %s)\n", vermajor, verminor, verpatch, + _mi_message( + #if MI_CRAN_COMPLIANT + "v%i.%i.%i%s%s\n" + #else + "v%i.%i.%i%s%s (built on %s, %s)\n", + #endif + , vermajor, verminor, verpatch, #if defined(MI_CMAKE_BUILD_TYPE) ", " mi_stringify(MI_CMAKE_BUILD_TYPE) #else @@ -219,7 +231,10 @@ void mi_options_print(void) mi_attr_noexcept #else "" #endif - , __DATE__, __TIME__); + #if !MI_CRAN_COMPLIANT + , __DATE__, __TIME__ + #endif + ); // show options for (int i = 0; i < _mi_option_last; i++) { @@ -446,7 +461,11 @@ static void mi_recurse_exit(void) { } void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message) { +#if MI_CRAN_COMPLIANT + if (out==NULL) { +#else if (out==NULL || (void*)out==(void*)stdout || (void*)out==(void*)stderr) { // TODO: use mi_out_stderr for stderr? +#endif if (!mi_recurse_enter()) return; out = mi_out_get_default(&arg); if (prefix != NULL) out(prefix, arg); @@ -534,7 +553,11 @@ void _mi_warning_message(const char* fmt, ...) { #if MI_DEBUG mi_decl_noreturn mi_decl_cold void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, const char* func ) mi_attr_noexcept { _mi_fprintf(NULL, NULL, "mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion); + #if MI_CRAN_COMPLIANT + Rf_error("mimalloc: assertion failed"); + #else abort(); + #endif } #endif @@ -552,17 +575,29 @@ static void mi_error_default(int err) { #ifdef _MSC_VER __debugbreak(); #endif + #if MI_CRAN_COMPLIANT + Rf_error("mimalloc: error: EFAULT"); + #else abort(); + #endif } #endif #if (MI_SECURE>0) if (err==EFAULT) { // abort on serious errors in secure mode (corrupted meta-data) + #if MI_CRAN_COMPLIANT + Rf_error("mimalloc: error: EFAULT"); + #else abort(); + #endif } #endif #if defined(MI_XMALLOC) if (err==ENOMEM || err==EOVERFLOW) { // abort on memory allocation fails in xmalloc mode + #if MI_CRAN_COMPLIANT + Rf_error("mimalloc: error: out of memory"); + #else abort(); + #endif } #endif } diff --git a/src/prim/osx/alloc-override-zone.c b/src/prim/osx/alloc-override-zone.c index fee4e5105..b3c74194c 100644 --- a/src/prim/osx/alloc-override-zone.c +++ b/src/prim/osx/alloc-override-zone.c @@ -174,19 +174,6 @@ static boolean_t intro_zone_locked(malloc_zone_t* zone) { return false; } - -/* ------------------------------------------------------ - At process start, override the default allocator ------------------------------------------------------- */ - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - -#if defined(__clang__) -#pragma clang diagnostic ignored "-Wc99-extensions" -#endif - static malloc_introspection_t mi_introspect = { .enumerator = &intro_enumerator, .good_size = &intro_good_size, diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c index 99331e3f8..4ff834ef8 100644 --- a/src/prim/unix/prim.c +++ b/src/prim/unix/prim.c @@ -11,6 +11,10 @@ terms of the MIT license. A copy of the license can be found in the file #define _DEFAULT_SOURCE // ensure mmap flags and syscall are defined #endif +#ifndef MI_CRAN_COMPLIANT +#define MI_CRAN_COMPLIANT 0 +#endif + #if defined(__sun) // illumos provides new mman.h api when any of these are defined // otherwise the old api based on caddr_t which predates the void pointers one. @@ -774,7 +778,11 @@ void _mi_prim_process_info(mi_process_info_t* pinfo) //---------------------------------------------------------------- void _mi_prim_out_stderr( const char* msg ) { + #if MI_CRAN_COMPLIANT + return; + #else fputs(msg,stderr); + #endif } diff --git a/src/prim/wasi/prim.c b/src/prim/wasi/prim.c index 745a41fd3..e5b80839f 100644 --- a/src/prim/wasi/prim.c +++ b/src/prim/wasi/prim.c @@ -14,6 +14,10 @@ terms of the MIT license. A copy of the license can be found in the file #include // fputs #include // getenv +#ifndef MI_CRAN_COMPLIANT +#define MI_CRAN_COMPLIANT 0 +#endif + //--------------------------------------------- // Initialize //--------------------------------------------- @@ -230,7 +234,11 @@ void _mi_prim_process_info(mi_process_info_t* pinfo) //---------------------------------------------------------------- void _mi_prim_out_stderr( const char* msg ) { + #if MI_CRAN_COMPLIANT + return; + #else fputs(msg,stderr); + #endif } diff --git a/src/prim/windows/prim.c b/src/prim/windows/prim.c index 75a93d2a7..065d49096 100644 --- a/src/prim/windows/prim.c +++ b/src/prim/windows/prim.c @@ -12,6 +12,10 @@ terms of the MIT license. A copy of the license can be found in the file #include "mimalloc/prim.h" #include // fputs, stderr +#ifndef MI_CRAN_COMPLIANT +#define MI_CRAN_COMPLIANT 0 +#endif + // xbox has no console IO #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) #define MI_HAS_CONSOLE_IO @@ -588,8 +592,12 @@ void _mi_prim_out_stderr( const char* msg ) WriteFile(hcon, msg, (DWORD)len, &written, NULL); } else { - // finally fall back to fputs after all + #if MI_CRAN_COMPLIANT + return; + #else + // finally fall back to fputs after all fputs(msg, stderr); + #endif } } }