Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
07724c6
transferring to linux test machine
supervacuus Aug 5, 2024
752b125
clean up formatting
supervacuus Aug 5, 2024
b38d0e6
fix build
supervacuus Aug 5, 2024
b41ed01
reintroduce #ifdef symmetry regarding the usage of the handler_strate…
supervacuus Aug 5, 2024
4f57a0e
const options param in the handler_strategy getter
supervacuus Aug 5, 2024
09020db
ensure we "leave" the signal-handler when we invoke the CLR/Mono runt…
supervacuus Aug 5, 2024
fee764e
ensure the page_allocator is only enabled when we have an actual nati…
supervacuus Nov 12, 2024
1a8626d
continuing the signal chain at the end is something we want for both …
supervacuus Nov 12, 2024
eb12874
get rid of obsolete local var
supervacuus Nov 12, 2024
b08d939
add trace logs to at-start chaining, so we can see the behavior in th…
supervacuus Nov 12, 2024
2841e64
ensure page-allocator is only referenced on UNIXes
supervacuus Nov 12, 2024
799743f
add integration test for managed and native crash
supervacuus Nov 14, 2024
0aac4e9
ignore 32-bit Linux build in the integration test
supervacuus Nov 14, 2024
fbe9818
remove native sdk logging assert temporarily
supervacuus Nov 14, 2024
0403d18
fix pytest skip for x86
supervacuus Nov 14, 2024
4231642
inverted demorgan
supervacuus Nov 14, 2024
f926707
extract skip_condition to check what provokes the invalid syntax
supervacuus Nov 14, 2024
6e65b62
re-enable log check, since we know it is not about log flushing but d…
supervacuus Nov 15, 2024
67de245
clean up sigaltstack initialization
supervacuus Nov 15, 2024
bc47fcf
clean up run assertion on output, so we can actually see what's happe…
supervacuus Nov 15, 2024
84c94df
create a non-faulty `sigaltstack` for the GHA runner
supervacuus Nov 15, 2024
c735270
disable the test on ASAN runs since that would require an instrumente…
supervacuus Nov 15, 2024
ca5e83a
Add changelog.
supervacuus Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
transferring to linux test machine
  • Loading branch information
supervacuus committed Nov 15, 2024
commit 07724c62ec19bcd8823ef1a9b04e0ddc282a9e2b
35 changes: 35 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,14 @@ typedef enum {
SENTRY_USER_CONSENT_REVOKED = 0,
} sentry_user_consent_t;

/**
* The crash handler strategy.
*/
typedef enum {
SENTRY_HANDLER_STRATEGY_DEFAULT = 0,
SENTRY_HANDLER_STRATEGY_CHAIN_AT_START = 1,
} sentry_handler_strategy_t;

/**
* Creates a new options struct.
* Can be freed with `sentry_options_free`.
Expand Down Expand Up @@ -1492,6 +1500,33 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_traces_sample_rate(
SENTRY_EXPERIMENTAL_API double sentry_options_get_traces_sample_rate(
sentry_options_t *opts);


#ifdef SENTRY_PLATFORM_LINUX

/**
* Returns the currently set strategy for the handler.
*
* This option does only work for the `inproc` backend on `Linux` and `Android`.
*
* The main use-case is when the Native SDK is used in the context of the CLR/Mono runtimes
* which convert some POSIX signals into managed-code exceptions and discontinue the signal chain.
*
* If this happens and we invoke the previous handler at the end (i.e., after our handler processed the signal, which is the default strategy)
* we will end up sending a native crash in addition to the managed code exception (which will either generate
* another crash-event if uncaught or could be handled in the managed code and neither terminate the application nor create a crash event).
* To correctly process the signals of CLR/Mono applications, we must invoke the runtime handler at the start of our handler.
*/
SENTRY_EXPERIMENTAL_API sentry_handler_strategy_t sentry_options_get_handler_strategy(
sentry_options_t *opts);

/**
* Sets the handler strategy.
*/
SENTRY_EXPERIMENTAL_API void sentry_options_get_handler_strategy(
sentry_options_t *opts, sentry_handler_strategy_t handler_strategy);

#endif // SENTRY_PLATFORM_LINUX

/* -- Session APIs -- */

typedef enum {
Expand Down
41 changes: 15 additions & 26 deletions src/backends/sentry_backend_inproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,6 @@
#include "transports/sentry_disk_transport.h"
#include <string.h>

/**
* Android's bionic libc seems to allocate alternate signal handler stacks for
* every thread and also references them from their internal maintenance
* structs.
*
* The way we currently set up our sigaltstack seems to interfere with this
* setup and causes crashes whenever an ART signal handler touches the thread
* that called `sentry_init()`.
*
* In addition to this problem, it also means there is no need for our own
* sigaltstack on Android since our signal handler will always be running on
* an alternate stack managed by bionic.
*
* Note: In bionic the sigaltstacks for 32-bit devices have a size of 16KiB and
* on 64-bit devices they have 32KiB. The size of our own was set to 64KiB
* independent of the device. If this is a problem, we need figure out
* together with Google if there is a way in which our configs can coexist.
*
* Both breakpad and crashpad are way more defensive in the setup of their
* signal stacks and take existing stacks into account (or reuse them).
*/
#define SIGNAL_DEF(Sig, Desc) { Sig, #Sig, Desc }

#define MAX_FRAMES 128
Expand Down Expand Up @@ -563,12 +542,20 @@ handle_ucontext(const sentry_ucontext_t *uctx)
sentry__enter_signal_handler();
#endif

sentry_value_t event = make_signal_event(sig_slot, uctx);

SENTRY_WITH_OPTIONS (options) {
sentry__write_crash_marker(options);
#ifdef SENTRY_PLATFORM_UNIX
sentry_handler_strategy_t handler_strategy = sentry_options_get_handler_strategy(options);

if (handler_strategy == SENTRY_HANDLER_STRATEGY_CHAIN_AT_START) {
// CLR/Mono convert signals provoked by "managed" native code into managed code exceptions.
// In these cases, we shouldn't react to the signal at all and let their handler discontinue the signal chain.
invoke_signal_handler(uctx->signum, uctx->siginfo, (void *)uctx->user_context);
}
#endif

sentry_value_t event = make_signal_event(sig_slot, uctx);
bool should_handle = true;
sentry__write_crash_marker(options);

if (options->on_crash_func) {
SENTRY_TRACE("invoking `on_crash` hook");
Expand Down Expand Up @@ -610,8 +597,10 @@ handle_ucontext(const sentry_ucontext_t *uctx)
// forward as we're not restoring the page allocator.
reset_signal_handlers();
sentry__leave_signal_handler();
invoke_signal_handler(
uctx->signum, uctx->siginfo, (void *)uctx->user_context);
if (handler_strategy == SENTRY_HANDLER_STRATEGY_DEFAULT) {
invoke_signal_handler(
uctx->signum, uctx->siginfo, (void *)uctx->user_context);
}
#endif
}

Expand Down
23 changes: 23 additions & 0 deletions src/sentry_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ sentry_options_new(void)
opts->shutdown_timeout = SENTRY_DEFAULT_SHUTDOWN_TIMEOUT;
opts->traces_sample_rate = 0.0;
opts->max_spans = 0;
opts->handler_strategy = SENTRY_HANDLER_STRATEGY_DEFAULT;

return opts;
}
Expand Down Expand Up @@ -594,3 +595,25 @@ sentry_options_set_backend(sentry_options_t *opts, sentry_backend_t *backend)
sentry__backend_free(opts->backend);
opts->backend = backend;
}

void
sentry_options_set_handler_strategy(sentry_options_t *opts, sentry_backend_t *backend)
{
sentry__backend_free(opts->backend);
opts->backend = backend;
}

#ifdef SENTRY_PLATFORM_LINUX

sentry_handler_strategy_t sentry_options_get_handler_strategy(
sentry_options_t *opts) {
return opts->handler_strategy;
}

void sentry_options_get_handler_strategy(
sentry_options_t *opts, sentry_handler_strategy_t handler_strategy) {
opts->handler_strategy = handler_strategy;
}

#endif // SENTRY_PLATFORM_LINUX

1 change: 1 addition & 0 deletions src/sentry_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ typedef struct sentry_options_s {
long user_consent;
long refcount;
uint64_t shutdown_timeout;
sentry_handler_strategy_t handler_strategy;
} sentry_options_t;

/**
Expand Down