diff --git a/CHANGELOG.md b/CHANGELOG.md index e9acb5ad1..7f9aeda80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +**Features**: + +- Add an opt-in memory reserve that is released when a crash is handled, so crashes are still captured after running out of memory. ([#2274](https://github.com/getsentry/sentry-native/pull/2274)) + **Fixes**: - Events captured while a crash is being handled, such as from the `on_crash` hook, are no longer dropped by `sample_rate`, matching the crash itself. ([#2269](https://github.com/getsentry/sentry-native/pull/2269)) diff --git a/CMakeLists.txt b/CMakeLists.txt index b86d4b4da..d23b50f04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,6 +289,10 @@ endif() set(SENTRY_SDK_NAME "" CACHE STRING "The SDK name to report when sending events.") set(SENTRY_HANDLER_STACK_SIZE 64 CACHE STRING "The stack size (in KiB) that should be reserved for the crash handler.") +set(SENTRY_CRASH_MEMORY_RESERVE 0 CACHE STRING "The memory (in KiB) that is reserved on init and released when a crash is handled. 0 disables it.") +if(NOT SENTRY_CRASH_MEMORY_RESERVE MATCHES "^[0-9]+$") + message(FATAL_ERROR "SENTRY_CRASH_MEMORY_RESERVE must be a non-negative integer") +endif() set(SENTRY_BATCHER_BUFFER_COUNT 3 CACHE STRING "Number of 100-item telemetry buffers (2-10).") if(NOT SENTRY_BATCHER_BUFFER_COUNT MATCHES "^[0-9]+$" OR SENTRY_BATCHER_BUFFER_COUNT LESS 2 @@ -307,6 +311,7 @@ message(STATUS "SENTRY_LIBRARY_TYPE=${SENTRY_LIBRARY_TYPE}") message(STATUS "SENTRY_SDK_NAME=${SENTRY_SDK_NAME}") message(STATUS "SENTRY_INTEGRATION_PLATFORM=${SENTRY_INTEGRATION_PLATFORM}") message(STATUS "SENTRY_HANDLER_STACK_SIZE=${SENTRY_HANDLER_STACK_SIZE}") +message(STATUS "SENTRY_CRASH_MEMORY_RESERVE=${SENTRY_CRASH_MEMORY_RESERVE}") message(STATUS "SENTRY_BATCHER_BUFFER_COUNT=${SENTRY_BATCHER_BUFFER_COUNT}") if (WIN32) message(STATUS "SENTRY_THREAD_STACK_GUARANTEE_FACTOR=${SENTRY_THREAD_STACK_GUARANTEE_FACTOR}") @@ -432,6 +437,7 @@ if(SENTRY_INTEGRATION_PLATFORM) endif() target_compile_definitions(sentry PRIVATE SENTRY_HANDLER_STACK_SIZE=${SENTRY_HANDLER_STACK_SIZE}) +target_compile_definitions(sentry PRIVATE SENTRY_CRASH_MEMORY_RESERVE=${SENTRY_CRASH_MEMORY_RESERVE}) target_compile_definitions(sentry PRIVATE SENTRY_BATCHER_BUFFER_COUNT=${SENTRY_BATCHER_BUFFER_COUNT}) if(WIN32) target_compile_definitions(sentry PRIVATE SENTRY_THREAD_STACK_GUARANTEE_FACTOR=${SENTRY_THREAD_STACK_GUARANTEE_FACTOR}) diff --git a/README.md b/README.md index fc21a0ced..a75860bee 100644 --- a/README.md +++ b/README.md @@ -314,6 +314,10 @@ using `cmake -D BUILD_SHARED_LIBS=OFF ..`. this value can be as small as 16KiB with `breakpad` and 24KiB with `crashpad` and `native`, but we recommend 32KiB as the lower bound on 64-bit systems. **The value should be a multiple of the page size**. +- `SENTRY_CRASH_MEMORY_RESERVE` (Default: `0`): + The size in KiB of memory reserved on `sentry_init()` and released when a crash is handled, so the crash handler + can still allocate after the application has run out of memory. `0` disables it. + - `SENTRY_THREAD_STACK_GUARANTEE_FACTOR` (Default: `10`, only for Windows): Defines the factor by which the thread's stack reserve must exceed the specified guarantee for the handler. _Example_: if the `SENTRY_HANDLER_STACK_SIZE` is defined as 64KiB, then the thread's stack reserve must at least have diff --git a/include/sentry.h b/include/sentry.h index 14484bdfc..220b88d4a 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -2458,6 +2458,17 @@ SENTRY_API void sentry_options_set_crashpad_limit_stack_capture_to_sp( SENTRY_API void sentry_options_set_max_stack_capture_size( sentry_options_t *opts, uint32_t max_stack_capture_size); +/** + * Sets the size (in bytes) of memory that is reserved on `sentry_init` and + * released when a crash is handled, so the crash handler can still allocate + * after the application has run out of memory. `0` disables it. + * + * Defaults to the `SENTRY_CRASH_MEMORY_RESERVE` build setting (in KiB), which + * is `0`. Custom backends must release the reserve from their crash handler. + */ +SENTRY_API void sentry_options_set_crash_memory_reserve( + sentry_options_t *opts, size_t bytes); + /** * Sets the maximum time (in milliseconds) to wait for the asynchronous * tasks to end on shutdown before attempting a forced termination. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b528429f9..c66ff0261 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,8 @@ sentry_target_sources_cwd(sentry sentry_client_report.h sentry_core.c sentry_core.h + sentry_crash_reserve.c + sentry_crash_reserve.h sentry_cpu_relax.h sentry_database.c sentry_database.h diff --git a/src/backends/native/sentry_crash_handler.c b/src/backends/native/sentry_crash_handler.c index a811712a0..a9cabf8ba 100644 --- a/src/backends/native/sentry_crash_handler.c +++ b/src/backends/native/sentry_crash_handler.c @@ -8,6 +8,7 @@ #include "sentry_alloc.h" #include "sentry_core.h" +#include "sentry_crash_reserve.h" #include "sentry_logger.h" #include "sentry_os.h" #include "sentry_sync.h" @@ -336,6 +337,8 @@ crash_signal_handler(int signum, siginfo_t *info, void *context) _exit(1); } + sentry__crash_reserve_release(); + sentry_crash_context_t *ctx = ipc->shmem; // Fill crash context @@ -1037,6 +1040,9 @@ crash_exception_filter(EXCEPTION_POINTERS *exception_info) return EXCEPTION_CONTINUE_SEARCH; } + // the daemon may share the application's memory budget + sentry__crash_reserve_release(); + sentry_crash_context_t *ctx = ipc->shmem; // Fill crash context diff --git a/src/backends/sentry_backend_breakpad.cpp b/src/backends/sentry_backend_breakpad.cpp index 1662686e2..86878bafc 100644 --- a/src/backends/sentry_backend_breakpad.cpp +++ b/src/backends/sentry_backend_breakpad.cpp @@ -6,6 +6,7 @@ extern "C" { #include "sentry_backend.h" #include "sentry_client_report.h" #include "sentry_core.h" +#include "sentry_crash_reserve.h" #include "sentry_database.h" #include "sentry_envelope.h" #include "sentry_hint.h" @@ -344,6 +345,20 @@ IsDebuggerActive() } #endif +// called before the minidump is written +#ifdef SENTRY_PLATFORM_WINDOWS +static bool +breakpad_backend_filter(void *UNUSED(context), + EXCEPTION_POINTERS *UNUSED(exinfo), MDRawAssertionInfo *UNUSED(assertion)) +#else +static bool +breakpad_backend_filter(void *UNUSED(context)) +#endif +{ + sentry__crash_reserve_release(); + return true; +} + static int breakpad_backend_startup( sentry_backend_t *backend, const sentry_options_t *options) @@ -355,26 +370,28 @@ breakpad_backend_startup( && defined(SENTRY_THREAD_STACK_GUARANTEE_AUTO_INIT) sentry__set_default_thread_stack_guarantee(); # endif - backend->data = new (std::nothrow) google_breakpad::ExceptionHandler( - current_run_folder->path_w, nullptr, breakpad_backend_callback, nullptr, - google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); + backend->data = new (std::nothrow) + google_breakpad::ExceptionHandler(current_run_folder->path_w, + breakpad_backend_filter, breakpad_backend_callback, nullptr, + google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); if (backend->data) { sentry__win32_install_sigabrt_handler(handle_sigabrt); } #elif defined(SENTRY_PLATFORM_MACOS) // If process is being debugged and there are breakpoints set it will cause // task_set_exception_ports to crash the whole process and debugger - backend->data = new (std::nothrow) - google_breakpad::ExceptionHandler(current_run_folder->path, nullptr, - breakpad_backend_callback, nullptr, !IsDebuggerActive(), nullptr); + backend->data = new (std::nothrow) google_breakpad::ExceptionHandler( + current_run_folder->path, breakpad_backend_filter, + breakpad_backend_callback, nullptr, !IsDebuggerActive(), nullptr); #elif defined(SENTRY_PLATFORM_IOS) - backend->data = new (std::nothrow) - google_breakpad::ExceptionHandler(current_run_folder->path, nullptr, - breakpad_backend_callback, nullptr, true, nullptr); + backend->data = new (std::nothrow) google_breakpad::ExceptionHandler( + current_run_folder->path, breakpad_backend_filter, + breakpad_backend_callback, nullptr, true, nullptr); #else google_breakpad::MinidumpDescriptor descriptor(current_run_folder->path); - backend->data = new (std::nothrow) google_breakpad::ExceptionHandler( - descriptor, nullptr, breakpad_backend_callback, nullptr, true, -1); + backend->data = new (std::nothrow) + google_breakpad::ExceptionHandler(descriptor, breakpad_backend_filter, + breakpad_backend_callback, nullptr, true, -1); #endif return backend->data == nullptr; } diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index c31018583..a4693f7e4 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -6,6 +6,7 @@ extern "C" { #include "sentry_backend.h" #include "sentry_core.h" #include "sentry_cpu_relax.h" +#include "sentry_crash_reserve.h" #include "sentry_database.h" #include "sentry_envelope.h" #include "sentry_hint.h" @@ -557,6 +558,7 @@ crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context) (void)!sentry__enter_signal_handler(); # endif sentry__enter_crash_handler(); + sentry__crash_reserve_release(); // Disable logging during crash handling if the option is set SENTRY_WITH_OPTIONS (options) { if (!options->enable_logging_when_crashed) { diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index 0bc415b3f..33a27bd85 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -5,6 +5,7 @@ #include "sentry_backend.h" #include "sentry_core.h" #include "sentry_cpu_relax.h" +#include "sentry_crash_reserve.h" #include "sentry_database.h" #include "sentry_envelope.h" #include "sentry_hint.h" @@ -1358,6 +1359,8 @@ process_ucontext(const sentry_ucontext_t *uctx) } #endif + sentry__crash_reserve_release(); + if (!g_backend_config.enable_logging_when_crashed) { sentry__logger_disable(); } diff --git a/src/sentry_core.c b/src/sentry_core.c index 5dd346a16..0365a8e2a 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -12,6 +12,7 @@ #include "sentry_backend.h" #include "sentry_client_report.h" #include "sentry_core.h" +#include "sentry_crash_reserve.h" #include "sentry_database.h" #include "sentry_envelope.h" #include "sentry_hint.h" @@ -253,6 +254,8 @@ sentry_init(sentry_options_t *options) } initial_scope_prepared = true; + sentry__crash_reserve_alloc(options->crash_memory_reserve); + // and then we will start the backend, since it requires a valid run sentry_backend_t *backend = options->backend; if (backend && backend->startup_func) { @@ -313,6 +316,7 @@ sentry_init(sentry_options_t *options) fail: SENTRY_WARN("`sentry_init` failed"); + sentry__crash_reserve_release(); if (transport) { sentry__transport_shutdown(transport, 0); } @@ -384,6 +388,7 @@ sentry_close(void) SENTRY_DEBUG("shutting down backend"); options->backend->shutdown_func(options->backend); } + sentry__crash_reserve_release(); if (options->transport) { if (sentry__transport_shutdown( diff --git a/src/sentry_crash_reserve.c b/src/sentry_crash_reserve.c new file mode 100644 index 000000000..a9b7e7dd0 --- /dev/null +++ b/src/sentry_crash_reserve.c @@ -0,0 +1,96 @@ +#include "sentry_crash_reserve.h" +#include "sentry_logger.h" + +#include + +#if defined(SENTRY_PLATFORM_WINDOWS) +# include +# define SENTRY_CRASH_RESERVE_SUPPORTED +#elif defined(SENTRY_PLATFORM_UNIX) && !defined(SENTRY_PLATFORM_PS) +# include +# if !defined(MAP_ANONYMOUS) && defined(SENTRY_PLATFORM_DARWIN) +# define MAP_ANONYMOUS MAP_ANON +# endif +# define SENTRY_CRASH_RESERVE_SUPPORTED +#endif + +static void *volatile g_reserve = NULL; + +#ifdef SENTRY_CRASH_RESERVE_SUPPORTED +static void * +swap_reserve(void *ptr) +{ +# ifdef SENTRY_PLATFORM_WINDOWS + return InterlockedExchangePointer((void *volatile *)&g_reserve, ptr); +# else + return __atomic_exchange_n(&g_reserve, ptr, __ATOMIC_SEQ_CST); +# endif +} + +static void * +map_memory(size_t size) +{ +# ifdef SENTRY_PLATFORM_WINDOWS + return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +# else + void *ptr = mmap( + NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + return ptr == MAP_FAILED ? NULL : ptr; +# endif +} +#endif + +void +sentry__crash_reserve_alloc(size_t size) +{ + sentry__crash_reserve_release(); + if (size == 0) { + return; + } + +#ifdef SENTRY_CRASH_RESERVE_SUPPORTED + void *ptr = map_memory(size); + if (!ptr) { + SENTRY_WARNF( + "failed to reserve %zu bytes of crash handler memory", size); + return; + } + // touch the pages so they are backed by memory + memset(ptr, 1, size); + // the size travels with the mapping + size_t *hdr = ptr; + hdr[0] = size; + hdr[1] = ~size; + swap_reserve(ptr); + SENTRY_DEBUGF("reserved %zu bytes of crash handler memory", size); +#else + SENTRY_WARN("the crash memory reserve is not supported on this platform"); +#endif +} + +void +sentry__crash_reserve_release(void) +{ +#ifdef SENTRY_CRASH_RESERVE_SUPPORTED + void *ptr = swap_reserve(NULL); + if (!ptr) { + return; + } +# ifdef SENTRY_PLATFORM_WINDOWS + VirtualFree(ptr, 0, MEM_RELEASE); +# else + size_t *hdr = ptr; + // don't let a corrupted size unmap unrelated memory + if (hdr[1] == ~hdr[0]) { + munmap(ptr, hdr[0]); + } +# endif +#endif +} + +size_t +sentry__crash_reserve_size(void) +{ + void *ptr = g_reserve; + return ptr ? *(size_t *)ptr : 0; +} diff --git a/src/sentry_crash_reserve.h b/src/sentry_crash_reserve.h new file mode 100644 index 000000000..e3f96bafd --- /dev/null +++ b/src/sentry_crash_reserve.h @@ -0,0 +1,22 @@ +#ifndef SENTRY_CRASH_RESERVE_H_INCLUDED +#define SENTRY_CRASH_RESERVE_H_INCLUDED + +#include "sentry_boot.h" + +/** + * Reserves `size` bytes of committed memory for the crash handler, replacing + * any previous reserve. + */ +void sentry__crash_reserve_alloc(size_t size); + +/** + * Releases the reserve. Safe to call from a crash handler and more than once. + */ +void sentry__crash_reserve_release(void); + +/** + * Returns the size of the memory that is currently reserved, or `0`. + */ +size_t sentry__crash_reserve_size(void); + +#endif diff --git a/src/sentry_options.c b/src/sentry_options.c index bfb62146b..9fff22277 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -92,6 +92,7 @@ sentry_options_new(void) opts->strict_trace_continuation = false; opts->crashpad_limit_stack_capture_to_sp = false; opts->max_stack_capture_size = 0; + opts->crash_memory_reserve = (size_t)SENTRY_CRASH_MEMORY_RESERVE * 1024; opts->cache_keep = SENTRY_CACHE_KEEP_NONE; opts->cache_max_age = 0; opts->cache_max_size = 0; @@ -767,6 +768,12 @@ sentry_options_set_max_stack_capture_size( opts->max_stack_capture_size = max_stack_capture_size; } +void +sentry_options_set_crash_memory_reserve(sentry_options_t *opts, size_t bytes) +{ + opts->crash_memory_reserve = bytes; +} + void sentry_options_set_shutdown_timeout( sentry_options_t *opts, uint64_t shutdown_timeout) diff --git a/src/sentry_options.h b/src/sentry_options.h index 12548a79d..405f43e77 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -56,6 +56,7 @@ struct sentry_options_s { bool strict_trace_continuation; bool crashpad_limit_stack_capture_to_sp; uint32_t max_stack_capture_size; + size_t crash_memory_reserve; sentry_cache_keep_t cache_keep; time_t cache_max_age; diff --git a/tests/fixtures/integration.c b/tests/fixtures/integration.c index 11d8dbb49..dc900f2ac 100644 --- a/tests/fixtures/integration.c +++ b/tests/fixtures/integration.c @@ -586,7 +586,7 @@ trigger_stack_overflow() } static void -trigger_oom(void) +limit_process_memory(void) { #ifdef SENTRY_PLATFORM_WINDOWS // Optionally limit process memory to trigger OOM faster. @@ -610,6 +610,12 @@ trigger_oom(void) } } #endif +} + +static void +trigger_oom(void) +{ + limit_process_memory(); size_t count = 1024; for (;;) { @@ -631,6 +637,32 @@ trigger_oom(void) } } +static void +trigger_oom_exhaust(void) +{ + limit_process_memory(); + + // keep allocating smaller blocks until almost no memory is left + for (size_t size = 64 * 1024 * 1024; size >= 64 * 1024; size /= 2) { + for (;;) { +#ifdef SENTRY_PLATFORM_WINDOWS + void *p = HeapAlloc(GetProcessHeap(), 0, size); +#else + void *p = malloc(size); +#endif + if (!p) { + break; + } + memset(p, 1, size); + } + } +#ifdef SENTRY_PLATFORM_WINDOWS + RaiseException(0xc000, 0, 0, NULL); +#else + *((volatile int *)3) = 1; +#endif +} + static sentry_value_t create_debug_crumb(const char *message) { @@ -838,6 +870,10 @@ main(int argc, char **argv) sentry_options_set_on_crash(options, on_crash_callback, NULL); } + if (has_arg(argc, argv, "crash-memory-reserve")) { + sentry_options_set_crash_memory_reserve(options, 4 * 1024 * 1024); + } + if (has_arg(argc, argv, "on-crashed-last-run")) { sentry_options_set_on_crashed_last_run( options, on_crashed_last_run_callback, NULL); @@ -1378,6 +1414,9 @@ main(int argc, char **argv) if (has_arg(argc, argv, "oom")) { trigger_oom(); } + if (has_arg(argc, argv, "oom-exhaust")) { + trigger_oom_exhaust(); + } #if defined(SENTRY_PLATFORM_WINDOWS) && !defined(__MINGW32__) \ && !defined(__MINGW64__) if (has_arg(argc, argv, "fastfail")) { diff --git a/tests/test_integration_stdout.py b/tests/test_integration_stdout.py index ba6326377..cc7651dbb 100644 --- a/tests/test_integration_stdout.py +++ b/tests/test_integration_stdout.py @@ -321,6 +321,25 @@ def test_abort_stdout(cmake, backend): pytest.fail(f"unsupported backend: {backend}") +@pytest.mark.skipif(not has_breakpad, reason="test needs breakpad backend") +@pytest.mark.skipif( + sys.platform != "win32", reason="test needs a Job Object memory limit" +) +def test_breakpad_oom_crash_memory_reserve_stdout(cmake): + """Test that a crash is captured after the process ran out of memory.""" + tmp_path, output = run_stdout_for( + "breakpad", + cmake, + ["crash-memory-reserve", "oom-exhaust"], + env=dict(os.environ, SENTRY_TEST_OOM_LIMIT="256"), + ) + + envelope = Envelope.deserialize(output) + + assert_minidump(envelope) + assert_breakpad_crash(envelope) + + @pytest.mark.skipif(is_qemu, reason="unreliable under qemu-user") def test_inproc_crash_stdout_before_send(cmake): tmp_path, output = run_crash_stdout_for("inproc", cmake, ["before-send"]) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 5c017bc0d..2869a2f01 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(sentry_test_unit test_cache.c test_client_report.c test_consent.c + test_crash_reserve.c test_concurrency.c test_embedded_info.c test_envelopes.c diff --git a/tests/unit/test_crash_reserve.c b/tests/unit/test_crash_reserve.c new file mode 100644 index 000000000..d221d4ed2 --- /dev/null +++ b/tests/unit/test_crash_reserve.c @@ -0,0 +1,67 @@ +#include "sentry_crash_reserve.h" +#include "sentry_testsupport.h" + +#if defined(SENTRY_PLATFORM_WINDOWS) \ + || (defined(SENTRY_PLATFORM_UNIX) && !defined(SENTRY_PLATFORM_PS)) +# define CRASH_RESERVE_SUPPORTED +#endif + +SENTRY_TEST(crash_reserve_alloc_release) +{ +#ifndef CRASH_RESERVE_SUPPORTED + SKIP_TEST(); +#else + sentry__crash_reserve_alloc(64 * 1024); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 64 * 1024); + + sentry__crash_reserve_release(); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 0); + + // releasing again is a no-op + sentry__crash_reserve_release(); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 0); +#endif +} + +SENTRY_TEST(crash_reserve_disabled) +{ + sentry__crash_reserve_alloc(0); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 0); + sentry__crash_reserve_release(); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 0); +} + +SENTRY_TEST(crash_reserve_init_close) +{ +#ifndef CRASH_RESERVE_SUPPORTED + SKIP_TEST(); +#else + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_crash_memory_reserve(options, 128 * 1024); + sentry_init(options); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 128 * 1024); + + sentry_close(); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 0); + + SENTRY_TEST_OPTIONS_NEW(default_options); + sentry_init(default_options); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), + (size_t)SENTRY_CRASH_MEMORY_RESERVE * 1024); + sentry_close(); +#endif +} + +SENTRY_TEST(crash_reserve_realloc) +{ +#ifndef CRASH_RESERVE_SUPPORTED + SKIP_TEST(); +#else + sentry__crash_reserve_alloc(64 * 1024); + sentry__crash_reserve_alloc(256 * 1024); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 256 * 1024); + + sentry__crash_reserve_release(); + TEST_CHECK_INT_EQUAL(sentry__crash_reserve_size(), 0); +#endif +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index b9dcad661..417366f51 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -142,6 +142,10 @@ XX(crash_context_null_options) XX(crash_context_options_propagation) XX(crash_context_transport_fields) XX(crash_marker) +XX(crash_reserve_alloc_release) +XX(crash_reserve_disabled) +XX(crash_reserve_init_close) +XX(crash_reserve_realloc) XX(crashed_last_run) XX(custom_logger) XX(daemon_adopts_existing_run)