From fb699b9a99f4e3a281cb75fab7efa706ed2047b9 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Tue, 1 Dec 2020 11:13:31 +0100 Subject: [PATCH 01/25] feat: Support modifying attachments after init Moves the attachments to the scope, and adds `sentry_add_attachment` and `sentry_remove_attachment` and wstr variants that modify this attachment list after calling init. Attachments are identified by their path. --- CHANGELOG.md | 6 + README.md | 2 + include/sentry.h | 46 ++++++++ src/CMakeLists.txt | 2 + src/backends/sentry_backend_crashpad.cpp | 1 + src/path/sentry_path.c | 13 +++ src/sentry_attachment.c | 136 ++++++++++++++++++++++ src/sentry_attachment.h | 54 +++++++++ src/sentry_core.c | 83 +++++++------- src/sentry_envelope.c | 4 +- src/sentry_options.c | 61 +++------- src/sentry_options.h | 20 +--- src/sentry_path.h | 5 + src/sentry_scope.c | 3 + src/sentry_scope.h | 2 + tests/unit/test_attachments.c | 138 +++++++++++++++++++++++ tests/unit/tests.inc | 2 + 17 files changed, 473 insertions(+), 105 deletions(-) create mode 100644 src/sentry_attachment.c create mode 100644 src/sentry_attachment.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a8186a3f..0c09823cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +**Features**: + +- The `sentry_add_attachment` and `sentry_remove_attachment` (and their wide-string variants) have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. + ## 0.9.0 **Breaking changes**: diff --git a/README.md b/README.md index 45426af5f..474779c16 100644 --- a/README.md +++ b/README.md @@ -363,6 +363,8 @@ Other important configuration options include: But since this process bypasses SEH, the application local exception handler is no longer invoked, which also means that for these kinds of crashes, `before_send` and `on_crash` will not be invoked before sending the minidump and thus have no effect. +- When using the crashpad backend, the list of attachments that will be sent + along with crashes is frozen at the time of `sentry_init`. ## Benchmarks diff --git a/include/sentry.h b/include/sentry.h index 6314c374c..ebb9ab6e3 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -13,6 +13,17 @@ * encoding, typically ANSI on Windows, UTF-8 macOS, and the locale encoding on * Linux; and they provide wchar-compatible alternatives on Windows which are * preferred. + * + * NOTE on attachments: + * + * Attachments are read lazily at the time of `sentry_capture_event` or at time + * of a hard crash. Relative attachment paths will be resolved according to the + * current working directory at the time of envelope creation. + * When adding and removing attachments, they are matched according to their + * given `path`. No normalization is performed. + * When using the `crashpad` backend, the list of attachments that will be added + * at the time of a hard crash will be frozen at the time of `sentry_init`, and + * later modifications will not be reflected. */ #ifndef SENTRY_H_INCLUDED @@ -1215,6 +1226,8 @@ SENTRY_API int sentry_options_get_symbolize_stacktraces( * `path` is assumed to be in platform-specific filesystem path encoding. * API Users on windows are encouraged to use `sentry_options_add_attachmentw` * instead. + * + * See the NOTE on attachments above for restrictions of this API. */ SENTRY_API void sentry_options_add_attachment( sentry_options_t *opts, const char *path); @@ -1771,6 +1784,39 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_handler_strategy( #endif // SENTRY_PLATFORM_LINUX +/** + * Adds a new attachment to be sent along. + * + * `path` is assumed to be in platform-specific filesystem path encoding. + * API Users on windows are encouraged to use `sentry_add_attachmentw` instead. + * + * See the NOTE on attachments above for restrictions of this API. + */ +SENTRY_API void sentry_add_attachment(const char *path); + +/** + * Removes a previously added attachment. + * + * `path` is assumed to be in platform-specific filesystem path encoding. + * API Users on windows are encouraged to use `sentry_remove_attachmentw` + * instead. + * + * See the NOTE on attachments above for restrictions of this API. + */ +SENTRY_API void sentry_remove_attachment(const char *path); + +#ifdef SENTRY_PLATFORM_WINDOWS +/** + * Wide char version of `sentry_add_attachment`. + */ +SENTRY_API void sentry_add_attachmentw(const wchar_t *path); + +/** + * Wide char version of `sentry_remove_attachment`. + */ +SENTRY_API void sentry_remove_attachmentw(const wchar_t *path); +#endif + /* -- Session APIs -- */ typedef enum { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 700f79753..d60bdd158 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,8 @@ sentry_target_sources_cwd(sentry sentry_alloc.c sentry_alloc.h + sentry_attachment.c + sentry_attachment.h sentry_backend.c sentry_backend.h sentry_boot.h diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index 84a7b0796..741cc9ed6 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -2,6 +2,7 @@ extern "C" { #include "sentry_boot.h" #include "sentry_alloc.h" +#include "sentry_attachment.h" #include "sentry_backend.h" #include "sentry_core.h" #include "sentry_database.h" diff --git a/src/path/sentry_path.c b/src/path/sentry_path.c index 4084a8988..9eefdf383 100644 --- a/src/path/sentry_path.c +++ b/src/path/sentry_path.c @@ -11,6 +11,19 @@ sentry__path_free(sentry_path_t *path) sentry_free(path); } +bool +sentry__path_eq(const sentry_path_t *path_a, const sentry_path_t *path_b) +{ + size_t i = 0; + while (path_a->path[i] == path_b->path[i]) { + if (path_a->path[i] == (sentry_pathchar_t)0) { + return true; + } + i++; + } + return false; +} + int sentry__path_remove_all(const sentry_path_t *path) { diff --git a/src/sentry_attachment.c b/src/sentry_attachment.c new file mode 100644 index 000000000..29242d291 --- /dev/null +++ b/src/sentry_attachment.c @@ -0,0 +1,136 @@ +#include "sentry_attachment.h" +#include "sentry_alloc.h" +#include "sentry_envelope.h" +#include "sentry_options.h" +#include "sentry_path.h" +#include "sentry_utils.h" +#include "sentry_value.h" + +#include + +static const char * +str_from_attachment_type(sentry_attachment_type_t attachment_type) +{ + switch (attachment_type) { + case ATTACHMENT: + return "event.attachment"; + case MINIDUMP: + return "event.minidump"; + case VIEW_HIERARCHY: + return "event.view_hierarchy"; + default: + UNREACHABLE("Unknown attachment type"); + return "event.attachment"; + } +} + +static void +sentry__attachment_free(sentry_attachment_t *attachment) +{ + sentry__path_free(attachment->path); + sentry_free(attachment); +} + +void +sentry__attachments_free(sentry_attachment_t *attachments) +{ + sentry_attachment_t *next_attachment = attachments; + while (next_attachment) { + sentry_attachment_t *attachment = next_attachment; + next_attachment = attachment->next; + + sentry__attachment_free(attachment); + } +} + +void +sentry__attachment_add(sentry_attachment_t **attachments_ptr, + sentry_path_t *path, sentry_attachment_type_t attachment_type, + const char *content_type) +{ + if (!path) { + return; + } + sentry_attachment_t *attachment = SENTRY_MAKE(sentry_attachment_t); + if (!attachment) { + sentry__path_free(path); + return; + } + attachment->path = path; + attachment->next = NULL; + attachment->type = attachment_type; + attachment->content_type = content_type; + + sentry_attachment_t **next_ptr = attachments_ptr; + + for (sentry_attachment_t *last_attachment = *attachments_ptr; + last_attachment; last_attachment = last_attachment->next) { + if (sentry__path_eq(last_attachment->path, path)) { + sentry__attachment_free(attachment); + return; + } + + next_ptr = &last_attachment->next; + } + + *next_ptr = attachment; +} + +void +sentry__attachment_remove( + sentry_attachment_t **attachments_ptr, sentry_path_t *path) +{ + sentry_attachment_t **next_ptr = attachments_ptr; + + for (sentry_attachment_t *attachment = *attachments_ptr; attachment; + attachment = attachment->next) { + if (sentry__path_eq(attachment->path, path)) { + *next_ptr = attachment->next; + sentry__attachment_free(attachment); + goto out; + } + + next_ptr = &attachment->next; + } + +out: + sentry__path_free(path); +} + +/** + * Reads the attachments from disk and adds them to the `envelope`. + */ +void +sentry__apply_attachments_to_envelope( + sentry_envelope_t *envelope, const sentry_attachment_t *attachments) +{ + if (!attachments) { + return; + } + + SENTRY_DEBUG("adding attachments to envelope"); + for (const sentry_attachment_t *attachment = attachments; attachment; + attachment = attachment->next) { + sentry_envelope_item_t *item = sentry__envelope_add_from_path( + envelope, attachment->path, "attachment"); + if (!item) { + continue; + } + if (attachment->type != ATTACHMENT) { // don't need to set the default + sentry__envelope_item_set_header(item, "attachment_type", + sentry_value_new_string( + str_from_attachment_type(attachment->type))); + } + if (attachment->content_type) { + sentry__envelope_item_set_header(item, "content_type", + sentry_value_new_string(attachment->content_type)); + } + sentry__envelope_item_set_header(item, "filename", +#ifdef SENTRY_PLATFORM_WINDOWS + sentry__value_new_string_from_wstr( +#else + sentry_value_new_string( +#endif + sentry__path_filename(attachment->path))); + } +} diff --git a/src/sentry_attachment.h b/src/sentry_attachment.h new file mode 100644 index 000000000..c87d4627c --- /dev/null +++ b/src/sentry_attachment.h @@ -0,0 +1,54 @@ +#ifndef SENTRY_ATTACHMENT_H_INCLUDED +#define SENTRY_ATTACHMENT_H_INCLUDED + +#include "sentry_boot.h" + +#include "sentry_envelope.h" +#include "sentry_path.h" + +/** + * The attachment_type. + */ +typedef enum { + ATTACHMENT, + MINIDUMP, + VIEW_HIERARCHY, +} sentry_attachment_type_t; + +/** + * This is a linked list of all the attachments registered via + * `sentry_options_add_attachment`. + */ +typedef struct sentry_attachment_s sentry_attachment_t; +struct sentry_attachment_s { + sentry_path_t *path; + sentry_attachment_type_t type; + const char *content_type; + sentry_attachment_t *next; +}; + +/** + * Frees the linked list of `attachments`. + */ +void sentry__attachments_free(sentry_attachment_t *attachments); + +/** + * Adds an attachment to the attachments list at `attachments_ptr`. + */ +void sentry__attachment_add(sentry_attachment_t **attachments_ptr, + sentry_path_t *path, sentry_attachment_type_t attachment_type, + const char *content_type); + +/** + * Removes an attachment from the attachments list at `attachments_ptr`. + */ +void sentry__attachment_remove( + sentry_attachment_t **attachments_ptr, sentry_path_t *path); + +/** + * Reads the attachments from disk and adds them to the `envelope`. + */ +void sentry__apply_attachments_to_envelope( + sentry_envelope_t *envelope, const sentry_attachment_t *attachments); + +#endif diff --git a/src/sentry_core.c b/src/sentry_core.c index 24d7a94bf..cf573a214 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -3,6 +3,7 @@ #include #include +#include "sentry_attachment.h" #include "sentry_backend.h" #include "sentry_core.h" #include "sentry_database.h" @@ -211,6 +212,8 @@ sentry_init(sentry_options_t *options) } sentry_value_freeze(scope->client_sdk); initialize_propagation_context(&scope->propagation_context); + scope->attachments = options->attachments; + options->attachments = NULL; } if (backend && backend->user_consent_changed_func) { backend->user_consent_changed_func(backend); @@ -545,22 +548,6 @@ static return send; } -static const char * -str_from_attachment_type(sentry_attachment_type_t attachment_type) -{ - switch (attachment_type) { - case ATTACHMENT: - return "event.attachment"; - case MINIDUMP: - return "event.minidump"; - case VIEW_HIERARCHY: - return "event.view_hierarchy"; - default: - UNREACHABLE("Unknown attachment type"); - return "event.attachment"; - } -} - sentry_envelope_t * sentry__prepare_event(const sentry_options_t *options, sentry_value_t event, sentry_uuid_t *event_id, bool invoke_before_send, @@ -604,30 +591,8 @@ sentry__prepare_event(const sentry_options_t *options, sentry_value_t event, goto fail; } - SENTRY_DEBUG("adding attachments to envelope"); - for (sentry_attachment_t *attachment = options->attachments; attachment; - attachment = attachment->next) { - sentry_envelope_item_t *item = sentry__envelope_add_from_path( - envelope, attachment->path, "attachment"); - if (!item) { - continue; - } - if (attachment->type != ATTACHMENT) { // don't need to set the default - sentry__envelope_item_set_header(item, "attachment_type", - sentry_value_new_string( - str_from_attachment_type(attachment->type))); - } - if (attachment->content_type) { - sentry__envelope_item_set_header(item, "content_type", - sentry_value_new_string(attachment->content_type)); - } - sentry__envelope_item_set_header(item, "filename", -#ifdef SENTRY_PLATFORM_WINDOWS - sentry__value_new_string_from_wstr( -#else - sentry_value_new_string( -#endif - sentry__path_filename(attachment->path))); + SENTRY_WITH_SCOPE (scope) { + sentry__apply_attachments_to_envelope(envelope, scope->attachments); } return envelope; @@ -1449,3 +1414,41 @@ sentry_capture_minidump_n(const char *path, size_t path_len) return sentry_uuid_nil(); } + +void +sentry_add_attachment(const char *path) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry__attachment_add( + &scope->attachments, sentry__path_from_str(path), ATTACHMENT, NULL); + } +} + +void +sentry_remove_attachment(const char *path) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry__attachment_remove( + &scope->attachments, sentry__path_from_str(path)); + } +} + +#ifdef SENTRY_PLATFORM_WINDOWS +void +sentry_add_attachmentw(const wchar_t *path) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry__attachment_add(&scope->attachments, + sentry__path_from_wstr(path), ATTACHMENT, NULL); + } +} + +void +sentry_remove_attachmentw(const wchar_t *path) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry__attachment_remove( + &scope->attachments, sentry__path_from_wstr(path)); + } +} +#endif diff --git a/src/sentry_envelope.c b/src/sentry_envelope.c index 137115c86..34285bdcc 100644 --- a/src/sentry_envelope.c +++ b/src/sentry_envelope.c @@ -494,7 +494,9 @@ sentry_envelope_serialize(const sentry_envelope_t *envelope, size_t *size_out) sentry__envelope_serialize_into_stringbuilder(envelope, &sb); - *size_out = sentry__stringbuilder_len(&sb); + if (size_out) { + *size_out = sentry__stringbuilder_len(&sb); + } return sentry__stringbuilder_into_string(&sb); } diff --git a/src/sentry_options.c b/src/sentry_options.c index 0bfb70b10..6eac065e7 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -1,5 +1,6 @@ #include "sentry_options.h" #include "sentry_alloc.h" +#include "sentry_attachment.h" #include "sentry_backend.h" #include "sentry_database.h" #include "sentry_logger.h" @@ -79,13 +80,6 @@ sentry__options_incref(sentry_options_t *options) return options; } -static void -attachment_free(sentry_attachment_t *attachment) -{ - sentry__path_free(attachment->path); - sentry_free(attachment); -} - void sentry_options_free(sentry_options_t *opts) { @@ -105,14 +99,7 @@ sentry_options_free(sentry_options_t *opts) sentry__path_free(opts->handler_path); sentry_transport_free(opts->transport); sentry__backend_free(opts->backend); - - sentry_attachment_t *next_attachment = opts->attachments; - while (next_attachment) { - sentry_attachment_t *attachment = next_attachment; - next_attachment = attachment->next; - - attachment_free(attachment); - } + sentry__attachments_free(opts->attachments); sentry__run_free(opts->run); sentry_free(opts); @@ -496,52 +483,35 @@ sentry_options_get_shutdown_timeout(sentry_options_t *opts) return opts->shutdown_timeout; } -static void -add_attachment(sentry_options_t *opts, sentry_path_t *path, - sentry_attachment_type_t attachment_type, const char *content_type) -{ - if (!path) { - return; - } - sentry_attachment_t *attachment = SENTRY_MAKE(sentry_attachment_t); - if (!attachment) { - sentry__path_free(path); - return; - } - attachment->path = path; - attachment->next = opts->attachments; - attachment->type = attachment_type; - attachment->content_type = content_type; - opts->attachments = attachment; -} - void sentry_options_add_attachment(sentry_options_t *opts, const char *path) { - add_attachment(opts, sentry__path_from_str(path), ATTACHMENT, NULL); + sentry__attachment_add( + &opts->attachments, sentry__path_from_str(path), ATTACHMENT, NULL); } void sentry_options_add_attachment_n( sentry_options_t *opts, const char *path, size_t path_len) { - add_attachment( - opts, sentry__path_from_str_n(path, path_len), ATTACHMENT, NULL); + sentry__attachment_add(&opts->attachments, + sentry__path_from_str_n(path, path_len), ATTACHMENT, NULL); } void sentry_options_add_view_hierarchy(sentry_options_t *opts, const char *path) { - add_attachment( - opts, sentry__path_from_str(path), VIEW_HIERARCHY, "application/json"); + sentry__attachment_add(&opts->attachments, sentry__path_from_str(path), + VIEW_HIERARCHY, "application/json"); } void sentry_options_add_view_hierarchy_n( sentry_options_t *opts, const char *path, size_t path_len) { - add_attachment(opts, sentry__path_from_str_n(path, path_len), - VIEW_HIERARCHY, "application/json"); + sentry__attachment_add(&opts->attachments, + sentry__path_from_str_n(path, path_len), VIEW_HIERARCHY, + "application/json"); } void @@ -585,8 +555,8 @@ void sentry_options_add_attachmentw_n( sentry_options_t *opts, const wchar_t *path, size_t path_len) { - add_attachment( - opts, sentry__path_from_wstr_n(path, path_len), ATTACHMENT, NULL); + sentry__attachment_add(&opts->attachments, + sentry__path_from_wstr_n(path, path_len), ATTACHMENT, NULL); } void @@ -606,8 +576,9 @@ void sentry_options_add_view_hierarchyw_n( sentry_options_t *opts, const wchar_t *path, size_t path_len) { - add_attachment(opts, sentry__path_from_wstr_n(path, path_len), - VIEW_HIERARCHY, "application/json"); + sentry__attachment_add(&opts->attachments, + sentry__path_from_wstr_n(path, path_len), VIEW_HIERARCHY, + "application/json"); } void diff --git a/src/sentry_options.h b/src/sentry_options.h index 0185bc67c..5316b69e5 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -3,6 +3,7 @@ #include "sentry_boot.h" +#include "sentry_attachment.h" #include "sentry_database.h" #include "sentry_logger.h" #include "sentry_session.h" @@ -13,25 +14,6 @@ #define SENTRY_DEFAULT_SHUTDOWN_TIMEOUT 2000 struct sentry_backend_s; -/** - * The attachment_type. - */ -typedef enum { - ATTACHMENT, - MINIDUMP, - VIEW_HIERARCHY, -} sentry_attachment_type_t; -/** - * This is a linked list of all the attachments registered via - * `sentry_options_add_attachment`. - */ -typedef struct sentry_attachment_s sentry_attachment_t; -struct sentry_attachment_s { - sentry_path_t *path; - sentry_attachment_type_t type; - const char *content_type; - sentry_attachment_t *next; -}; /** * This is the main options struct, which is being accessed throughout all of diff --git a/src/sentry_path.h b/src/sentry_path.h index 9cd72dc32..5a6cdea4f 100644 --- a/src/sentry_path.h +++ b/src/sentry_path.h @@ -94,6 +94,11 @@ void sentry__path_free(sentry_path_t *path); */ const sentry_pathchar_t *sentry__path_filename(const sentry_path_t *path); +/** + * Returns whether the two paths are equal. + */ +bool sentry__path_eq(const sentry_path_t *path_a, const sentry_path_t *path_b); + /** * Returns whether the last path segment matches `filename`. */ diff --git a/src/sentry_scope.c b/src/sentry_scope.c index 7109cd984..fb8c83569 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -1,5 +1,6 @@ #include "sentry_scope.h" #include "sentry_alloc.h" +#include "sentry_attachment.h" #include "sentry_backend.h" #include "sentry_core.h" #include "sentry_database.h" @@ -77,6 +78,7 @@ init_scope(sentry_scope_t *scope) scope->breadcrumbs = sentry_value_new_list(); scope->level = SENTRY_LEVEL_ERROR; scope->client_sdk = sentry_value_new_null(); + scope->attachments = NULL; scope->transaction_object = NULL; scope->span = NULL; } @@ -109,6 +111,7 @@ cleanup_scope(sentry_scope_t *scope) sentry_value_decref(scope->propagation_context); sentry_value_decref(scope->breadcrumbs); sentry_value_decref(scope->client_sdk); + sentry__attachments_free(scope->attachments); sentry__transaction_decref(scope->transaction_object); sentry__span_decref(scope->span); } diff --git a/src/sentry_scope.h b/src/sentry_scope.h index eaf7eb37d..e9d248c48 100644 --- a/src/sentry_scope.h +++ b/src/sentry_scope.h @@ -3,6 +3,7 @@ #include "sentry_boot.h" +#include "sentry_attachment.h" #include "sentry_session.h" #include "sentry_value.h" @@ -20,6 +21,7 @@ struct sentry_scope_s { sentry_value_t breadcrumbs; sentry_level_t level; sentry_value_t client_sdk; + sentry_attachment_t *attachments; // The span attached to this scope, if any. // diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index 3c2ddbef2..09e5b791f 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -1,5 +1,7 @@ +#include "sentry_attachment.h" #include "sentry_envelope.h" #include "sentry_path.h" +#include "sentry_scope.h" #include "sentry_string.h" #include "sentry_testsupport.h" @@ -88,3 +90,139 @@ SENTRY_TEST(lazy_attachments) TEST_CHECK_INT_EQUAL(testdata.called, 2); } + +SENTRY_TEST(attachments_add_dedupe) +{ + sentry_options_t *options = sentry_options_new(); + sentry_options_add_attachment(options, SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_options_add_attachment(options, SENTRY_TEST_PATH_PREFIX ".b.txt"); + + sentry_init(options); + + sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".b.txt"); + sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); +#ifdef SENTRY_PLATFORM_WINDOWS + sentry_add_attachmentw(L".a.txt"); + sentry_add_attachmentw(L".b.txt"); + sentry_add_attachmentw(L".c.txt"); +#endif + + sentry_path_t *path_a + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_path_t *path_b + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".b.txt"); + sentry_path_t *path_c + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".c.txt"); + + sentry__path_write_buffer(path_a, "aaa", 3); + sentry__path_write_buffer(path_b, "bbb", 3); + sentry__path_write_buffer(path_c, "ccc", 3); + + sentry_envelope_t *envelope = sentry__envelope_new(); + SENTRY_WITH_SCOPE (scope) { + sentry__apply_attachments_to_envelope(envelope, scope->attachments); + } + char *serialized = sentry_envelope_serialize(envelope, NULL); + sentry_envelope_free(envelope); + + TEST_CHECK_STRING_EQUAL(serialized, + "{}\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".a.txt\"}\naaa\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".b.txt\"}\nbbb\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".c.txt\"}" + "\nccc"); + + sentry_free(serialized); + + sentry_shutdown(); + + sentry__path_remove(path_a); + sentry__path_remove(path_b); + sentry__path_remove(path_c); + + sentry__path_free(path_a); + sentry__path_free(path_b); + sentry__path_free(path_c); +} + +SENTRY_TEST(attachments_add_remove) +{ + sentry_options_t *options = sentry_options_new(); + sentry_options_add_attachment(options, SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_options_add_attachment(options, SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_options_add_attachment(options, SENTRY_TEST_PATH_PREFIX ".b.txt"); + + sentry_init(options); + + sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".d.txt"); +#ifdef SENTRY_PLATFORM_WINDOWS + sentry_add_attachmentw(L".e.txt"); + sentry_add_attachmentw(L".d.txt"); +#endif + + sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".d.txt"); +#ifdef SENTRY_PLATFORM_WINDOWS + sentry_remove_attachmentw(L".e.txt"); + sentry_remove_attachmentw(L".d.txt"); +#endif + + sentry_path_t *path_a + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_path_t *path_b + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".b.txt"); + sentry_path_t *path_c + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".c.txt"); + + sentry__path_write_buffer(path_a, "aaa", 3); + sentry__path_write_buffer(path_b, "bbb", 3); + sentry__path_write_buffer(path_c, "ccc", 3); + + sentry_envelope_t *envelope; + char *serialized; + + envelope = sentry__envelope_new(); + SENTRY_WITH_SCOPE (scope) { + sentry__apply_attachments_to_envelope(envelope, scope->attachments); + } + serialized = sentry_envelope_serialize(envelope, NULL); + sentry_envelope_free(envelope); + + TEST_CHECK_STRING_EQUAL(serialized, + "{}\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".a.txt\"}\naaa\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".b.txt\"}" + "\nbbb"); + + sentry_free(serialized); + + sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".b.txt"); +#ifdef SENTRY_PLATFORM_WINDOWS + sentry_remove_attachmentw(L".b.txt"); + sentry_remove_attachmentw(L".a.txt"); +#endif + + envelope = sentry__envelope_new(); + SENTRY_WITH_SCOPE (scope) { + sentry__apply_attachments_to_envelope(envelope, scope->attachments); + } + serialized = sentry_envelope_serialize(envelope, NULL); + sentry_envelope_free(envelope); + + TEST_CHECK_STRING_EQUAL(serialized, "{}"); + + sentry_free(serialized); + + sentry_shutdown(); + + sentry__path_remove(path_a); + sentry__path_remove(path_b); + sentry__path_remove(path_c); + + sentry__path_free(path_a); + sentry__path_free(path_b); + sentry__path_free(path_c); +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 048f554c5..99b4d45c4 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -1,6 +1,8 @@ XX(assert_sdk_name) XX(assert_sdk_user_agent) XX(assert_sdk_version) +XX(attachments_add_dedupe) +XX(attachments_add_remove) XX(background_worker) XX(basic_consent_tracking) XX(basic_function_transport) From 72341ece4f6b9b29be3bbb0d351eb67fc80e045a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 30 Apr 2025 16:32:38 +0200 Subject: [PATCH 02/25] feat: pass added and removed attachments to the backend --- external/crashpad | 2 +- src/backends/sentry_backend_crashpad.cpp | 28 +++++++++++++++++ src/sentry_backend.h | 2 ++ src/sentry_core.c | 38 +++++++++++++++++++----- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/external/crashpad b/external/crashpad index b2653919b..b97109c0c 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit b2653919b42cf310482a9e33620cf82e952b5d2d +Subproject commit b97109c0cbda479d2f3e21419466b0228ce38e08 diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index 741cc9ed6..6fca20c4b 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -661,6 +661,30 @@ crashpad_backend_prune_database(sentry_backend_t *backend) crashpad::PruneCrashReportDatabase(data->db, &condition); } +#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) +static void +crashpad_backend_add_attachment( + sentry_backend_t *backend, const sentry_path_t *attachment) +{ + auto *data = static_cast(backend->data); + if (!data->client) { + return; + } + data->client->AddAttachment(base::FilePath(attachment->path)); +} + +static void +crashpad_backend_remove_attachment( + sentry_backend_t *backend, const sentry_path_t *attachment) +{ + auto *data = static_cast(backend->data); + if (!data->client) { + return; + } + data->client->RemoveAttachment(base::FilePath(attachment->path)); +} +#endif + sentry_backend_t * sentry__backend_new(void) { @@ -688,6 +712,10 @@ sentry__backend_new(void) backend->user_consent_changed_func = crashpad_backend_user_consent_changed; backend->get_last_crash_func = crashpad_backend_last_crash; backend->prune_database_func = crashpad_backend_prune_database; +#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) + backend->add_attachment_func = crashpad_backend_add_attachment; + backend->remove_attachment_func = crashpad_backend_remove_attachment; +#endif backend->data = data; backend->can_capture_after_shutdown = true; diff --git a/src/sentry_backend.h b/src/sentry_backend.h index e3c96b0f5..14e96afcc 100644 --- a/src/sentry_backend.h +++ b/src/sentry_backend.h @@ -25,6 +25,8 @@ struct sentry_backend_s { void (*user_consent_changed_func)(sentry_backend_t *); uint64_t (*get_last_crash_func)(sentry_backend_t *); void (*prune_database_func)(sentry_backend_t *); + void (*add_attachment_func)(sentry_backend_t *, const sentry_path_t *); + void (*remove_attachment_func)(sentry_backend_t *, const sentry_path_t *); void *data; // Whether this backend still runs after shutdown_func was called. bool can_capture_after_shutdown; diff --git a/src/sentry_core.c b/src/sentry_core.c index cf573a214..662a64a59 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1418,18 +1418,30 @@ sentry_capture_minidump_n(const char *path, size_t path_len) void sentry_add_attachment(const char *path) { + sentry_path_t *attachment = sentry__path_from_str(path); + SENTRY_WITH_OPTIONS (options) { + if (options->backend && options->backend->add_attachment_func) { + options->backend->add_attachment_func(options->backend, attachment); + } + } SENTRY_WITH_SCOPE_MUT (scope) { sentry__attachment_add( - &scope->attachments, sentry__path_from_str(path), ATTACHMENT, NULL); + &scope->attachments, attachment, ATTACHMENT, NULL); } } void sentry_remove_attachment(const char *path) { + sentry_path_t *attachment = sentry__path_from_str(path); + SENTRY_WITH_OPTIONS (options) { + if (options->backend && options->backend->remove_attachment_func) { + options->backend->remove_attachment_func( + options->backend, attachment); + } + } SENTRY_WITH_SCOPE_MUT (scope) { - sentry__attachment_remove( - &scope->attachments, sentry__path_from_str(path)); + sentry__attachment_remove(&scope->attachments, attachment); } } @@ -1437,18 +1449,30 @@ sentry_remove_attachment(const char *path) void sentry_add_attachmentw(const wchar_t *path) { + sentry_path_t *attachment = sentry__path_from_wstr(path); + SENTRY_WITH_OPTIONS (options) { + if (options->backend && options->backend->add_attachment_func) { + options->backend->add_attachment_func(options->backend, attachment); + } + } SENTRY_WITH_SCOPE_MUT (scope) { - sentry__attachment_add(&scope->attachments, - sentry__path_from_wstr(path), ATTACHMENT, NULL); + sentry__attachment_add( + &scope->attachments, attachment, ATTACHMENT, NULL); } } void sentry_remove_attachmentw(const wchar_t *path) { + sentry_path_t *attachment = sentry__path_from_wstr(path); + SENTRY_WITH_OPTIONS (options) { + if (options->backend && options->backend->remove_attachment_func) { + options->backend->remove_attachment_func( + options->backend, attachment); + } + } SENTRY_WITH_SCOPE_MUT (scope) { - sentry__attachment_remove( - &scope->attachments, sentry__path_from_wstr(path)); + sentry__attachment_remove(&scope->attachments, attachment); } } #endif From 9a317be468032471c7b8445b5bf08e89ecde6870 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 5 Jun 2025 13:02:08 +0200 Subject: [PATCH 03/25] add `_n` --- include/sentry.h | 5 +++++ src/sentry_core.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index ebb9ab6e3..cb73cf462 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -1793,6 +1793,7 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_handler_strategy( * See the NOTE on attachments above for restrictions of this API. */ SENTRY_API void sentry_add_attachment(const char *path); +SENTRY_API void sentry_add_attachment_n(const char *path, size_t path_len); /** * Removes a previously added attachment. @@ -1804,17 +1805,21 @@ SENTRY_API void sentry_add_attachment(const char *path); * See the NOTE on attachments above for restrictions of this API. */ SENTRY_API void sentry_remove_attachment(const char *path); +SENTRY_API void sentry_remove_attachment_n(const char *path, size_t path_len); #ifdef SENTRY_PLATFORM_WINDOWS /** * Wide char version of `sentry_add_attachment`. */ SENTRY_API void sentry_add_attachmentw(const wchar_t *path); +SENTRY_API void sentry_add_attachmentw_n(const wchar_t *path, size_t path_len); /** * Wide char version of `sentry_remove_attachment`. */ SENTRY_API void sentry_remove_attachmentw(const wchar_t *path); +SENTRY_API void sentry_remove_attachmentw_n( + const wchar_t *path, size_t path_len); #endif /* -- Session APIs -- */ diff --git a/src/sentry_core.c b/src/sentry_core.c index 662a64a59..aa74673ec 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1418,7 +1418,13 @@ sentry_capture_minidump_n(const char *path, size_t path_len) void sentry_add_attachment(const char *path) { - sentry_path_t *attachment = sentry__path_from_str(path); + sentry_add_attachment_n(path, sentry__guarded_strlen(path)); +} + +void +sentry_add_attachment_n(const char *path, size_t path_len) +{ + sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); SENTRY_WITH_OPTIONS (options) { if (options->backend && options->backend->add_attachment_func) { options->backend->add_attachment_func(options->backend, attachment); @@ -1433,7 +1439,13 @@ sentry_add_attachment(const char *path) void sentry_remove_attachment(const char *path) { - sentry_path_t *attachment = sentry__path_from_str(path); + sentry_remove_attachment_n(path, sentry__guarded_strlen(path)); +} + +void +sentry_remove_attachment_n(const char *path, size_t path_len) +{ + sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); SENTRY_WITH_OPTIONS (options) { if (options->backend && options->backend->remove_attachment_func) { options->backend->remove_attachment_func( @@ -1449,7 +1461,14 @@ sentry_remove_attachment(const char *path) void sentry_add_attachmentw(const wchar_t *path) { - sentry_path_t *attachment = sentry__path_from_wstr(path); + size_t path_len = path ? wcslen(path) : 0; + sentry_add_attachmentw_n(path, path_len); +} + +void +sentry_add_attachmentw_n(const wchar_t *path, size_t path_len) +{ + sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); SENTRY_WITH_OPTIONS (options) { if (options->backend && options->backend->add_attachment_func) { options->backend->add_attachment_func(options->backend, attachment); @@ -1464,7 +1483,14 @@ sentry_add_attachmentw(const wchar_t *path) void sentry_remove_attachmentw(const wchar_t *path) { - sentry_path_t *attachment = sentry__path_from_wstr(path); + size_t path_len = path ? wcslen(path) : 0; + sentry_remove_attachmentw_n(path, path_len); +} + +void +sentry_remove_attachmentw_n(const wchar_t *path, size_t path_len) +{ + sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); SENTRY_WITH_OPTIONS (options) { if (options->backend && options->backend->remove_attachment_func) { options->backend->remove_attachment_func( From 5ca524daa8af1515fb610f84bf4888e1798a6c1a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 5 Jun 2025 13:36:15 +0200 Subject: [PATCH 04/25] scope api --- include/sentry.h | 8 ++++++++ src/sentry_scope.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/sentry.h b/include/sentry.h index cb73cf462..93c2ef981 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -1794,6 +1794,10 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_handler_strategy( */ SENTRY_API void sentry_add_attachment(const char *path); SENTRY_API void sentry_add_attachment_n(const char *path, size_t path_len); +SENTRY_API void sentry_scope_add_attachment( + sentry_scope_t *scope, const char *path); +SENTRY_API void sentry_scope_add_attachment_n( + sentry_scope_t *scope, const char *path, size_t path_len); /** * Removes a previously added attachment. @@ -1813,6 +1817,10 @@ SENTRY_API void sentry_remove_attachment_n(const char *path, size_t path_len); */ SENTRY_API void sentry_add_attachmentw(const wchar_t *path); SENTRY_API void sentry_add_attachmentw_n(const wchar_t *path, size_t path_len); +SENTRY_API void sentry_scope_add_attachmentw( + sentry_scope_t *scope, const wchar_t *path); +SENTRY_API void sentry_scope_add_attachmentw_n( + sentry_scope_t *scope, const wchar_t *path, size_t path_len); /** * Wide char version of `sentry_remove_attachment`. diff --git a/src/sentry_scope.c b/src/sentry_scope.c index fb8c83569..04cdb64b2 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -672,3 +672,34 @@ sentry_scope_set_level(sentry_scope_t *scope, sentry_level_t level) { scope->level = level; } + +void +sentry_scope_add_attachment(sentry_scope_t *scope, const char *path) +{ + sentry_scope_add_attachment_n(scope, path, sentry__guarded_strlen(path)); +} + +void +sentry_scope_add_attachment_n( + sentry_scope_t *scope, const char *path, size_t path_len) +{ + sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); + sentry__attachment_add(&scope->attachments, attachment, ATTACHMENT, NULL); +} + +#ifdef SENTRY_PLATFORM_WINDOWS +void +sentry_scope_add_attachmentw(sentry_scope_t *scope, const wchar_t *path) +{ + size_t path_len = path ? wcslen(path) : 0; + sentry_scope_add_attachmentw_n(scope, path, path_len); +} + +void +sentry_scope_add_attachmentw_n( + sentry_scope_t *scope, const wchar_t *path, size_t path_len) +{ + sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); + sentry__attachment_add(&scope->attachments, attachment, ATTACHMENT, NULL); +} +#endif From 9569d042857f549084e4d1d792cb7ff15e55c242 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 5 Jun 2025 15:39:07 +0200 Subject: [PATCH 05/25] merge & apply attachments --- src/sentry_attachment.c | 19 +++++++ src/sentry_attachment.h | 7 +++ src/sentry_core.c | 15 +++++- tests/unit/test_attachments.c | 99 +++++++++++++++++++++++++++++++++++ tests/unit/tests.inc | 1 + 5 files changed, 140 insertions(+), 1 deletion(-) diff --git a/src/sentry_attachment.c b/src/sentry_attachment.c index 29242d291..8783dd0a4 100644 --- a/src/sentry_attachment.c +++ b/src/sentry_attachment.c @@ -27,6 +27,9 @@ str_from_attachment_type(sentry_attachment_type_t attachment_type) static void sentry__attachment_free(sentry_attachment_t *attachment) { + if (!attachment) { + return; + } sentry__path_free(attachment->path); sentry_free(attachment); } @@ -134,3 +137,19 @@ sentry__apply_attachments_to_envelope( sentry__path_filename(attachment->path))); } } + +void +sentry__attachments_extend( + sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachments) +{ + if (!attachments) { + return; + } + + for (sentry_attachment_t *attachment = attachments; attachment; + attachment = attachment->next) { + sentry__attachment_add(attachments_ptr, + sentry__path_clone(attachment->path), attachment->type, + attachment->content_type); + } +} diff --git a/src/sentry_attachment.h b/src/sentry_attachment.h index c87d4627c..b3188cd4b 100644 --- a/src/sentry_attachment.h +++ b/src/sentry_attachment.h @@ -51,4 +51,11 @@ void sentry__attachment_remove( void sentry__apply_attachments_to_envelope( sentry_envelope_t *envelope, const sentry_attachment_t *attachments); +/** + * Extends the linked list of attachments at `attachments_ptr` with all + * attachments in `attachments`. + */ +void sentry__attachments_extend( + sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachments); + #endif diff --git a/src/sentry_core.c b/src/sentry_core.c index aa74673ec..541d06ae9 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -559,10 +559,12 @@ sentry__prepare_event(const sentry_options_t *options, sentry_value_t event, sentry__record_errors_on_current_session(1); } + sentry_attachment_t *all_attachments = NULL; if (local_scope) { SENTRY_DEBUG("merging local scope into event"); sentry_scope_mode_t mode = SENTRY_SCOPE_BREADCRUMBS; sentry__scope_apply_to_event(local_scope, options, event, mode); + sentry__attachments_extend(&all_attachments, local_scope->attachments); sentry__scope_free(local_scope); } @@ -572,6 +574,9 @@ sentry__prepare_event(const sentry_options_t *options, sentry_value_t event, if (!options->symbolize_stacktraces) { mode &= ~SENTRY_SCOPE_STACKTRACES; } + if (all_attachments) { + sentry__attachments_extend(&all_attachments, scope->attachments); + } sentry__scope_apply_to_event(scope, options, event, mode); } @@ -592,9 +597,17 @@ sentry__prepare_event(const sentry_options_t *options, sentry_value_t event, } SENTRY_WITH_SCOPE (scope) { - sentry__apply_attachments_to_envelope(envelope, scope->attachments); + if (all_attachments) { + // all attachments merged from multiple scopes + sentry__apply_attachments_to_envelope(envelope, all_attachments); + } else { + // only global scope has attachments + sentry__apply_attachments_to_envelope(envelope, scope->attachments); + } } + sentry__attachments_free(all_attachments); + return envelope; fail: diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index 09e5b791f..fe69ed432 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -226,3 +226,102 @@ SENTRY_TEST(attachments_add_remove) sentry__path_free(path_b); sentry__path_free(path_c); } + +SENTRY_TEST(attachments_extend) +{ + SENTRY_TEST_OPTIONS_NEW(options); + sentry_init(options); + + sentry_path_t *path_a + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_path_t *path_b + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".b.txt"); + sentry_path_t *path_c + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_path_t *path_d + = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".d.txt"); + + sentry__path_write_buffer(path_a, "aaa", 3); + sentry__path_write_buffer(path_b, "bbb", 3); + sentry__path_write_buffer(path_c, "ccc", 3); + sentry__path_write_buffer(path_d, "ddd", 3); + + sentry_attachment_t *attachments_abc = NULL; + sentry__attachment_add( + &attachments_abc, sentry__path_clone(path_a), ATTACHMENT, NULL); + sentry__attachment_add( + &attachments_abc, sentry__path_clone(path_b), ATTACHMENT, NULL); + sentry__attachment_add( + &attachments_abc, sentry__path_clone(path_c), ATTACHMENT, NULL); + + sentry_attachment_t *attachments_bcd = NULL; + sentry__attachment_add( + &attachments_bcd, sentry__path_clone(path_b), ATTACHMENT, NULL); + sentry__attachment_add( + &attachments_bcd, sentry__path_clone(path_c), ATTACHMENT, NULL); + sentry__attachment_add( + &attachments_bcd, sentry__path_clone(path_d), ATTACHMENT, NULL); + + sentry_attachment_t *all_attachments = NULL; + sentry__attachments_extend(&all_attachments, attachments_abc); + TEST_CHECK(all_attachments != NULL); + + SENTRY_WITH_SCOPE (scope) { + sentry_envelope_t *envelope = sentry__envelope_new(); + sentry__apply_attachments_to_envelope(envelope, all_attachments); + + char *serialized = sentry_envelope_serialize(envelope, NULL); + + TEST_CHECK_STRING_EQUAL(serialized, + "{}\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".a.txt\"}" + "\naaa\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".b.txt\"}" + "\nbbb\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".c.txt\"}" + "\nccc"); + + sentry_free(serialized); + sentry_envelope_free(envelope); + } + + sentry__attachments_extend(&all_attachments, attachments_bcd); + TEST_CHECK(all_attachments != NULL); + + SENTRY_WITH_SCOPE (scope) { + sentry_envelope_t *envelope = sentry__envelope_new(); + sentry__apply_attachments_to_envelope(envelope, all_attachments); + + char *serialized = sentry_envelope_serialize(envelope, NULL); + + TEST_CHECK_STRING_EQUAL(serialized, + "{}\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".a.txt\"}" + "\naaa\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".b.txt\"}" + "\nbbb\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".c.txt\"}" + "\nccc\n" + "{\"type\":\"attachment\",\"length\":3,\"filename\":\".d.txt\"}" + "\nddd"); + + sentry_free(serialized); + sentry_envelope_free(envelope); + } + + sentry_close(); + + sentry__attachments_free(attachments_abc); + sentry__attachments_free(attachments_bcd); + sentry__attachments_free(all_attachments); + + sentry__path_remove(path_a); + sentry__path_remove(path_b); + sentry__path_remove(path_c); + sentry__path_remove(path_d); + + sentry__path_free(path_a); + sentry__path_free(path_b); + sentry__path_free(path_c); + sentry__path_free(path_d); +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 99b4d45c4..9ca44d8ad 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -3,6 +3,7 @@ XX(assert_sdk_user_agent) XX(assert_sdk_version) XX(attachments_add_dedupe) XX(attachments_add_remove) +XX(attachments_extend) XX(background_worker) XX(basic_consent_tracking) XX(basic_function_transport) From 9c99b5d39614c0be89493ab1eef68c146f1cf8dd Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 5 Jun 2025 15:43:03 +0200 Subject: [PATCH 06/25] update note on attachments --- include/sentry.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index 93c2ef981..387488319 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -21,9 +21,9 @@ * current working directory at the time of envelope creation. * When adding and removing attachments, they are matched according to their * given `path`. No normalization is performed. - * When using the `crashpad` backend, the list of attachments that will be added - * at the time of a hard crash will be frozen at the time of `sentry_init`, and - * later modifications will not be reflected. + * When using the `crashpad` backend on macOS, the list of attachments that will + * be added at the time of a hard crash will be frozen at the time of + * `sentry_init`, and later modifications will not be reflected. */ #ifndef SENTRY_H_INCLUDED From 30cf86761ed2960b053365a7b43df0ccb49f76e4 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 5 Jun 2025 16:46:29 +0200 Subject: [PATCH 07/25] integration tests --- CONTRIBUTING.md | 2 ++ examples/example.c | 12 ++++++++++++ tests/test_integration_crashpad.py | 17 ++++++++++++----- tests/test_integration_http.py | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 805fbc233..43d63d5be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,6 +155,7 @@ The example currently supports the following commands: instead of a hardcoded value. - `attachment`: Adds an attachment, which is currently defined as the `CMakeCache.txt` file, which is part of the CMake build folder. +- `attach-after-init`: Same as `attachment` but after the SDK has been initialized. - `stdout`: Uses a custom transport which dumps all envelopes to `stdout`. - `no-setup`: Skips all scope and breadcrumb initialization code. - `start-session`: Starts a new release-health session. @@ -185,6 +186,7 @@ The example currently supports the following commands: This file can be found in `./tests/fixtures/view-hierachy.json`. - `set-trace`: Sets the scope `propagation_context`'s trace data to the given `trace_id="aaaabbbbccccddddeeeeffff00001111"` and `parent_span_id=""f0f0f0f0f0f0f0f0"`. - `capture-with-scope`: Captures an event with a local scope. +- `attach-to-scope`: Same as `attachment` but attaches the file to the local scope. Only on Linux using crashpad: - `crashpad-wait-for-upload`: Couples application shutdown to complete the upload in the `crashpad_handler`. diff --git a/examples/example.c b/examples/example.c index b6897cfaf..275e92eaa 100644 --- a/examples/example.c +++ b/examples/example.c @@ -399,6 +399,12 @@ main(int argc, char **argv) sentry_set_trace(direct_trace_id, direct_parent_span_id); } + if (has_arg(argc, argv, "attach-after-init")) { + // assuming the example / test is run directly from the cmake build + // directory + sentry_add_attachment("./CMakeCache.txt"); + } + if (has_arg(argc, argv, "start-session")) { sentry_start_session(); } @@ -424,6 +430,12 @@ main(int argc, char **argv) sentry_value_t debug_crumb = create_debug_crumb("scoped crumb"); sentry_scope_add_breadcrumb(scope, debug_crumb); + if (has_arg(argc, argv, "attach-to-scope")) { + // assuming the example / test is run directly from the cmake build + // directory + sentry_scope_add_attachment(scope, "./CMakeCache.txt"); + } + sentry_capture_event_with_scope(event, scope); } diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index d1e0cacf0..2ef6ef4ec 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -289,11 +289,11 @@ def test_crashpad_wer_crash(cmake, httpserver, run_args): "run_args,build_args", [ # if we crash, we want a dump - ([], {"SENTRY_TRANSPORT_COMPRESSION": "Off"}), - ([], {"SENTRY_TRANSPORT_COMPRESSION": "On"}), + (["attachment"], {"SENTRY_TRANSPORT_COMPRESSION": "Off"}), + (["attachment"], {"SENTRY_TRANSPORT_COMPRESSION": "On"}), # if we crash and before-send doesn't discard, we want a dump pytest.param( - ["before-send"], + ["attachment", "before-send"], {}, marks=pytest.mark.skipif( sys.platform == "darwin", @@ -302,13 +302,21 @@ def test_crashpad_wer_crash(cmake, httpserver, run_args): ), # if on_crash() is non-discarding, a discarding before_send() is overruled, so we get a dump pytest.param( - ["discarding-before-send", "on-crash"], + ["attachment", "discarding-before-send", "on-crash"], {}, marks=pytest.mark.skipif( sys.platform == "darwin", reason="crashpad doesn't provide SetFirstChanceExceptionHandler on macOS", ), ), + pytest.param( + ["attach-after-init"], + {}, + marks=pytest.mark.skipif( + sys.platform == "darwin", + reason="crashpad doesn't support dynamic attachments on macOS", + ), + ), ], ) def test_crashpad_dumping_crash(cmake, httpserver, run_args, build_args): @@ -329,7 +337,6 @@ def test_crashpad_dumping_crash(cmake, httpserver, run_args, build_args): [ "log", "start-session", - "attachment", "attach-view-hierarchy", "overflow-breadcrumbs", "crash", diff --git a/tests/test_integration_http.py b/tests/test_integration_http.py index cea0f1940..146d14ec7 100644 --- a/tests/test_integration_http.py +++ b/tests/test_integration_http.py @@ -1173,7 +1173,7 @@ def test_capture_with_scope(cmake, httpserver): run( tmp_path, "sentry_example", - ["log", "attachment", "capture-with-scope"], + ["log", "attach-to-scope", "capture-with-scope"], check=True, env=dict(os.environ, SENTRY_DSN=make_dsn(httpserver)), ) From 55336fcf98e603ccbf3450fa3c36bab695a5f23a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 5 Jun 2025 17:01:14 +0200 Subject: [PATCH 08/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 474779c16..f0a2c9028 100644 --- a/README.md +++ b/README.md @@ -363,7 +363,7 @@ Other important configuration options include: But since this process bypasses SEH, the application local exception handler is no longer invoked, which also means that for these kinds of crashes, `before_send` and `on_crash` will not be invoked before sending the minidump and thus have no effect. -- When using the crashpad backend, the list of attachments that will be sent +- When using the crashpad backend on macOS, the list of attachments that will be sent along with crashes is frozen at the time of `sentry_init`. ## Benchmarks From 32a6aeac466232f6d55802538cc94db47e664122 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 5 Jun 2025 17:05:10 +0200 Subject: [PATCH 09/25] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c09823cd..4efba843f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ **Features**: -- The `sentry_add_attachment` and `sentry_remove_attachment` (and their wide-string variants) have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. +- The `sentry_add_attachment`, `sentry_scope_add_attachment`, and `sentry_remove_attachment` (and their wide-string variants) have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. ([#1266](https://github.com/getsentry/sentry-native/pull/1266)) ## 0.9.0 From 09c9dc4e68ad010e798f59cb12e96598ae6a15ce Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 11 Jun 2025 12:12:44 +0200 Subject: [PATCH 10/25] Apply suggestions from code review Co-authored-by: Mischan Toosarani-Hausberger --- src/backends/sentry_backend_crashpad.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index 6fca20c4b..a0e9b8c1b 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -667,7 +667,8 @@ crashpad_backend_add_attachment( sentry_backend_t *backend, const sentry_path_t *attachment) { auto *data = static_cast(backend->data); - if (!data->client) { + if (!data || !data->client) { +``` return; } data->client->AddAttachment(base::FilePath(attachment->path)); @@ -678,7 +679,7 @@ crashpad_backend_remove_attachment( sentry_backend_t *backend, const sentry_path_t *attachment) { auto *data = static_cast(backend->data); - if (!data->client) { + if (!data || !data->client) { return; } data->client->RemoveAttachment(base::FilePath(attachment->path)); From 7200e7869a7d7040e5f0408e6fbafb8ed6280be8 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 11 Jun 2025 12:14:51 +0200 Subject: [PATCH 11/25] remove ticks --- src/backends/sentry_backend_crashpad.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index a0e9b8c1b..81d2d930d 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -668,7 +668,6 @@ crashpad_backend_add_attachment( { auto *data = static_cast(backend->data); if (!data || !data->client) { -``` return; } data->client->AddAttachment(base::FilePath(attachment->path)); From 939a918211ebef543de656ac7f74cadd48fc6737 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 11 Jun 2025 12:18:33 +0200 Subject: [PATCH 12/25] Apply more suggestions from code review --- src/sentry_attachment.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/sentry_attachment.c b/src/sentry_attachment.c index 8783dd0a4..eaf337b1f 100644 --- a/src/sentry_attachment.c +++ b/src/sentry_attachment.c @@ -25,7 +25,7 @@ str_from_attachment_type(sentry_attachment_type_t attachment_type) } static void -sentry__attachment_free(sentry_attachment_t *attachment) +attachment_free(sentry_attachment_t *attachment) { if (!attachment) { return; @@ -42,7 +42,7 @@ sentry__attachments_free(sentry_attachment_t *attachments) sentry_attachment_t *attachment = next_attachment; next_attachment = attachment->next; - sentry__attachment_free(attachment); + attachment_free(attachment); } } @@ -69,7 +69,7 @@ sentry__attachment_add(sentry_attachment_t **attachments_ptr, for (sentry_attachment_t *last_attachment = *attachments_ptr; last_attachment; last_attachment = last_attachment->next) { if (sentry__path_eq(last_attachment->path, path)) { - sentry__attachment_free(attachment); + attachment_free(attachment); return; } @@ -89,7 +89,7 @@ sentry__attachment_remove( attachment = attachment->next) { if (sentry__path_eq(attachment->path, path)) { *next_ptr = attachment->next; - sentry__attachment_free(attachment); + attachment_free(attachment); goto out; } @@ -100,9 +100,6 @@ sentry__attachment_remove( sentry__path_free(path); } -/** - * Reads the attachments from disk and adds them to the `envelope`. - */ void sentry__apply_attachments_to_envelope( sentry_envelope_t *envelope, const sentry_attachment_t *attachments) From 12c7b561784074e975968b06cc58b8fa8b0214ef Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 11 Jun 2025 13:45:05 +0200 Subject: [PATCH 13/25] De-duplicate envelope attachment code - remove sentry__apply_attachments_to_envelope - add sentry__envelope_add_attachments - reuse sentry__envelope_add_attachment --- src/backends/sentry_backend_breakpad.cpp | 2 +- src/backends/sentry_backend_inproc.c | 2 +- src/sentry_attachment.c | 57 ------------------------ src/sentry_attachment.h | 7 --- src/sentry_core.c | 4 +- src/sentry_envelope.c | 48 ++++++++++++++++++-- src/sentry_envelope.h | 9 +++- tests/unit/test_attachments.c | 10 ++--- 8 files changed, 61 insertions(+), 78 deletions(-) diff --git a/src/backends/sentry_backend_breakpad.cpp b/src/backends/sentry_backend_breakpad.cpp index 07e0f6361..bac8d6534 100644 --- a/src/backends/sentry_backend_breakpad.cpp +++ b/src/backends/sentry_backend_breakpad.cpp @@ -170,7 +170,7 @@ breakpad_backend_callback(const google_breakpad::MinidumpDescriptor &descriptor, = sentry__screenshot_get_path(options); if (sentry__screenshot_capture(screenshot_path)) { sentry__envelope_add_attachment( - envelope, screenshot_path, nullptr); + envelope, screenshot_path, ATTACHMENT, nullptr); } sentry__path_free(screenshot_path); } diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index b03982df1..f4b8bd554 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -602,7 +602,7 @@ handle_ucontext(const sentry_ucontext_t *uctx) = sentry__screenshot_get_path(options); if (sentry__screenshot_capture(screenshot_path)) { sentry__envelope_add_attachment( - envelope, screenshot_path, NULL); + envelope, screenshot_path, ATTACHMENT, NULL); } sentry__path_free(screenshot_path); } diff --git a/src/sentry_attachment.c b/src/sentry_attachment.c index eaf337b1f..417b7b7d8 100644 --- a/src/sentry_attachment.c +++ b/src/sentry_attachment.c @@ -1,28 +1,6 @@ #include "sentry_attachment.h" #include "sentry_alloc.h" -#include "sentry_envelope.h" -#include "sentry_options.h" #include "sentry_path.h" -#include "sentry_utils.h" -#include "sentry_value.h" - -#include - -static const char * -str_from_attachment_type(sentry_attachment_type_t attachment_type) -{ - switch (attachment_type) { - case ATTACHMENT: - return "event.attachment"; - case MINIDUMP: - return "event.minidump"; - case VIEW_HIERARCHY: - return "event.view_hierarchy"; - default: - UNREACHABLE("Unknown attachment type"); - return "event.attachment"; - } -} static void attachment_free(sentry_attachment_t *attachment) @@ -100,41 +78,6 @@ sentry__attachment_remove( sentry__path_free(path); } -void -sentry__apply_attachments_to_envelope( - sentry_envelope_t *envelope, const sentry_attachment_t *attachments) -{ - if (!attachments) { - return; - } - - SENTRY_DEBUG("adding attachments to envelope"); - for (const sentry_attachment_t *attachment = attachments; attachment; - attachment = attachment->next) { - sentry_envelope_item_t *item = sentry__envelope_add_from_path( - envelope, attachment->path, "attachment"); - if (!item) { - continue; - } - if (attachment->type != ATTACHMENT) { // don't need to set the default - sentry__envelope_item_set_header(item, "attachment_type", - sentry_value_new_string( - str_from_attachment_type(attachment->type))); - } - if (attachment->content_type) { - sentry__envelope_item_set_header(item, "content_type", - sentry_value_new_string(attachment->content_type)); - } - sentry__envelope_item_set_header(item, "filename", -#ifdef SENTRY_PLATFORM_WINDOWS - sentry__value_new_string_from_wstr( -#else - sentry_value_new_string( -#endif - sentry__path_filename(attachment->path))); - } -} - void sentry__attachments_extend( sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachments) diff --git a/src/sentry_attachment.h b/src/sentry_attachment.h index b3188cd4b..69ca13a91 100644 --- a/src/sentry_attachment.h +++ b/src/sentry_attachment.h @@ -3,7 +3,6 @@ #include "sentry_boot.h" -#include "sentry_envelope.h" #include "sentry_path.h" /** @@ -45,12 +44,6 @@ void sentry__attachment_add(sentry_attachment_t **attachments_ptr, void sentry__attachment_remove( sentry_attachment_t **attachments_ptr, sentry_path_t *path); -/** - * Reads the attachments from disk and adds them to the `envelope`. - */ -void sentry__apply_attachments_to_envelope( - sentry_envelope_t *envelope, const sentry_attachment_t *attachments); - /** * Extends the linked list of attachments at `attachments_ptr` with all * attachments in `attachments`. diff --git a/src/sentry_core.c b/src/sentry_core.c index 541d06ae9..f4d0fe498 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -599,10 +599,10 @@ sentry__prepare_event(const sentry_options_t *options, sentry_value_t event, SENTRY_WITH_SCOPE (scope) { if (all_attachments) { // all attachments merged from multiple scopes - sentry__apply_attachments_to_envelope(envelope, all_attachments); + sentry__envelope_add_attachments(envelope, all_attachments); } else { // only global scope has attachments - sentry__apply_attachments_to_envelope(envelope, scope->attachments); + sentry__envelope_add_attachments(envelope, scope->attachments); } } diff --git a/src/sentry_envelope.c b/src/sentry_envelope.c index 34285bdcc..0f39575e5 100644 --- a/src/sentry_envelope.c +++ b/src/sentry_envelope.c @@ -8,6 +8,7 @@ #include "sentry_string.h" #include "sentry_transport.h" #include "sentry_value.h" +#include #include struct sentry_envelope_item_s { @@ -345,9 +346,26 @@ sentry__envelope_add_session( envelope, payload, payload_len, "session"); } +static const char * +str_from_attachment_type(sentry_attachment_type_t attachment_type) +{ + switch (attachment_type) { + case ATTACHMENT: + return "event.attachment"; + case MINIDUMP: + return "event.minidump"; + case VIEW_HIERARCHY: + return "event.view_hierarchy"; + default: + UNREACHABLE("Unknown attachment type"); + return "event.attachment"; + } +} + sentry_envelope_item_t * sentry__envelope_add_attachment(sentry_envelope_t *envelope, - const sentry_path_t *attachment, const char *type) + const sentry_path_t *attachment, sentry_attachment_type_t type, + const char *content_type) { if (!envelope || !attachment) { return NULL; @@ -355,11 +373,17 @@ sentry__envelope_add_attachment(sentry_envelope_t *envelope, sentry_envelope_item_t *item = sentry__envelope_add_from_path(envelope, attachment, "attachment"); - if (type) { + if (!item) { + return NULL; + } + if (type != ATTACHMENT) { // don't need to set the default + sentry__envelope_item_set_header(item, "attachment_type", + sentry_value_new_string(str_from_attachment_type(type))); + } + if (content_type) { sentry__envelope_item_set_header( - item, "attachment_type", sentry_value_new_string(type)); + item, "content_type", sentry_value_new_string(content_type)); } - sentry__envelope_item_set_header(item, "filename", #ifdef SENTRY_PLATFORM_WINDOWS sentry__value_new_string_from_wstr( @@ -371,6 +395,22 @@ sentry__envelope_add_attachment(sentry_envelope_t *envelope, return item; } +void +sentry__envelope_add_attachments( + sentry_envelope_t *envelope, const sentry_attachment_t *attachments) +{ + if (!envelope || !attachments) { + return; + } + + SENTRY_DEBUG("adding attachments to envelope"); + for (const sentry_attachment_t *attachment = attachments; attachment; + attachment = attachment->next) { + sentry__envelope_add_attachment(envelope, attachment->path, + attachment->type, attachment->content_type); + } +} + sentry_envelope_item_t * sentry__envelope_add_from_buffer(sentry_envelope_t *envelope, const char *buf, size_t buf_len, const char *type) diff --git a/src/sentry_envelope.h b/src/sentry_envelope.h index 842cbb475..269eb485c 100644 --- a/src/sentry_envelope.h +++ b/src/sentry_envelope.h @@ -4,6 +4,7 @@ #include "sentry_boot.h" #include "sentry_core.h" +#include "sentry_attachment.h" #include "sentry_path.h" #include "sentry_ratelimiter.h" #include "sentry_session.h" @@ -59,7 +60,13 @@ sentry_envelope_item_t *sentry__envelope_add_session( */ sentry_envelope_item_t *sentry__envelope_add_attachment( sentry_envelope_t *envelope, const sentry_path_t *attachment, - const char *type); + sentry_attachment_type_t type, const char *content_type); + +/** + * Add attachments to this envelope. + */ +void sentry__envelope_add_attachments( + sentry_envelope_t *envelope, const sentry_attachment_t *attachments); /** * This will add the file contents from `path` as an envelope item of type diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index fe69ed432..e1ab5f69b 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -121,7 +121,7 @@ SENTRY_TEST(attachments_add_dedupe) sentry_envelope_t *envelope = sentry__envelope_new(); SENTRY_WITH_SCOPE (scope) { - sentry__apply_attachments_to_envelope(envelope, scope->attachments); + sentry__envelope_add_attachments(envelope, scope->attachments); } char *serialized = sentry_envelope_serialize(envelope, NULL); sentry_envelope_free(envelope); @@ -185,7 +185,7 @@ SENTRY_TEST(attachments_add_remove) envelope = sentry__envelope_new(); SENTRY_WITH_SCOPE (scope) { - sentry__apply_attachments_to_envelope(envelope, scope->attachments); + sentry__envelope_add_attachments(envelope, scope->attachments); } serialized = sentry_envelope_serialize(envelope, NULL); sentry_envelope_free(envelope); @@ -207,7 +207,7 @@ SENTRY_TEST(attachments_add_remove) envelope = sentry__envelope_new(); SENTRY_WITH_SCOPE (scope) { - sentry__apply_attachments_to_envelope(envelope, scope->attachments); + sentry__envelope_add_attachments(envelope, scope->attachments); } serialized = sentry_envelope_serialize(envelope, NULL); sentry_envelope_free(envelope); @@ -268,7 +268,7 @@ SENTRY_TEST(attachments_extend) SENTRY_WITH_SCOPE (scope) { sentry_envelope_t *envelope = sentry__envelope_new(); - sentry__apply_attachments_to_envelope(envelope, all_attachments); + sentry__envelope_add_attachments(envelope, all_attachments); char *serialized = sentry_envelope_serialize(envelope, NULL); @@ -290,7 +290,7 @@ SENTRY_TEST(attachments_extend) SENTRY_WITH_SCOPE (scope) { sentry_envelope_t *envelope = sentry__envelope_new(); - sentry__apply_attachments_to_envelope(envelope, all_attachments); + sentry__envelope_add_attachments(envelope, all_attachments); char *serialized = sentry_envelope_serialize(envelope, NULL); From b8e47dc399390a7abfc96d221d59ef269c111627 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 15:11:54 +0200 Subject: [PATCH 14/25] sentry_add_attachment -> sentry_add_attachment_path --- examples/example.c | 4 ++-- include/sentry.h | 22 ++++++++++++---------- src/sentry_core.c | 12 ++++++------ src/sentry_scope.c | 11 ++++++----- tests/unit/test_attachments.c | 24 ++++++++++++------------ 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/examples/example.c b/examples/example.c index 275e92eaa..bc8551364 100644 --- a/examples/example.c +++ b/examples/example.c @@ -402,7 +402,7 @@ main(int argc, char **argv) if (has_arg(argc, argv, "attach-after-init")) { // assuming the example / test is run directly from the cmake build // directory - sentry_add_attachment("./CMakeCache.txt"); + sentry_add_attachment_path("./CMakeCache.txt"); } if (has_arg(argc, argv, "start-session")) { @@ -433,7 +433,7 @@ main(int argc, char **argv) if (has_arg(argc, argv, "attach-to-scope")) { // assuming the example / test is run directly from the cmake build // directory - sentry_scope_add_attachment(scope, "./CMakeCache.txt"); + sentry_scope_add_attachment_path(scope, "./CMakeCache.txt"); } sentry_capture_event_with_scope(event, scope); diff --git a/include/sentry.h b/include/sentry.h index 387488319..b7db7c7d8 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -1788,15 +1788,16 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_handler_strategy( * Adds a new attachment to be sent along. * * `path` is assumed to be in platform-specific filesystem path encoding. - * API Users on windows are encouraged to use `sentry_add_attachmentw` instead. + * API Users on windows are encouraged to use `sentry_add_attachment_pathw` + * instead. * * See the NOTE on attachments above for restrictions of this API. */ -SENTRY_API void sentry_add_attachment(const char *path); -SENTRY_API void sentry_add_attachment_n(const char *path, size_t path_len); -SENTRY_API void sentry_scope_add_attachment( +SENTRY_API void sentry_add_attachment_path(const char *path); +SENTRY_API void sentry_add_attachment_path_n(const char *path, size_t path_len); +SENTRY_API void sentry_scope_add_attachment_path( sentry_scope_t *scope, const char *path); -SENTRY_API void sentry_scope_add_attachment_n( +SENTRY_API void sentry_scope_add_attachment_path_n( sentry_scope_t *scope, const char *path, size_t path_len); /** @@ -1813,13 +1814,14 @@ SENTRY_API void sentry_remove_attachment_n(const char *path, size_t path_len); #ifdef SENTRY_PLATFORM_WINDOWS /** - * Wide char version of `sentry_add_attachment`. + * Wide char version of `sentry_add_attachment_path`. */ -SENTRY_API void sentry_add_attachmentw(const wchar_t *path); -SENTRY_API void sentry_add_attachmentw_n(const wchar_t *path, size_t path_len); -SENTRY_API void sentry_scope_add_attachmentw( +SENTRY_API void sentry_add_attachment_pathw(const wchar_t *path); +SENTRY_API void sentry_add_attachment_pathw_n( + const wchar_t *path, size_t path_len); +SENTRY_API void sentry_scope_add_attachment_pathw( sentry_scope_t *scope, const wchar_t *path); -SENTRY_API void sentry_scope_add_attachmentw_n( +SENTRY_API void sentry_scope_add_attachment_pathw_n( sentry_scope_t *scope, const wchar_t *path, size_t path_len); /** diff --git a/src/sentry_core.c b/src/sentry_core.c index f4d0fe498..07f6ba474 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1429,13 +1429,13 @@ sentry_capture_minidump_n(const char *path, size_t path_len) } void -sentry_add_attachment(const char *path) +sentry_add_attachment_path(const char *path) { - sentry_add_attachment_n(path, sentry__guarded_strlen(path)); + sentry_add_attachment_path_n(path, sentry__guarded_strlen(path)); } void -sentry_add_attachment_n(const char *path, size_t path_len) +sentry_add_attachment_path_n(const char *path, size_t path_len) { sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); SENTRY_WITH_OPTIONS (options) { @@ -1472,14 +1472,14 @@ sentry_remove_attachment_n(const char *path, size_t path_len) #ifdef SENTRY_PLATFORM_WINDOWS void -sentry_add_attachmentw(const wchar_t *path) +sentry_add_attachment_pathw(const wchar_t *path) { size_t path_len = path ? wcslen(path) : 0; - sentry_add_attachmentw_n(path, path_len); + sentry_add_attachment_pathw_n(path, path_len); } void -sentry_add_attachmentw_n(const wchar_t *path, size_t path_len) +sentry_add_attachment_pathw_n(const wchar_t *path, size_t path_len) { sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); SENTRY_WITH_OPTIONS (options) { diff --git a/src/sentry_scope.c b/src/sentry_scope.c index 04cdb64b2..a01305073 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -674,13 +674,14 @@ sentry_scope_set_level(sentry_scope_t *scope, sentry_level_t level) } void -sentry_scope_add_attachment(sentry_scope_t *scope, const char *path) +sentry_scope_add_attachment_path(sentry_scope_t *scope, const char *path) { - sentry_scope_add_attachment_n(scope, path, sentry__guarded_strlen(path)); + sentry_scope_add_attachment_path_n( + scope, path, sentry__guarded_strlen(path)); } void -sentry_scope_add_attachment_n( +sentry_scope_add_attachment_path_n( sentry_scope_t *scope, const char *path, size_t path_len) { sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); @@ -689,14 +690,14 @@ sentry_scope_add_attachment_n( #ifdef SENTRY_PLATFORM_WINDOWS void -sentry_scope_add_attachmentw(sentry_scope_t *scope, const wchar_t *path) +sentry_scope_add_attachment_pathw(sentry_scope_t *scope, const wchar_t *path) { size_t path_len = path ? wcslen(path) : 0; sentry_scope_add_attachmentw_n(scope, path, path_len); } void -sentry_scope_add_attachmentw_n( +sentry_scope_add_attachment_pathw_n( sentry_scope_t *scope, const wchar_t *path, size_t path_len) { sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index e1ab5f69b..27e372e4d 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -99,13 +99,13 @@ SENTRY_TEST(attachments_add_dedupe) sentry_init(options); - sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".a.txt"); - sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".b.txt"); - sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".b.txt"); + sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".c.txt"); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_add_attachmentw(L".a.txt"); - sentry_add_attachmentw(L".b.txt"); - sentry_add_attachmentw(L".c.txt"); + sentry_add_attachment_pathw(L".a.txt"); + sentry_add_attachment_pathw(L".b.txt"); + sentry_add_attachment_pathw(L".c.txt"); #endif sentry_path_t *path_a @@ -155,18 +155,18 @@ SENTRY_TEST(attachments_add_remove) sentry_init(options); - sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); - sentry_add_attachment(SENTRY_TEST_PATH_PREFIX ".d.txt"); + sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".d.txt"); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_add_attachmentw(L".e.txt"); - sentry_add_attachmentw(L".d.txt"); + sentry_add_attachment_pathw(L".e.txt"); + sentry_add_attachment_pathw(L".d.txt"); #endif sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".d.txt"); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_remove_attachmentw(L".e.txt"); - sentry_remove_attachmentw(L".d.txt"); + sentry_remove_attachment_from_filew(L".e.txt"); + sentry_remove_attachment_from_filew(L".d.txt"); #endif sentry_path_t *path_a From d672c29497d259ed7bf3434af30e51b80469fbe2 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 15:14:08 +0200 Subject: [PATCH 15/25] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4efba843f..040d26c8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ **Features**: -- The `sentry_add_attachment`, `sentry_scope_add_attachment`, and `sentry_remove_attachment` (and their wide-string variants) have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. ([#1266](https://github.com/getsentry/sentry-native/pull/1266)) +- The `sentry_add_attachment_path`, `sentry_scope_add_attachment_path`, and `sentry_remove_attachment` (and their wide-string variants) have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. ([#1266](https://github.com/getsentry/sentry-native/pull/1266)) ## 0.9.0 From 17197d4c1f2122635c26af00cf2d4f35a05a5862 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 15:24:39 +0200 Subject: [PATCH 16/25] fixup: missed rename --- src/sentry_scope.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry_scope.c b/src/sentry_scope.c index a01305073..74766f08f 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -693,7 +693,7 @@ void sentry_scope_add_attachment_pathw(sentry_scope_t *scope, const wchar_t *path) { size_t path_len = path ? wcslen(path) : 0; - sentry_scope_add_attachmentw_n(scope, path, path_len); + sentry_scope_add_attachment_pathw_n(scope, path, path_len); } void From e9a2df1ba7c72716fdd79871fbdceafba0771ad8 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 15:45:46 +0200 Subject: [PATCH 17/25] fixup: another missed rename --- tests/unit/test_attachments.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index 27e372e4d..fe57c8065 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -165,8 +165,8 @@ SENTRY_TEST(attachments_add_remove) sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".d.txt"); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_remove_attachment_from_filew(L".e.txt"); - sentry_remove_attachment_from_filew(L".d.txt"); + sentry_remove_attachment_pathw(L".e.txt"); + sentry_remove_attachment_pathw(L".d.txt"); #endif sentry_path_t *path_a From a542aca6450d564940128fddc9401ab29ee13d81 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 16:26:31 +0200 Subject: [PATCH 18/25] remove_attachmentw() without _path --- tests/unit/test_attachments.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index fe57c8065..7b2198f43 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -165,8 +165,8 @@ SENTRY_TEST(attachments_add_remove) sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".d.txt"); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_remove_attachment_pathw(L".e.txt"); - sentry_remove_attachment_pathw(L".d.txt"); + sentry_remove_attachmentw(L".e.txt"); + sentry_remove_attachmentw(L".d.txt"); #endif sentry_path_t *path_a From 3a0cb459a2140d206339761de8e7f0a28c42cadf Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 22:39:33 +0200 Subject: [PATCH 19/25] revise sentry_attach_file & removal --- examples/example.c | 4 +- include/sentry.h | 51 +++++++++++------------ src/sentry_attachment.c | 45 ++++++++++---------- src/sentry_attachment.h | 11 +++-- src/sentry_core.c | 77 ++++++++++++----------------------- src/sentry_options.c | 8 ++-- src/sentry_scope.c | 26 ++++++------ tests/unit/test_attachments.c | 60 ++++++++++----------------- 8 files changed, 123 insertions(+), 159 deletions(-) diff --git a/examples/example.c b/examples/example.c index bc8551364..e60c24d4f 100644 --- a/examples/example.c +++ b/examples/example.c @@ -402,7 +402,7 @@ main(int argc, char **argv) if (has_arg(argc, argv, "attach-after-init")) { // assuming the example / test is run directly from the cmake build // directory - sentry_add_attachment_path("./CMakeCache.txt"); + sentry_attach_file("./CMakeCache.txt"); } if (has_arg(argc, argv, "start-session")) { @@ -433,7 +433,7 @@ main(int argc, char **argv) if (has_arg(argc, argv, "attach-to-scope")) { // assuming the example / test is run directly from the cmake build // directory - sentry_scope_add_attachment_path(scope, "./CMakeCache.txt"); + sentry_scope_attach_file(scope, "./CMakeCache.txt"); } sentry_capture_event_with_scope(event, scope); diff --git a/include/sentry.h b/include/sentry.h index b7db7c7d8..1cf27711e 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -1784,52 +1784,53 @@ SENTRY_EXPERIMENTAL_API void sentry_options_set_handler_strategy( #endif // SENTRY_PLATFORM_LINUX +/** + * A sentry Attachment. + * + * See https://develop.sentry.dev/sdk/data-model/envelope-items/#attachment + */ +struct sentry_attachment_s; +typedef struct sentry_attachment_s sentry_attachment_t; + /** * Adds a new attachment to be sent along. * * `path` is assumed to be in platform-specific filesystem path encoding. - * API Users on windows are encouraged to use `sentry_add_attachment_pathw` - * instead. + * API Users on windows are encouraged to use `sentry_attach_filew` or + * `sentry_scope_attach_filew` instead. + * + * The returned `sentry_attachment_t` is owned by the SDK and will remain valid + * until the attachment is removed with `sentry_remove_attachment` or + * `sentry_close` is called * * See the NOTE on attachments above for restrictions of this API. */ -SENTRY_API void sentry_add_attachment_path(const char *path); -SENTRY_API void sentry_add_attachment_path_n(const char *path, size_t path_len); -SENTRY_API void sentry_scope_add_attachment_path( +SENTRY_API sentry_attachment_t *sentry_attach_file(const char *path); +SENTRY_API sentry_attachment_t *sentry_attach_file_n( + const char *path, size_t path_len); +SENTRY_API sentry_attachment_t *sentry_scope_attach_file( sentry_scope_t *scope, const char *path); -SENTRY_API void sentry_scope_add_attachment_path_n( +SENTRY_API sentry_attachment_t *sentry_scope_attach_file_n( sentry_scope_t *scope, const char *path, size_t path_len); /** - * Removes a previously added attachment. - * - * `path` is assumed to be in platform-specific filesystem path encoding. - * API Users on windows are encouraged to use `sentry_remove_attachmentw` - * instead. + * Removes and frees a previously added attachment. * * See the NOTE on attachments above for restrictions of this API. */ -SENTRY_API void sentry_remove_attachment(const char *path); -SENTRY_API void sentry_remove_attachment_n(const char *path, size_t path_len); +SENTRY_API void sentry_remove_attachment(sentry_attachment_t *attachment); #ifdef SENTRY_PLATFORM_WINDOWS /** - * Wide char version of `sentry_add_attachment_path`. + * Wide char versions of `sentry_attach_file` and `sentry_scope_attach_file`. */ -SENTRY_API void sentry_add_attachment_pathw(const wchar_t *path); -SENTRY_API void sentry_add_attachment_pathw_n( +SENTRY_API sentry_attachment_t *sentry_attach_filew(const wchar_t *path); +SENTRY_API sentry_attachment_t *sentry_attach_filew_n( const wchar_t *path, size_t path_len); -SENTRY_API void sentry_scope_add_attachment_pathw( +SENTRY_API sentry_attachment_t *sentry_scope_attach_filew( sentry_scope_t *scope, const wchar_t *path); -SENTRY_API void sentry_scope_add_attachment_pathw_n( +SENTRY_API sentry_attachment_t *sentry_scope_attach_filew_n( sentry_scope_t *scope, const wchar_t *path, size_t path_len); - -/** - * Wide char version of `sentry_remove_attachment`. - */ -SENTRY_API void sentry_remove_attachmentw(const wchar_t *path); -SENTRY_API void sentry_remove_attachmentw_n( - const wchar_t *path, size_t path_len); #endif /* -- Session APIs -- */ diff --git a/src/sentry_attachment.c b/src/sentry_attachment.c index 417b7b7d8..49eb77f2d 100644 --- a/src/sentry_attachment.c +++ b/src/sentry_attachment.c @@ -24,18 +24,18 @@ sentry__attachments_free(sentry_attachment_t *attachments) } } -void -sentry__attachment_add(sentry_attachment_t **attachments_ptr, +sentry_attachment_t * +sentry__attachments_add(sentry_attachment_t **attachments_ptr, sentry_path_t *path, sentry_attachment_type_t attachment_type, const char *content_type) { if (!path) { - return; + return NULL; } sentry_attachment_t *attachment = SENTRY_MAKE(sentry_attachment_t); if (!attachment) { sentry__path_free(path); - return; + return NULL; } attachment->path = path; attachment->next = NULL; @@ -44,38 +44,39 @@ sentry__attachment_add(sentry_attachment_t **attachments_ptr, sentry_attachment_t **next_ptr = attachments_ptr; - for (sentry_attachment_t *last_attachment = *attachments_ptr; - last_attachment; last_attachment = last_attachment->next) { - if (sentry__path_eq(last_attachment->path, path)) { + for (sentry_attachment_t *it = *attachments_ptr; it; it = it->next) { + if (sentry__path_eq(it->path, path)) { attachment_free(attachment); - return; + return it; } - next_ptr = &last_attachment->next; + next_ptr = &it->next; } *next_ptr = attachment; + return attachment; } void -sentry__attachment_remove( - sentry_attachment_t **attachments_ptr, sentry_path_t *path) +sentry__attachments_remove( + sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachment) { + if (!attachment) { + return; + } + sentry_attachment_t **next_ptr = attachments_ptr; - for (sentry_attachment_t *attachment = *attachments_ptr; attachment; - attachment = attachment->next) { - if (sentry__path_eq(attachment->path, path)) { - *next_ptr = attachment->next; - attachment_free(attachment); - goto out; + for (sentry_attachment_t *it = *attachments_ptr; it; it = it->next) { + if (it == attachment || sentry__path_eq(it->path, attachment->path)) { + + *next_ptr = it->next; + attachment_free(it); + return; } - next_ptr = &attachment->next; + next_ptr = &it->next; } - -out: - sentry__path_free(path); } void @@ -88,7 +89,7 @@ sentry__attachments_extend( for (sentry_attachment_t *attachment = attachments; attachment; attachment = attachment->next) { - sentry__attachment_add(attachments_ptr, + sentry__attachments_add(attachments_ptr, sentry__path_clone(attachment->path), attachment->type, attachment->content_type); } diff --git a/src/sentry_attachment.h b/src/sentry_attachment.h index 69ca13a91..cc69263e1 100644 --- a/src/sentry_attachment.h +++ b/src/sentry_attachment.h @@ -18,7 +18,6 @@ typedef enum { * This is a linked list of all the attachments registered via * `sentry_options_add_attachment`. */ -typedef struct sentry_attachment_s sentry_attachment_t; struct sentry_attachment_s { sentry_path_t *path; sentry_attachment_type_t type; @@ -34,15 +33,15 @@ void sentry__attachments_free(sentry_attachment_t *attachments); /** * Adds an attachment to the attachments list at `attachments_ptr`. */ -void sentry__attachment_add(sentry_attachment_t **attachments_ptr, - sentry_path_t *path, sentry_attachment_type_t attachment_type, - const char *content_type); +sentry_attachment_t *sentry__attachments_add( + sentry_attachment_t **attachments_ptr, sentry_path_t *path, + sentry_attachment_type_t attachment_type, const char *content_type); /** * Removes an attachment from the attachments list at `attachments_ptr`. */ -void sentry__attachment_remove( - sentry_attachment_t **attachments_ptr, sentry_path_t *path); +void sentry__attachments_remove( + sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachment); /** * Extends the linked list of attachments at `attachments_ptr` with all diff --git a/src/sentry_core.c b/src/sentry_core.c index 07f6ba474..bac6b2e80 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1428,90 +1428,67 @@ sentry_capture_minidump_n(const char *path, size_t path_len) return sentry_uuid_nil(); } -void -sentry_add_attachment_path(const char *path) +sentry_attachment_t * +sentry_attach_file(const char *path) { - sentry_add_attachment_path_n(path, sentry__guarded_strlen(path)); + return sentry_attach_file_n(path, sentry__guarded_strlen(path)); } -void -sentry_add_attachment_path_n(const char *path, size_t path_len) +sentry_attachment_t * +sentry_attach_file_n(const char *path, size_t path_len) { - sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); + sentry_path_t *attachment_path = sentry__path_from_str_n(path, path_len); SENTRY_WITH_OPTIONS (options) { if (options->backend && options->backend->add_attachment_func) { - options->backend->add_attachment_func(options->backend, attachment); + options->backend->add_attachment_func( + options->backend, attachment_path); } } + sentry_attachment_t *attachment = NULL; SENTRY_WITH_SCOPE_MUT (scope) { - sentry__attachment_add( - &scope->attachments, attachment, ATTACHMENT, NULL); + attachment = sentry__attachments_add( + &scope->attachments, attachment_path, ATTACHMENT, NULL); } + return attachment; } void -sentry_remove_attachment(const char *path) -{ - sentry_remove_attachment_n(path, sentry__guarded_strlen(path)); -} - -void -sentry_remove_attachment_n(const char *path, size_t path_len) +sentry_remove_attachment(sentry_attachment_t *attachment) { - sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); SENTRY_WITH_OPTIONS (options) { if (options->backend && options->backend->remove_attachment_func) { options->backend->remove_attachment_func( - options->backend, attachment); + options->backend, attachment->path); } } SENTRY_WITH_SCOPE_MUT (scope) { - sentry__attachment_remove(&scope->attachments, attachment); + sentry__attachments_remove(&scope->attachments, attachment); } } #ifdef SENTRY_PLATFORM_WINDOWS -void -sentry_add_attachment_pathw(const wchar_t *path) +sentry_attachment_t * +sentry_attach_filew(const wchar_t *path) { size_t path_len = path ? wcslen(path) : 0; - sentry_add_attachment_pathw_n(path, path_len); + return sentry_attach_filew_n(path, path_len); } -void -sentry_add_attachment_pathw_n(const wchar_t *path, size_t path_len) +sentry_attachment_t * +sentry_attach_filew_n(const wchar_t *path, size_t path_len) { - sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); + sentry_path_t *attachment_path = sentry__path_from_wstr_n(path, path_len); SENTRY_WITH_OPTIONS (options) { if (options->backend && options->backend->add_attachment_func) { - options->backend->add_attachment_func(options->backend, attachment); - } - } - SENTRY_WITH_SCOPE_MUT (scope) { - sentry__attachment_add( - &scope->attachments, attachment, ATTACHMENT, NULL); - } -} - -void -sentry_remove_attachmentw(const wchar_t *path) -{ - size_t path_len = path ? wcslen(path) : 0; - sentry_remove_attachmentw_n(path, path_len); -} - -void -sentry_remove_attachmentw_n(const wchar_t *path, size_t path_len) -{ - sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); - SENTRY_WITH_OPTIONS (options) { - if (options->backend && options->backend->remove_attachment_func) { - options->backend->remove_attachment_func( - options->backend, attachment); + options->backend->add_attachment_func( + options->backend, attachment_path); } } + sentry_attachment_t *attachment = NULL; SENTRY_WITH_SCOPE_MUT (scope) { - sentry__attachment_remove(&scope->attachments, attachment); + attachment = sentry__attachments_add( + &scope->attachments, attachment_path, ATTACHMENT, NULL); } + return attachment; } #endif diff --git a/src/sentry_options.c b/src/sentry_options.c index 6eac065e7..c5b8d20b2 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -486,7 +486,7 @@ sentry_options_get_shutdown_timeout(sentry_options_t *opts) void sentry_options_add_attachment(sentry_options_t *opts, const char *path) { - sentry__attachment_add( + sentry__attachments_add( &opts->attachments, sentry__path_from_str(path), ATTACHMENT, NULL); } @@ -494,14 +494,14 @@ void sentry_options_add_attachment_n( sentry_options_t *opts, const char *path, size_t path_len) { - sentry__attachment_add(&opts->attachments, + sentry__attachments_add(&opts->attachments, sentry__path_from_str_n(path, path_len), ATTACHMENT, NULL); } void sentry_options_add_view_hierarchy(sentry_options_t *opts, const char *path) { - sentry__attachment_add(&opts->attachments, sentry__path_from_str(path), + sentry__attachments_add(&opts->attachments, sentry__path_from_str(path), VIEW_HIERARCHY, "application/json"); } @@ -509,7 +509,7 @@ void sentry_options_add_view_hierarchy_n( sentry_options_t *opts, const char *path, size_t path_len) { - sentry__attachment_add(&opts->attachments, + sentry__attachments_add(&opts->attachments, sentry__path_from_str_n(path, path_len), VIEW_HIERARCHY, "application/json"); } diff --git a/src/sentry_scope.c b/src/sentry_scope.c index 74766f08f..cc1c03697 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -673,34 +673,36 @@ sentry_scope_set_level(sentry_scope_t *scope, sentry_level_t level) scope->level = level; } -void -sentry_scope_add_attachment_path(sentry_scope_t *scope, const char *path) +sentry_attachment_t * +sentry_scope_attach_file(sentry_scope_t *scope, const char *path) { - sentry_scope_add_attachment_path_n( + return sentry_scope_attach_file_n( scope, path, sentry__guarded_strlen(path)); } -void -sentry_scope_add_attachment_path_n( +sentry_attachment_t * +sentry_scope_attach_file_n( sentry_scope_t *scope, const char *path, size_t path_len) { sentry_path_t *attachment = sentry__path_from_str_n(path, path_len); - sentry__attachment_add(&scope->attachments, attachment, ATTACHMENT, NULL); + return sentry__attachments_add( + &scope->attachments, attachment, ATTACHMENT, NULL); } #ifdef SENTRY_PLATFORM_WINDOWS -void -sentry_scope_add_attachment_pathw(sentry_scope_t *scope, const wchar_t *path) +sentry_attachment_t * +sentry_scope_attach_filew(sentry_scope_t *scope, const wchar_t *path) { size_t path_len = path ? wcslen(path) : 0; - sentry_scope_add_attachment_pathw_n(scope, path, path_len); + return sentry_scope_attach_filew_n(scope, path, path_len); } -void -sentry_scope_add_attachment_pathw_n( +sentry_attachment_t * +sentry_scope_attach_filew_n( sentry_scope_t *scope, const wchar_t *path, size_t path_len) { sentry_path_t *attachment = sentry__path_from_wstr_n(path, path_len); - sentry__attachment_add(&scope->attachments, attachment, ATTACHMENT, NULL); + return sentry__attachments_add( + &scope->attachments, attachment, ATTACHMENT, NULL); } #endif diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index 7b2198f43..34da7e669 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -99,13 +99,13 @@ SENTRY_TEST(attachments_add_dedupe) sentry_init(options); - sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".a.txt"); - sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".b.txt"); - sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".a.txt"); + sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".b.txt"); + sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".c.txt"); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_add_attachment_pathw(L".a.txt"); - sentry_add_attachment_pathw(L".b.txt"); - sentry_add_attachment_pathw(L".c.txt"); + sentry_attach_filew(L".a.txt"); + sentry_attach_filew(L".b.txt"); + sentry_attach_filew(L".c.txt"); #endif sentry_path_t *path_a @@ -155,18 +155,20 @@ SENTRY_TEST(attachments_add_remove) sentry_init(options); - sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".c.txt"); - sentry_add_attachment_path(SENTRY_TEST_PATH_PREFIX ".d.txt"); + sentry_attachment_t *attachment_c + = sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".c.txt"); + sentry_attachment_t *attachment_d + = sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".d.txt"); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_add_attachment_pathw(L".e.txt"); - sentry_add_attachment_pathw(L".d.txt"); + sentry_attachment_t *attachment_ew = sentry_attach_filew(L".e.txt"); + sentry_attachment_t *attachment_dw = sentry_attach_filew(L".d.txt"); #endif - sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".c.txt"); - sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".d.txt"); + sentry_remove_attachment(attachment_c); + sentry_remove_attachment(attachment_d); #ifdef SENTRY_PLATFORM_WINDOWS - sentry_remove_attachmentw(L".e.txt"); - sentry_remove_attachmentw(L".d.txt"); + sentry_remove_attachment(attachment_ew); + sentry_remove_attachment(attachment_dw); #endif sentry_path_t *path_a @@ -198,24 +200,6 @@ SENTRY_TEST(attachments_add_remove) sentry_free(serialized); - sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".a.txt"); - sentry_remove_attachment(SENTRY_TEST_PATH_PREFIX ".b.txt"); -#ifdef SENTRY_PLATFORM_WINDOWS - sentry_remove_attachmentw(L".b.txt"); - sentry_remove_attachmentw(L".a.txt"); -#endif - - envelope = sentry__envelope_new(); - SENTRY_WITH_SCOPE (scope) { - sentry__envelope_add_attachments(envelope, scope->attachments); - } - serialized = sentry_envelope_serialize(envelope, NULL); - sentry_envelope_free(envelope); - - TEST_CHECK_STRING_EQUAL(serialized, "{}"); - - sentry_free(serialized); - sentry_shutdown(); sentry__path_remove(path_a); @@ -247,19 +231,19 @@ SENTRY_TEST(attachments_extend) sentry__path_write_buffer(path_d, "ddd", 3); sentry_attachment_t *attachments_abc = NULL; - sentry__attachment_add( + sentry__attachments_add( &attachments_abc, sentry__path_clone(path_a), ATTACHMENT, NULL); - sentry__attachment_add( + sentry__attachments_add( &attachments_abc, sentry__path_clone(path_b), ATTACHMENT, NULL); - sentry__attachment_add( + sentry__attachments_add( &attachments_abc, sentry__path_clone(path_c), ATTACHMENT, NULL); sentry_attachment_t *attachments_bcd = NULL; - sentry__attachment_add( + sentry__attachments_add( &attachments_bcd, sentry__path_clone(path_b), ATTACHMENT, NULL); - sentry__attachment_add( + sentry__attachments_add( &attachments_bcd, sentry__path_clone(path_c), ATTACHMENT, NULL); - sentry__attachment_add( + sentry__attachments_add( &attachments_bcd, sentry__path_clone(path_d), ATTACHMENT, NULL); sentry_attachment_t *all_attachments = NULL; From 5a0027363dc843e291311d3a0cabfd092d4ebabd Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 22:55:39 +0200 Subject: [PATCH 20/25] fix windows --- src/sentry_options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sentry_options.c b/src/sentry_options.c index c5b8d20b2..593c64ac7 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -555,7 +555,7 @@ void sentry_options_add_attachmentw_n( sentry_options_t *opts, const wchar_t *path, size_t path_len) { - sentry__attachment_add(&opts->attachments, + sentry__attachments_add(&opts->attachments, sentry__path_from_wstr_n(path, path_len), ATTACHMENT, NULL); } @@ -576,7 +576,7 @@ void sentry_options_add_view_hierarchyw_n( sentry_options_t *opts, const wchar_t *path, size_t path_len) { - sentry__attachment_add(&opts->attachments, + sentry__attachments_add(&opts->attachments, sentry__path_from_wstr_n(path, path_len), VIEW_HIERARCHY, "application/json"); } From 759caa0b9f379a932edbdc63dacf15752f21d5ea Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 22:54:51 +0200 Subject: [PATCH 21/25] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 040d26c8c..756bb6604 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ **Features**: -- The `sentry_add_attachment_path`, `sentry_scope_add_attachment_path`, and `sentry_remove_attachment` (and their wide-string variants) have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. ([#1266](https://github.com/getsentry/sentry-native/pull/1266)) +- The `sentry_attach_file`, `sentry_scope_attach_file` (and their wide-string variants), and `sentry_remove_attachment` have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. ([#1266](https://github.com/getsentry/sentry-native/pull/1266)) ## 0.9.0 From deb6fce820d2f30155c6072d76c8ce927025d17f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 23:01:43 +0200 Subject: [PATCH 22/25] clean up --- src/sentry_attachment.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/sentry_attachment.c b/src/sentry_attachment.c index 49eb77f2d..b30630774 100644 --- a/src/sentry_attachment.c +++ b/src/sentry_attachment.c @@ -15,10 +15,10 @@ attachment_free(sentry_attachment_t *attachment) void sentry__attachments_free(sentry_attachment_t *attachments) { - sentry_attachment_t *next_attachment = attachments; - while (next_attachment) { - sentry_attachment_t *attachment = next_attachment; - next_attachment = attachment->next; + sentry_attachment_t *it = attachments; + while (it) { + sentry_attachment_t *attachment = it; + it = attachment->next; attachment_free(attachment); } @@ -69,7 +69,6 @@ sentry__attachments_remove( for (sentry_attachment_t *it = *attachments_ptr; it; it = it->next) { if (it == attachment || sentry__path_eq(it->path, attachment->path)) { - *next_ptr = it->next; attachment_free(it); return; @@ -83,14 +82,8 @@ void sentry__attachments_extend( sentry_attachment_t **attachments_ptr, sentry_attachment_t *attachments) { - if (!attachments) { - return; - } - - for (sentry_attachment_t *attachment = attachments; attachment; - attachment = attachment->next) { - sentry__attachments_add(attachments_ptr, - sentry__path_clone(attachment->path), attachment->type, - attachment->content_type); + for (sentry_attachment_t *it = attachments; it; it = it->next) { + sentry__attachments_add(attachments_ptr, sentry__path_clone(it->path), + it->type, it->content_type); } } From d36e17bcc0dbb6b664a1344d5a9f7cd96e8f2972 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 12 Jun 2025 23:20:58 +0200 Subject: [PATCH 23/25] fix attachments_add_remove on windows --- tests/unit/test_attachments.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index 34da7e669..08eb59086 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -161,14 +161,12 @@ SENTRY_TEST(attachments_add_remove) = sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".d.txt"); #ifdef SENTRY_PLATFORM_WINDOWS sentry_attachment_t *attachment_ew = sentry_attach_filew(L".e.txt"); - sentry_attachment_t *attachment_dw = sentry_attach_filew(L".d.txt"); #endif sentry_remove_attachment(attachment_c); sentry_remove_attachment(attachment_d); #ifdef SENTRY_PLATFORM_WINDOWS sentry_remove_attachment(attachment_ew); - sentry_remove_attachment(attachment_dw); #endif sentry_path_t *path_a From 62eff3b035959be512c148b1656776249807bd50 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 13 Jun 2025 09:58:47 +0200 Subject: [PATCH 24/25] Update CHANGELOG.md & NOTE on attachments --- CHANGELOG.md | 1 + include/sentry.h | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 756bb6604..64e5f1d63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Features**: - The `sentry_attach_file`, `sentry_scope_attach_file` (and their wide-string variants), and `sentry_remove_attachment` have been added to modify the list of attachments that are sent along with sentry events after a call to `sentry_init`. ([#1266](https://github.com/getsentry/sentry-native/pull/1266)) + - NOTE: When using the `crashpad` backend on macOS, the list of attachments that will be added at the time of a hard crash will be frozen at the time of `sentry_init`, and later modifications will not be reflected. ## 0.9.0 diff --git a/include/sentry.h b/include/sentry.h index 1cf27711e..91c584418 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -16,11 +16,11 @@ * * NOTE on attachments: * - * Attachments are read lazily at the time of `sentry_capture_event` or at time - * of a hard crash. Relative attachment paths will be resolved according to the - * current working directory at the time of envelope creation. - * When adding and removing attachments, they are matched according to their - * given `path`. No normalization is performed. + * Attachments are read lazily at the time of `sentry_capture_event`, + * `sentry_capture_event_with_scope`, or at time of a hard crash. Relative + * attachment paths will be resolved according to the current working directory + * at the time of envelope creation. When adding and removing attachments, they + * are matched according to their given `path`. No normalization is performed. * When using the `crashpad` backend on macOS, the list of attachments that will * be added at the time of a hard crash will be frozen at the time of * `sentry_init`, and later modifications will not be reflected. From 05b138f8e871f83c945df92efccfb2fb2b6317c3 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 13 Jun 2025 10:00:26 +0200 Subject: [PATCH 25/25] Update external/crashpad --- external/crashpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index b97109c0c..2e8ce8b68 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit b97109c0cbda479d2f3e21419466b0228ce38e08 +Subproject commit 2e8ce8b6832aaaa8c4fbdd3b66d2b80ef4ca585c