Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fdd2d91
perf: use recursive rwlock for global scope
jpnurmi Jul 14, 2026
22a16b5
fix: prevent rwlock writer starvation
jpnurmi Jul 16, 2026
cbee686
WIP: drop recursive, hide scope
jpnurmi Jul 21, 2026
acff4c0
reset
jpnurmi Jul 22, 2026
cadd3de
refactor(scope): hide direct data access
jpnurmi Jul 22, 2026
241b14a
WIP: observers
jpnurmi Jul 27, 2026
bcdab09
feat(sync): add platform rwlock primitive
jpnurmi Aug 5, 2026
557879d
refactor(sync): make rwlock operations inline
jpnurmi Aug 5, 2026
466a386
refactor(scope): guard simple fields with rwlock
jpnurmi Aug 5, 2026
c3bed2e
refactor(scope): retain user and fingerprint values safely
jpnurmi Aug 5, 2026
c6e8ee7
refactor(scope): store string fields as values
jpnurmi Aug 5, 2026
dda98a7
refactor(scope): move locked payload into scope data
jpnurmi Aug 6, 2026
3cfdf9a
refactor(scope): hide direct scope data access
jpnurmi Aug 6, 2026
5eec237
ref containers
jpnurmi Aug 6, 2026
884c831
breadcrumbs
jpnurmi Aug 7, 2026
bcbcba6
trace_context
jpnurmi Aug 7, 2026
26843b8
propagation_context
jpnurmi Aug 7, 2026
a93501d
dsc
jpnurmi Aug 7, 2026
4059643
span/transaction_object
jpnurmi Aug 7, 2026
922faa1
restore
jpnurmi Aug 7, 2026
b7c09a3
ref(value): track string length
jpnurmi Aug 7, 2026
c7f00f6
attachments
jpnurmi Aug 7, 2026
ae763a2
lock observers
jpnurmi Aug 7, 2026
05fe336
finally :D
jpnurmi Aug 7, 2026
9c92900
fix formatting
jpnurmi Aug 7, 2026
9676b47
init
jpnurmi Aug 7, 2026
f2f0133
attachments cont'd
jpnurmi Aug 9, 2026
ab8fc0e
fix(scope): Keep global scope alive during access
jpnurmi Aug 9, 2026
8ec9c8c
fix(attachments): Release ignored attachment references
jpnurmi Aug 9, 2026
3c7c966
attachments again
jpnurmi Aug 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -944,17 +944,19 @@ main(int argc, char **argv)
}

if (has_arg(argc, argv, "attachment")) {
sentry_attachment_t *bytes
sentry_value_t bytes
= sentry_attach_bytes("\xc0\xff\xee", 3, "bytes.bin");
sentry_attachment_set_content_type(bytes, "application/octet-stream");
sentry_value_decref(bytes);
}
if (has_arg(argc, argv, "attach-view-hierarchy")) {
// assuming the example / test is run directly from the cmake build
// directory
sentry_attachment_t *view_hierarchy
sentry_value_t view_hierarchy
= sentry_attach_file("./view-hierarchy.json");
sentry_attachment_set_type(
view_hierarchy, SENTRY_ATTACHMENT_TYPE_VIEW_HIERARCHY);
sentry_value_decref(view_hierarchy);
}

if (has_arg(argc, argv, "large-attachment")) {
Expand All @@ -972,11 +974,12 @@ main(int argc, char **argv)
remaining -= chunk;
}
fclose(f);
sentry_attachment_t *attachment = sentry_attach_file(large_file);
if (attachment) {
sentry_value_t attachment = sentry_attach_file(large_file);
if (!sentry_value_is_null(attachment)) {
sentry_attachment_set_type(
attachment, SENTRY_ATTACHMENT_TYPE_MINIDUMP);
}
sentry_value_decref(attachment);
}
}

Expand Down Expand Up @@ -1082,10 +1085,11 @@ 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_attach_file("./CMakeCache.txt");
sentry_attachment_t *bytes
sentry_value_decref(sentry_attach_file("./CMakeCache.txt"));
sentry_value_t bytes
= sentry_attach_bytes("\xc0\xff\xee", 3, "bytes.bin");
sentry_attachment_set_content_type(bytes, "application/octet-stream");
sentry_value_decref(bytes);
}

if (has_arg(argc, argv, "update-release-env")) {
Expand Down Expand Up @@ -1125,11 +1129,13 @@ 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_attach_file(scope, "./CMakeCache.txt");
sentry_attachment_t *bytes = sentry_scope_attach_bytes(
sentry_value_decref(
sentry_scope_attach_file(scope, "./CMakeCache.txt"));
sentry_value_t bytes = sentry_scope_attach_bytes(
scope, "\xc0\xff\xee", 3, "bytes.bin");
sentry_attachment_set_content_type(
bytes, "application/octet-stream");
sentry_value_decref(bytes);
}

sentry_scope_capture_event(scope, event);
Expand Down
106 changes: 48 additions & 58 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -2937,14 +2937,6 @@ 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;

/**
* Attaches a file to be sent along with events.
*
Expand All @@ -2956,18 +2948,18 @@ typedef struct sentry_attachment_s sentry_attachment_t;
* Calling this function multiple times with the same `path` is safe, but
* duplicate attachments with equal paths will not be added.
*
* 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.
* Returns an owned attachment value, or a null value on error. The returned
* value may be passed to `sentry_remove_attachment`, which consumes it, or
* released with `sentry_value_decref`.
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API sentry_attachment_t *sentry_attach_file(const char *path);
SENTRY_API sentry_attachment_t *sentry_attach_file_n(
SENTRY_API sentry_value_t sentry_attach_file(const char *path);
SENTRY_API sentry_value_t sentry_attach_file_n(
const char *path, size_t path_len);
SENTRY_API sentry_attachment_t *sentry_scope_attach_file(
SENTRY_API sentry_value_t sentry_scope_attach_file(
sentry_scope_t *scope, const char *path);
SENTRY_API sentry_attachment_t *sentry_scope_attach_file_n(
SENTRY_API sentry_value_t sentry_scope_attach_file_n(
sentry_scope_t *scope, const char *path, size_t path_len);

/**
Expand All @@ -2988,21 +2980,20 @@ SENTRY_API sentry_attachment_t *sentry_scope_attach_file_n(
* by appending a unique suffix to the filename. Therefore, attachments may show
* up with altered names in the Sentry Web UI.
*
* 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.
* Returns an owned attachment value, or a null value on error. The returned
* value may be passed to `sentry_remove_attachment`, which consumes it, or
* released with `sentry_value_decref`.
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API sentry_attachment_t *sentry_attach_bytes(
SENTRY_API sentry_value_t sentry_attach_bytes(
const char *buf, size_t buf_len, const char *filename);
SENTRY_API sentry_attachment_t *sentry_attach_bytes_n(
SENTRY_API sentry_value_t sentry_attach_bytes_n(
const char *buf, size_t buf_len, const char *filename, size_t filename_len);
SENTRY_API sentry_attachment_t *sentry_scope_attach_bytes(sentry_scope_t *scope,
SENTRY_API sentry_value_t sentry_scope_attach_bytes(sentry_scope_t *scope,
const char *buf, size_t buf_len, const char *filename);
SENTRY_API sentry_attachment_t *sentry_scope_attach_bytes_n(
sentry_scope_t *scope, const char *buf, size_t buf_len,
const char *filename, size_t filename_len);
SENTRY_API sentry_value_t sentry_scope_attach_bytes_n(sentry_scope_t *scope,
const char *buf, size_t buf_len, const char *filename, size_t filename_len);

/**
* Removes and frees all previously added attachments.
Expand All @@ -3012,35 +3003,36 @@ SENTRY_API void sentry_clear_attachments(void);
/**
* Removes and frees a previously added attachment.
*
* Consumes `attachment`.
*
* See the NOTE on attachments above for restrictions of this API.
*/
SENTRY_API void sentry_remove_attachment(sentry_attachment_t *attachment);
SENTRY_API void sentry_remove_attachment(sentry_value_t attachment);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Wide char versions of `sentry_attach_file` and `sentry_scope_attach_file`.
*/
SENTRY_API sentry_attachment_t *sentry_attach_filew(const wchar_t *path);
SENTRY_API sentry_attachment_t *sentry_attach_filew_n(
SENTRY_API sentry_value_t sentry_attach_filew(const wchar_t *path);
SENTRY_API sentry_value_t sentry_attach_filew_n(
const wchar_t *path, size_t path_len);
SENTRY_API sentry_attachment_t *sentry_scope_attach_filew(
SENTRY_API sentry_value_t sentry_scope_attach_filew(
sentry_scope_t *scope, const wchar_t *path);
SENTRY_API sentry_attachment_t *sentry_scope_attach_filew_n(
SENTRY_API sentry_value_t sentry_scope_attach_filew_n(
sentry_scope_t *scope, const wchar_t *path, size_t path_len);

/**
* Wide char versions of `sentry_attach_bytes` and `sentry_scope_attach_bytes`.
*/
SENTRY_API sentry_attachment_t *sentry_attach_bytesw(
SENTRY_API sentry_value_t sentry_attach_bytesw(
const char *buf, size_t buf_len, const wchar_t *filename);
SENTRY_API sentry_attachment_t *sentry_attach_bytesw_n(const char *buf,
SENTRY_API sentry_value_t sentry_attach_bytesw_n(const char *buf,
size_t buf_len, const wchar_t *filename, size_t filename_len);
SENTRY_API sentry_attachment_t *sentry_scope_attach_bytesw(
sentry_scope_t *scope, const char *buf, size_t buf_len,
const wchar_t *filename);
SENTRY_API sentry_attachment_t *sentry_scope_attach_bytesw_n(
sentry_scope_t *scope, const char *buf, size_t buf_len,
const wchar_t *filename, size_t filename_len);
SENTRY_API sentry_value_t sentry_scope_attach_bytesw(sentry_scope_t *scope,
const char *buf, size_t buf_len, const wchar_t *filename);
SENTRY_API sentry_value_t sentry_scope_attach_bytesw_n(sentry_scope_t *scope,
const char *buf, size_t buf_len, const wchar_t *filename,
size_t filename_len);
#endif

#define SENTRY_ATTACHMENT_TYPE_GENERIC "event.attachment"
Expand All @@ -3059,36 +3051,34 @@ SENTRY_API sentry_attachment_t *sentry_scope_attach_bytesw_n(
* https://develop.sentry.dev/sdk/telemetry/attachments/#attachment-types
*/
SENTRY_API void sentry_attachment_set_type(
sentry_attachment_t *attachment, const char *type);
sentry_value_t attachment, const char *type);
SENTRY_API void sentry_attachment_set_type_n(
sentry_attachment_t *attachment, const char *type, size_t type_len);
sentry_value_t attachment, const char *type, size_t type_len);

/**
* Sets the content type of attachment.
*/
SENTRY_API void sentry_attachment_set_content_type(
sentry_attachment_t *attachment, const char *content_type);
SENTRY_API void sentry_attachment_set_content_type_n(
sentry_attachment_t *attachment, const char *content_type,
size_t content_type_len);
sentry_value_t attachment, const char *content_type);
SENTRY_API void sentry_attachment_set_content_type_n(sentry_value_t attachment,
const char *content_type, size_t content_type_len);

/**
* Sets the filename of an attachment.
*/
SENTRY_API void sentry_attachment_set_filename(
sentry_attachment_t *attachment, const char *filename);
sentry_value_t attachment, const char *filename);
SENTRY_API void sentry_attachment_set_filename_n(
sentry_attachment_t *attachment, const char *filename, size_t filename_len);
sentry_value_t attachment, const char *filename, size_t filename_len);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Wide char version of `sentry_attachment_set_filename`.
*/
SENTRY_API void sentry_attachment_set_filenamew(
sentry_attachment_t *attachment, const wchar_t *filename);
sentry_value_t attachment, const wchar_t *filename);
SENTRY_API void sentry_attachment_set_filenamew_n(
sentry_attachment_t *attachment, const wchar_t *filename,
size_t filename_len);
sentry_value_t attachment, const wchar_t *filename, size_t filename_len);
#endif

/* -- Session APIs -- */
Expand Down Expand Up @@ -3672,39 +3662,39 @@ SENTRY_API sentry_hint_t *sentry_hint_new(void);
* Attaches a file to a hint.
*
* The file will be read and sent when the event is captured.
* Returns a pointer to the attachment, or NULL on error.
* Returns an owned attachment value, or a null value on error.
*/
SENTRY_API sentry_attachment_t *sentry_hint_attach_file(
SENTRY_API sentry_value_t sentry_hint_attach_file(
sentry_hint_t *hint, const char *path);
SENTRY_API sentry_attachment_t *sentry_hint_attach_file_n(
SENTRY_API sentry_value_t sentry_hint_attach_file_n(
sentry_hint_t *hint, const char *path, size_t path_len);

/**
* Attaches bytes to a hint.
*
* The data is copied internally and will be sent when the event is captured.
* Returns a pointer to the attachment, or NULL on error.
* Returns an owned attachment value, or a null value on error.
*/
SENTRY_API sentry_attachment_t *sentry_hint_attach_bytes(
SENTRY_API sentry_value_t sentry_hint_attach_bytes(
sentry_hint_t *hint, const char *buf, size_t buf_len, const char *filename);
SENTRY_API sentry_attachment_t *sentry_hint_attach_bytes_n(sentry_hint_t *hint,
SENTRY_API sentry_value_t sentry_hint_attach_bytes_n(sentry_hint_t *hint,
const char *buf, size_t buf_len, const char *filename, size_t filename_len);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Wide char version of `sentry_hint_attach_file`.
*/
SENTRY_API sentry_attachment_t *sentry_hint_attach_filew(
SENTRY_API sentry_value_t sentry_hint_attach_filew(
sentry_hint_t *hint, const wchar_t *path);
SENTRY_API sentry_attachment_t *sentry_hint_attach_filew_n(
SENTRY_API sentry_value_t sentry_hint_attach_filew_n(
sentry_hint_t *hint, const wchar_t *path, size_t path_len);

/**
* Wide char version of `sentry_hint_attach_bytes`.
*/
SENTRY_API sentry_attachment_t *sentry_hint_attach_bytesw(sentry_hint_t *hint,
SENTRY_API sentry_value_t sentry_hint_attach_bytesw(sentry_hint_t *hint,
const char *buf, size_t buf_len, const wchar_t *filename);
SENTRY_API sentry_attachment_t *sentry_hint_attach_bytesw_n(sentry_hint_t *hint,
SENTRY_API sentry_value_t sentry_hint_attach_bytesw_n(sentry_hint_t *hint,
const char *buf, size_t buf_len, const wchar_t *filename,
size_t filename_len);
#endif
Expand Down
9 changes: 5 additions & 4 deletions ndk/lib/src/main/jni/sentry.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,10 @@ Java_io_sentry_ndk_NativeScope_nativeAddAttachment(
return;
}

// The returned sentry_attachment_t* is intentionally discarded.
// The returned attachment value is intentionally released immediately.
// We are not tracking it across the JNI boundary for individual removals.
// Use sentry_clear_attachments() for bulk removal.
sentry_attach_file(charPath);
sentry_value_decref(sentry_attach_file(charPath));

(*env)->ReleaseStringUTFChars(env, path, charPath);
}
Expand All @@ -293,10 +293,11 @@ Java_io_sentry_ndk_NativeScope_nativeAddAttachmentBytes(
return;
}

// The returned sentry_attachment_t* is intentionally discarded.
// The returned attachment value is intentionally released immediately.
// We are not tracking it across the JNI boundary for individual removals.
// Use sentry_clear_attachments() for bulk removal.
sentry_attach_bytes((const char *)buf, (size_t)bufLen, charFilename);
sentry_value_decref(
sentry_attach_bytes((const char *)buf, (size_t)bufLen, charFilename));

(*env)->ReleaseStringUTFChars(env, filename, charFilename);
(*env)->ReleaseByteArrayElements(env, data, buf, JNI_ABORT);
Expand Down
42 changes: 18 additions & 24 deletions src/backends/native/sentry_crash_daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,14 @@ write_attachment_to_envelope(int fd, const char *file_path,
static bool
attachment_is_placeholder(const sentry_options_t *options, const char *path)
{
sentry_attachment_t attachment = { 0 };
attachment.path = sentry__path_from_str(path);
if (!attachment.path) {
sentry_value_t attachment
= sentry__attachment_from_path(sentry__path_from_str(path));
if (sentry_value_is_null(attachment)) {
return false;
}
bool is_placeholder
= sentry__attachment_is_placeholder(&attachment, options);
sentry__path_free(attachment.path);
= sentry__attachment_is_placeholder(attachment, options);
sentry_value_decref(attachment);
return is_placeholder;
}

Expand Down Expand Up @@ -280,38 +280,32 @@ add_attachment_refs(sentry_envelope_t *envelope,
SENTRY_WARN("Skipping malformed attachment manifest entry");
continue;
}
sentry_attachment_t attachment = { 0 };
attachment.path = sentry__path_from_str(path);
attachment.filename = sentry__path_from_str(filename);
if (!attachment.path || !attachment.filename) {
sentry_value_t attachment
= sentry__attachment_from_path(sentry__path_from_str(path));
if (sentry_value_is_null(attachment)) {
SENTRY_WARNF("Failed to allocate attachment paths for: %s", path);
sentry__path_free(attachment.path);
sentry__path_free(attachment.filename);
continue;
}
attachment.type
= (char *)((attachment_type && *attachment_type) ? attachment_type
: NULL);
attachment.content_type
= sentry__string_empty(content_type) ? NULL : (char *)content_type;
if (!sentry__attachment_is_placeholder(&attachment, options)) {
sentry__path_free(attachment.path);
sentry__path_free(attachment.filename);
sentry_attachment_set_filename(attachment, filename);
sentry_attachment_set_type(attachment,
(attachment_type && *attachment_type) ? attachment_type : NULL);
sentry_attachment_set_content_type(attachment,
sentry__string_empty(content_type) ? NULL : content_type);
if (!sentry__attachment_is_placeholder(attachment, options)) {
sentry_value_decref(attachment);
continue;
}
if (!materialized && !sentry__envelope_materialize(envelope)) {
SENTRY_WARN("Failed to materialize envelope for attachment-refs");
sentry__path_free(attachment.path);
sentry__path_free(attachment.filename);
sentry_value_decref(attachment);
break;
}
materialized = true;
if (!sentry__cache_attachment_ref(
envelope, &attachment, options->run->cache_path, NULL)) {
envelope, attachment, options->run->cache_path, NULL)) {
SENTRY_WARN("failed to cache attachment-ref");
}
sentry__path_free(attachment.path);
sentry__path_free(attachment.filename);
sentry_value_decref(attachment);
}
sentry_value_decref(list);
}
Expand Down
Loading