From 9a1c0fc8a3c2662b87f6bc0e5bfbcfd96767dfa6 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 28 Mar 2023 16:27:35 +0200 Subject: [PATCH 01/36] feat: provide ptr+len string interfaces --- include/sentry.h | 106 +++++++- src/path/sentry_path_unix.c | 22 +- src/sentry_core.c | 124 +++++++-- src/sentry_envelope.c | 27 +- src/sentry_options.c | 80 ++++++ src/sentry_path.h | 4 + src/sentry_string.h | 36 +++ src/sentry_tracing.c | 494 +++++++++++++++++++++++----------- src/sentry_tracing.h | 10 +- src/sentry_utils.c | 128 ++++----- src/sentry_utils.h | 1 + src/sentry_uuid.c | 10 +- src/sentry_value.c | 237 +++++++++++----- tests/unit/test_attachments.c | 4 +- tests/unit/test_basic.c | 10 +- tests/unit/test_session.c | 6 +- tests/unit/test_tracing.c | 174 ++++++++++++ tests/unit/test_value.c | 112 +++++++- tests/unit/tests.inc | 14 + 19 files changed, 1256 insertions(+), 343 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index 088f81dffc..d038b005e0 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -208,6 +208,9 @@ SENTRY_API sentry_value_t sentry_value_new_bool(int value); */ SENTRY_API sentry_value_t sentry_value_new_string(const char *value); +SENTRY_API sentry_value_t sentry_value_new_string_n( + const char *value, size_t value_len); + /** * Creates a new list value. */ @@ -232,10 +235,15 @@ SENTRY_API sentry_value_type_t sentry_value_get_type(sentry_value_t value); SENTRY_API int sentry_value_set_by_key( sentry_value_t value, const char *k, sentry_value_t v); +SENTRY_API int sentry_value_set_by_key_n( + sentry_value_t value, const char *k, size_t k_len, sentry_value_t v); + /** * This removes a value from the map by key. */ SENTRY_API int sentry_value_remove_by_key(sentry_value_t value, const char *k); +SENTRY_API int sentry_value_remove_by_key_n( + sentry_value_t value, const char *k, size_t k_len); /** * Appends a value to a list. @@ -268,6 +276,8 @@ SENTRY_API int sentry_value_remove_by_index(sentry_value_t value, size_t index); */ SENTRY_API sentry_value_t sentry_value_get_by_key( sentry_value_t value, const char *k); +SENTRY_API sentry_value_t sentry_value_get_by_key_n( + sentry_value_t value, const char *k, size_t k_len); /** * Looks up a value in a map by key. If missing a null value is returned. @@ -278,6 +288,8 @@ SENTRY_API sentry_value_t sentry_value_get_by_key( */ SENTRY_API sentry_value_t sentry_value_get_by_key_owned( sentry_value_t value, const char *k); +SENTRY_API sentry_value_t sentry_value_get_by_key_owned_n( + sentry_value_t value, const char *k, size_t k_len); /** * Looks up a value in a list by index. If missing a null value is returned. @@ -365,6 +377,8 @@ SENTRY_API sentry_value_t sentry_value_new_event(void); */ SENTRY_API sentry_value_t sentry_value_new_message_event( sentry_level_t level, const char *logger, const char *text); +SENTRY_API sentry_value_t sentry_value_new_message_event_n(sentry_level_t level, + const char *logger, size_t logger_len, const char *text, size_t text_len); /** * Creates a new Breadcrumb with a specific type and message. @@ -375,6 +389,8 @@ SENTRY_API sentry_value_t sentry_value_new_message_event( */ SENTRY_API sentry_value_t sentry_value_new_breadcrumb( const char *type, const char *message); +SENTRY_API sentry_value_t sentry_value_new_breadcrumb_n( + const char *type, size_t type_len, const char *message, size_t message_len); /** * Creates a new Exception value. @@ -390,6 +406,8 @@ SENTRY_API sentry_value_t sentry_value_new_breadcrumb( */ SENTRY_EXPERIMENTAL_API sentry_value_t sentry_value_new_exception( const char *type, const char *value); +SENTRY_EXPERIMENTAL_API sentry_value_t sentry_value_new_exception_n( + const char *type, size_t type_len, const char *value, size_t value_len); /** * Creates a new Thread value. @@ -403,6 +421,8 @@ SENTRY_EXPERIMENTAL_API sentry_value_t sentry_value_new_exception( */ SENTRY_EXPERIMENTAL_API sentry_value_t sentry_value_new_thread( uint64_t id, const char *name); +SENTRY_EXPERIMENTAL_API sentry_value_t sentry_value_new_thread_n( + uint64_t id, const char *name, size_t name_len); /** * Creates a new Stack Trace conforming to the Stack Trace Interface. @@ -534,6 +554,8 @@ SENTRY_API sentry_uuid_t sentry_uuid_new_v4(void); * Parses a uuid from a string. */ SENTRY_API sentry_uuid_t sentry_uuid_from_string(const char *str); +SENTRY_API sentry_uuid_t sentry_uuid_from_string_n( + const char *str, size_t str_len); /** * Creates a uuid from bytes. @@ -603,6 +625,8 @@ SENTRY_API char *sentry_envelope_serialize( */ SENTRY_API int sentry_envelope_write_to_file( const sentry_envelope_t *envelope, const char *path); +SENTRY_API int sentry_envelope_write_to_file_n( + const sentry_envelope_t *envelope, const char *path, size_t path_len); /** * The Sentry Client Options. @@ -866,6 +890,8 @@ SENTRY_API void sentry_options_set_on_crash( * Sets the DSN. */ SENTRY_API void sentry_options_set_dsn(sentry_options_t *opts, const char *dsn); +SENTRY_API void sentry_options_set_dsn_n( + sentry_options_t *opts, const char *dsn, size_t dsn_len); /** * Gets the DSN. @@ -903,6 +929,8 @@ SENTRY_API double sentry_options_get_sample_rate(const sentry_options_t *opts); */ SENTRY_API void sentry_options_set_release( sentry_options_t *opts, const char *release); +SENTRY_API void sentry_options_set_release_n( + sentry_options_t *opts, const char *release, size_t release_len); /** * Gets the release. @@ -914,6 +942,8 @@ SENTRY_API const char *sentry_options_get_release(const sentry_options_t *opts); */ SENTRY_API void sentry_options_set_environment( sentry_options_t *opts, const char *environment); +SENTRY_API void sentry_options_set_environment_n( + sentry_options_t *opts, const char *environment, size_t environment_len); /** * Gets the environment. @@ -926,6 +956,8 @@ SENTRY_API const char *sentry_options_get_environment( */ SENTRY_API void sentry_options_set_dist( sentry_options_t *opts, const char *dist); +SENTRY_API void sentry_options_set_dist_n( + sentry_options_t *opts, const char *dist, size_t len); /** * Gets the dist. @@ -939,6 +971,8 @@ SENTRY_API const char *sentry_options_get_dist(const sentry_options_t *opts); */ SENTRY_API void sentry_options_set_http_proxy( sentry_options_t *opts, const char *proxy); +SENTRY_API void sentry_options_set_http_proxy_n( + sentry_options_t *opts, const char *proxy, size_t proxy_len); /** * Returns the configured http proxy. @@ -952,6 +986,8 @@ SENTRY_API const char *sentry_options_get_http_proxy( */ SENTRY_API void sentry_options_set_ca_certs( sentry_options_t *opts, const char *path); +SENTRY_API void sentry_options_set_ca_certs_n( + sentry_options_t *opts, const char *path, size_t path_len); /** * Returns the configured path for ca certificates. @@ -964,6 +1000,8 @@ SENTRY_API const char *sentry_options_get_ca_certs( */ SENTRY_API void sentry_options_set_transport_thread_name( sentry_options_t *opts, const char *name); +SENTRY_API void sentry_options_set_transport_thread_name_n( + sentry_options_t *opts, const char *name, size_t name_len); /** * Returns the configured http transport thread name. @@ -1069,6 +1107,8 @@ SENTRY_API int sentry_options_get_symbolize_stacktraces( */ SENTRY_API void sentry_options_add_attachment( sentry_options_t *opts, const char *path); +SENTRY_API void sentry_options_add_attachment_n( + sentry_options_t *opts, const char *path, size_t path_len); /** * Sets the path to the crashpad handler if the crashpad backend is used. @@ -1086,6 +1126,8 @@ SENTRY_API void sentry_options_add_attachment( */ SENTRY_API void sentry_options_set_handler_path( sentry_options_t *opts, const char *path); +SENTRY_API void sentry_options_set_handler_path_n( + sentry_options_t *opts, const char *path, size_t path_len); /** * Sets the path to the Sentry Database Directory. @@ -1118,6 +1160,8 @@ SENTRY_API void sentry_options_set_handler_path( */ SENTRY_API void sentry_options_set_database_path( sentry_options_t *opts, const char *path); +SENTRY_API void sentry_options_set_database_path_n( + sentry_options_t *opts, const char *path, size_t path_len); #ifdef SENTRY_PLATFORM_WINDOWS /** @@ -1125,18 +1169,23 @@ SENTRY_API void sentry_options_set_database_path( */ SENTRY_API void sentry_options_add_attachmentw( sentry_options_t *opts, const wchar_t *path); - +SENTRY_API void sentry_options_add_attachmentw_n( + sentry_options_t *opts, const wchar_t *path, size_t path_len); /** * Wide char version of `sentry_options_set_handler_path`. */ SENTRY_API void sentry_options_set_handler_pathw( sentry_options_t *opts, const wchar_t *path); +SENTRY_API void sentry_options_set_handler_pathw_n( + sentry_options_t *opts, const wchar_t *path, size_t path_len); /** * Wide char version of `sentry_options_set_database_path`. */ SENTRY_API void sentry_options_set_database_pathw( sentry_options_t *opts, const wchar_t *path); +SENTRY_API void sentry_options_set_database_pathw_n( + sentry_options_t *opts, const wchar_t *path, size_t path_len); #endif /** @@ -1297,31 +1346,40 @@ SENTRY_API void sentry_remove_user(void); * Sets a tag. */ SENTRY_API void sentry_set_tag(const char *key, const char *value); +SENTRY_API void sentry_set_tag_n( + const char *key, size_t key_len, const char *value, size_t value_len); /** * Removes the tag with the specified key. */ SENTRY_API void sentry_remove_tag(const char *key); +SENTRY_API void sentry_remove_tag_n(const char *key, size_t key_len); /** * Sets extra information. */ SENTRY_API void sentry_set_extra(const char *key, sentry_value_t value); +SENTRY_API void sentry_set_extra_n( + const char *key, size_t key_len, sentry_value_t value); /** * Removes the extra with the specified key. */ SENTRY_API void sentry_remove_extra(const char *key); +SENTRY_API void sentry_remove_extra_n(const char *key, size_t key_len); /** * Sets a context object. */ SENTRY_API void sentry_set_context(const char *key, sentry_value_t value); +SENTRY_API void sentry_set_context_n( + const char *key, size_t key_len, sentry_value_t value); /** * Removes the context object with the specified key. */ SENTRY_API void sentry_remove_context(const char *key); +SENTRY_API void sentry_remove_context_n(const char *key, size_t key_len); /** * Sets the event fingerprint. @@ -1330,6 +1388,8 @@ SENTRY_API void sentry_remove_context(const char *key); * trailing `NULL`. */ SENTRY_API void sentry_set_fingerprint(const char *fingerprint, ...); +SENTRY_API void sentry_set_fingerprint_n( + const char *fingerprint, size_t fingerprint_len, ...); /** * Removes the fingerprint. @@ -1340,6 +1400,8 @@ SENTRY_API void sentry_remove_fingerprint(void); * Sets the transaction. */ SENTRY_API void sentry_set_transaction(const char *transaction); +SENTRY_API void sentry_set_transaction_n( + const char *transaction, size_t transaction_len); /** * Sets the event level. @@ -1448,6 +1510,9 @@ typedef struct sentry_span_s sentry_span_t; */ SENTRY_EXPERIMENTAL_API sentry_transaction_context_t * sentry_transaction_context_new(const char *name, const char *operation); +SENTRY_EXPERIMENTAL_API sentry_transaction_context_t * +sentry_transaction_context_new_n(const char *name, size_t name_len, + const char *operation, size_t operation_len); /** * Sets the `name` on a Transaction Context, which will be used in the @@ -1458,6 +1523,8 @@ sentry_transaction_context_new(const char *name, const char *operation); */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name( sentry_transaction_context_t *tx_cxt, const char *name); +SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name_n( + sentry_transaction_context_t *tx_cxt, const char *name, size_t name_len); /** * Sets the `operation` on a Transaction Context, which will be used in the @@ -1471,6 +1538,9 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_name( */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation( sentry_transaction_context_t *tx_cxt, const char *operation); +SENTRY_EXPERIMENTAL_API void sentry_transaction_context_set_operation_n( + sentry_transaction_context_t *tx_cxt, const char *operation, + size_t operation_len); /** * Sets the `sampled` field on a Transaction Context, which will be used in the @@ -1508,6 +1578,9 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_remove_sampled( */ SENTRY_EXPERIMENTAL_API void sentry_transaction_context_update_from_header( sentry_transaction_context_t *tx_cxt, const char *key, const char *value); +SENTRY_EXPERIMENTAL_API void sentry_transaction_context_update_from_header_n( + sentry_transaction_context_t *tx_cxt, const char *key, size_t key_len, + const char *value, size_t value_len); /** * Starts a new Transaction based on the provided context, restored from an @@ -1618,7 +1691,11 @@ SENTRY_EXPERIMENTAL_API void sentry_set_span(sentry_span_t *span); * in a thread-safe way. */ SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_transaction_start_child( - sentry_transaction_t *parent, char *operation, char *description); + sentry_transaction_t *parent, const char *operation, + const char *description); +SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_transaction_start_child_n( + sentry_transaction_t *parent, const char *operation, size_t operation_len, + const char *description, size_t description_len); /** * Starts a new Span. @@ -1651,7 +1728,10 @@ SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_transaction_start_child( * in a thread-safe way. */ SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_span_start_child( - sentry_span_t *parent, char *operation, char *description); + sentry_span_t *parent, const char *operation, const char *description); +SENTRY_EXPERIMENTAL_API sentry_span_t *sentry_span_start_child_n( + sentry_span_t *parent, const char *operation, size_t operation_len, + const char *description, size_t description_len); /** * Finishes a Span. @@ -1675,6 +1755,9 @@ SENTRY_EXPERIMENTAL_API void sentry_span_finish(sentry_span_t *span); */ SENTRY_EXPERIMENTAL_API void sentry_transaction_set_tag( sentry_transaction_t *transaction, const char *tag, const char *value); +SENTRY_EXPERIMENTAL_API void sentry_transaction_set_tag_n( + sentry_transaction_t *transaction, const char *tag, size_t tag_len, + const char *value, size_t value_len); /** * Removes a tag from a Transaction. @@ -1684,6 +1767,8 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_set_tag( */ SENTRY_EXPERIMENTAL_API void sentry_transaction_remove_tag( sentry_transaction_t *transaction, const char *tag); +SENTRY_EXPERIMENTAL_API void sentry_transaction_remove_tag_n( + sentry_transaction_t *transaction, const char *tag, size_t tag_len); /** * Sets the given key in a Transaction's "data" section to the given value. @@ -1693,6 +1778,9 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_remove_tag( */ SENTRY_EXPERIMENTAL_API void sentry_transaction_set_data( sentry_transaction_t *transaction, const char *key, sentry_value_t value); +SENTRY_EXPERIMENTAL_API void sentry_transaction_set_data_n( + sentry_transaction_t *transaction, const char *key, size_t key_len, + sentry_value_t value); /** * Removes a key from a Transaction's "data" section. @@ -1702,6 +1790,8 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_set_data( */ SENTRY_EXPERIMENTAL_API void sentry_transaction_remove_data( sentry_transaction_t *transaction, const char *key); +SENTRY_EXPERIMENTAL_API void sentry_transaction_remove_data_n( + sentry_transaction_t *transaction, const char *key, size_t key_len); /** * Sets a tag on a Span to the given string value. @@ -1713,6 +1803,8 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_remove_data( */ SENTRY_EXPERIMENTAL_API void sentry_span_set_tag( sentry_span_t *span, const char *tag, const char *value); +SENTRY_EXPERIMENTAL_API void sentry_span_set_tag_n(sentry_span_t *span, + const char *tag, size_t tag_len, const char *value, size_t value_len); /** * Removes a tag from a Span. @@ -1722,6 +1814,8 @@ SENTRY_EXPERIMENTAL_API void sentry_span_set_tag( */ SENTRY_EXPERIMENTAL_API void sentry_span_remove_tag( sentry_span_t *span, const char *tag); +SENTRY_EXPERIMENTAL_API void sentry_span_remove_tag_n( + sentry_span_t *span, const char *tag, size_t tag_len); /** * Sets the given key in a Span's "data" section to the given value. @@ -1731,6 +1825,8 @@ SENTRY_EXPERIMENTAL_API void sentry_span_remove_tag( */ SENTRY_EXPERIMENTAL_API void sentry_span_set_data( sentry_span_t *span, const char *key, sentry_value_t value); +SENTRY_EXPERIMENTAL_API void sentry_span_set_data_n( + sentry_span_t *span, const char *key, size_t key_len, sentry_value_t value); /** * Removes a key from a Span's "data" section. @@ -1740,6 +1836,8 @@ SENTRY_EXPERIMENTAL_API void sentry_span_set_data( */ SENTRY_EXPERIMENTAL_API void sentry_span_remove_data( sentry_span_t *span, const char *key); +SENTRY_EXPERIMENTAL_API void sentry_span_remove_data_n( + sentry_span_t *span, const char *key, size_t key_len); /** * Sets a Transaction's name. @@ -1749,6 +1847,8 @@ SENTRY_EXPERIMENTAL_API void sentry_span_remove_data( */ SENTRY_EXPERIMENTAL_API void sentry_transaction_set_name( sentry_transaction_t *transaction, const char *name); +SENTRY_EXPERIMENTAL_API void sentry_transaction_set_name_n( + sentry_transaction_t *transaction, const char *name, size_t name_len); /** * The status of a Span or Transaction. diff --git a/src/path/sentry_path_unix.c b/src/path/sentry_path_unix.c index d75a0eb8f1..063ed0b0de 100644 --- a/src/path/sentry_path_unix.c +++ b/src/path/sentry_path_unix.c @@ -168,16 +168,20 @@ sentry__path_dir(const sentry_path_t *path) return sentry__path_from_str_owned(newpathbuf); } -sentry_path_t * -sentry__path_from_str(const char *s) -{ - char *path = sentry__string_clone(s); - if (!path) { - return NULL; +#define GEN_SENTRY__PATH_FROM_STR(FN, GEN_STR_PARAM, STR_CLONE_FN) \ + sentry_path_t *FN(GEN_STR_PARAM(s)) \ + { \ + char *path = STR_CLONE_FN(s); \ + if (!path) { \ + return NULL; \ + } \ + /* NOTE: function will free `path` on error */ \ + return sentry__path_from_str_owned(path); \ } - // NOTE: function will free `path` on error - return sentry__path_from_str_owned(path); -} +GEN_SENTRY__PATH_FROM_STR(sentry__path_from_str_n, PTR_LEN_PARAM_FROM_NAME, + CALL_SENTRY__STRING_CLONE_N) +GEN_SENTRY__PATH_FROM_STR( + sentry__path_from_str, STR_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE) sentry_path_t * sentry__path_from_str_owned(char *s) diff --git a/src/sentry_core.c b/src/sentry_core.c index b10d6065df..a6547d07ba 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1,10 +1,8 @@ #include "sentry_boot.h" #include -#include #include -#include "sentry_alloc.h" #include "sentry_backend.h" #include "sentry_core.h" #include "sentry_database.h" @@ -640,6 +638,16 @@ sentry_set_tag(const char *key, const char *value) } } +void +sentry_set_tag_n( + const char *key, size_t key_len, const char *value, size_t value_len) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_value_set_by_key_n(scope->tags, key, key_len, + sentry_value_new_string_n(value, value_len)); + } +} + void sentry_remove_tag(const char *key) { @@ -648,6 +656,14 @@ sentry_remove_tag(const char *key) } } +void +sentry_remove_tag_n(const char *key, size_t key_len) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_value_remove_by_key_n(scope->tags, key, key_len); + } +} + void sentry_set_extra(const char *key, sentry_value_t value) { @@ -656,6 +672,14 @@ sentry_set_extra(const char *key, sentry_value_t value) } } +void +sentry_set_extra_n(const char *key, size_t key_len, sentry_value_t value) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_value_set_by_key_n(scope->extra, key, key_len, value); + } +} + void sentry_remove_extra(const char *key) { @@ -664,6 +688,14 @@ sentry_remove_extra(const char *key) } } +void +sentry_remove_extra_n(const char *key, size_t key_len) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_value_remove_by_key_n(scope->extra, key, key_len); + } +} + void sentry_set_context(const char *key, sentry_value_t value) { @@ -672,6 +704,14 @@ sentry_set_context(const char *key, sentry_value_t value) } } +void +sentry_set_context_n(const char *key, size_t key_len, sentry_value_t value) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_value_set_by_key_n(scope->contexts, key, key_len, value); + } +} + void sentry_remove_context(const char *key) { @@ -680,6 +720,14 @@ sentry_remove_context(const char *key) } } +void +sentry_remove_context_n(const char *key, size_t key_len) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_value_remove_by_key_n(scope->contexts, key, key_len); + } +} + void sentry_set_fingerprint(const char *fingerprint, ...) { @@ -696,7 +744,7 @@ sentry_set_fingerprint(const char *fingerprint, ...) SENTRY_WITH_SCOPE_MUT (scope) { sentry_value_decref(scope->fingerprint); scope->fingerprint = fingerprint_value; - }; + } } void @@ -705,7 +753,7 @@ sentry_remove_fingerprint(void) SENTRY_WITH_SCOPE_MUT (scope) { sentry_value_decref(scope->fingerprint); scope->fingerprint = sentry_value_new_null(); - }; + } } void @@ -721,6 +769,21 @@ sentry_set_transaction(const char *transaction) } } +void +sentry_set_transaction_n(const char *transaction, size_t transaction_len) +{ + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_free(scope->transaction); + scope->transaction + = sentry__string_clonen_or_null(transaction, transaction_len); + + if (scope->transaction_object) { + sentry_transaction_set_name_n( + scope->transaction_object, transaction, transaction_len); + } + } +} + void sentry_set_level(sentry_level_t level) { @@ -869,31 +932,37 @@ sentry_set_span(sentry_span_t *span) } } -sentry_span_t * -sentry_transaction_start_child( - sentry_transaction_t *opaque_parent, char *operation, char *description) -{ - if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) { - SENTRY_DEBUG("no transaction available to create a child under"); - return NULL; - } - sentry_value_t parent = opaque_parent->inner; - - // TODO: consider snapshotting this value during tx creation and storing in - // tx and span - size_t max_spans = SENTRY_SPANS_MAX; - SENTRY_WITH_OPTIONS (options) { - max_spans = options->max_spans; - } - - sentry_value_t span - = sentry__value_span_new(max_spans, parent, operation, description); - return sentry__span_new(opaque_parent, span); -} +#define GEN_SENTRY_TRANSACTION_START_CHILD( \ + FN, STR_PARAM_GEN, NEW_SPAN_VALUE_FN) \ + sentry_span_t *FN(sentry_transaction_t *opaque_parent, \ + STR_PARAM_GEN(operation), STR_PARAM_GEN(description)) \ + { \ + if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) { \ + SENTRY_DEBUG("no transaction available to create a child under"); \ + return NULL; \ + } \ + sentry_value_t parent = opaque_parent->inner; \ + \ + /* TODO: consider snapshotting this value during tx creation and \ + * storing in tx and span */ \ + size_t max_spans = SENTRY_SPANS_MAX; \ + SENTRY_WITH_OPTIONS (options) { \ + max_spans = options->max_spans; \ + } \ + \ + sentry_value_t span \ + = NEW_SPAN_VALUE_FN(max_spans, parent, operation, description); \ + return sentry__span_new(opaque_parent, span); \ + } + +GEN_SENTRY_TRANSACTION_START_CHILD(sentry_transaction_start_child, + STR_PARAM_FROM_NAME, CALL_SENTRY__VALUE_SPAN_NEW) +GEN_SENTRY_TRANSACTION_START_CHILD(sentry_transaction_start_child_n, + PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__VALUE_SPAN_NEW_N) sentry_span_t * -sentry_span_start_child( - sentry_span_t *opaque_parent, char *operation, char *description) +sentry_span_start_child(sentry_span_t *opaque_parent, const char *operation, + const char *description) { if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) { SENTRY_DEBUG("no parent span available to create a child span under"); @@ -1010,7 +1079,6 @@ sentry_span_finish(sentry_span_t *opaque_span) fail: sentry__span_decref(opaque_span); - return; } int diff --git a/src/sentry_envelope.c b/src/sentry_envelope.c index cfcf5af824..3cab2cd20f 100644 --- a/src/sentry_envelope.c +++ b/src/sentry_envelope.c @@ -458,18 +458,21 @@ sentry_envelope_write_to_path( return rv; } -int -sentry_envelope_write_to_file( - const sentry_envelope_t *envelope, const char *path) -{ - sentry_path_t *path_obj = sentry__path_from_str(path); - - int rv = sentry_envelope_write_to_path(envelope, path_obj); - - sentry__path_free(path_obj); - - return rv; -} +#define GEN_SENTRY_ENVELOPE_WRITE_TO_FILE(FN, GEN_STR_PARAM, PATH_FROM_STR_FN) \ + int FN(const sentry_envelope_t *envelope, GEN_STR_PARAM(path)) \ + { \ + sentry_path_t *path_obj = PATH_FROM_STR_FN(path); \ + \ + int rv = sentry_envelope_write_to_path(envelope, path_obj); \ + \ + sentry__path_free(path_obj); \ + \ + return rv; \ + } +GEN_SENTRY_ENVELOPE_WRITE_TO_FILE(sentry_envelope_write_to_file_n, + PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__PATH_FROM_STR_N) +GEN_SENTRY_ENVELOPE_WRITE_TO_FILE(sentry_envelope_write_to_file, + STR_PARAM_FROM_NAME, CALL_SENTRY__PATH_FROM_STR) #ifdef SENTRY_UNITTEST size_t diff --git a/src/sentry_options.c b/src/sentry_options.c index b0a6fe8aa6..fa32bf3c41 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -130,6 +130,14 @@ sentry_options_set_on_crash( opts->on_crash_data = data; } +void +sentry_options_set_dsn_n( + sentry_options_t *opts, const char *raw_dsn, size_t raw_dsn_len) +{ + sentry__dsn_decref(opts->dsn); + opts->dsn = sentry__dsn_new_n(raw_dsn, raw_dsn_len); +} + void sentry_options_set_dsn(sentry_options_t *opts, const char *raw_dsn) { @@ -160,6 +168,14 @@ sentry_options_get_sample_rate(const sentry_options_t *opts) return opts->sample_rate; } +void +sentry_options_set_release_n( + sentry_options_t *opts, const char *release, size_t release_len) +{ + sentry_free(opts->release); + opts->release = sentry__string_clonen_or_null(release, release_len); +} + void sentry_options_set_release(sentry_options_t *opts, const char *release) { @@ -173,6 +189,15 @@ sentry_options_get_release(const sentry_options_t *opts) return opts->release; } +void +sentry_options_set_environment_n( + sentry_options_t *opts, const char *environment, size_t environment_len) +{ + sentry_free(opts->environment); + opts->environment + = sentry__string_clonen_or_null(environment, environment_len); +} + void sentry_options_set_environment(sentry_options_t *opts, const char *environment) { @@ -186,6 +211,14 @@ sentry_options_get_environment(const sentry_options_t *opts) return opts->environment; } +void +sentry_options_set_dist_n( + sentry_options_t *opts, const char *dist, size_t dist_len) +{ + sentry_free(opts->dist); + opts->dist = sentry__string_clonen_or_null(dist, dist_len); +} + void sentry_options_set_dist(sentry_options_t *opts, const char *dist) { @@ -199,6 +232,14 @@ sentry_options_get_dist(const sentry_options_t *opts) return opts->dist; } +void +sentry_options_set_http_proxy_n( + sentry_options_t *opts, const char *proxy, size_t proxy_len) +{ + sentry_free(opts->http_proxy); + opts->http_proxy = sentry__string_clonen_or_null(proxy, proxy_len); +} + void sentry_options_set_http_proxy(sentry_options_t *opts, const char *proxy) { @@ -219,6 +260,14 @@ sentry_options_set_ca_certs(sentry_options_t *opts, const char *path) opts->ca_certs = sentry__string_clone(path); } +void +sentry_options_set_ca_certs_n( + sentry_options_t *opts, const char *path, size_t path_len) +{ + sentry_free(opts->ca_certs); + opts->ca_certs = sentry__string_clonen(path, path_len); +} + const char * sentry_options_get_ca_certs(const sentry_options_t *opts) { @@ -233,6 +282,14 @@ sentry_options_set_transport_thread_name( opts->transport_thread_name = sentry__string_clone(name); } +void +sentry_options_set_transport_thread_name_n( + sentry_options_t *opts, const char *name, size_t name_len) +{ + sentry_free(opts->transport_thread_name); + opts->transport_thread_name = sentry__string_clonen_or_null(name, name_len); +} + const char * sentry_options_get_transport_thread_name(const sentry_options_t *opts) { @@ -350,6 +407,13 @@ sentry_options_add_attachment(sentry_options_t *opts, const char *path) add_attachment(opts, sentry__path_from_str(path)); } +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)); +} + void sentry_options_set_handler_path(sentry_options_t *opts, const char *path) { @@ -357,6 +421,14 @@ sentry_options_set_handler_path(sentry_options_t *opts, const char *path) opts->handler_path = sentry__path_from_str(path); } +void +sentry_options_set_handler_path_n( + sentry_options_t *opts, const char *path, size_t path_len) +{ + sentry__path_free(opts->handler_path); + opts->handler_path = sentry__path_from_str_n(path, path_len); +} + void sentry_options_set_database_path(sentry_options_t *opts, const char *path) { @@ -364,6 +436,14 @@ sentry_options_set_database_path(sentry_options_t *opts, const char *path) opts->database_path = sentry__path_from_str(path); } +void +sentry_options_set_database_path_n( + sentry_options_t *opts, const char *path, size_t path_len) +{ + sentry__path_free(opts->database_path); + opts->database_path = sentry__path_from_str_n(path, path_len); +} + #ifdef SENTRY_PLATFORM_WINDOWS void sentry_options_add_attachmentw(sentry_options_t *opts, const wchar_t *path) diff --git a/src/sentry_path.h b/src/sentry_path.h index 8cedd1d213..d108c3735e 100644 --- a/src/sentry_path.h +++ b/src/sentry_path.h @@ -53,6 +53,10 @@ sentry_path_t *sentry__path_dir(const sentry_path_t *path); * Create a new path from the given string. */ sentry_path_t *sentry__path_from_str(const char *s); +sentry_path_t *sentry__path_from_str_n(const char *s, size_t s_len); +#define CALL_SENTRY__PATH_FROM_STR(STR) sentry__path_from_str(STR) +#define CALL_SENTRY__PATH_FROM_STR_N(STR) \ + sentry__path_from_str_n(STR, STR##_len) /** * Create a new path from the given string. diff --git a/src/sentry_string.h b/src/sentry_string.h index 255d55d171..72708a7d55 100644 --- a/src/sentry_string.h +++ b/src/sentry_string.h @@ -7,6 +7,15 @@ #include #include +#define STR_PARAM_FROM_NAME(NAME) const char *NAME +#define PTR_LEN_PARAM_FROM_NAME(NAME) \ + STR_PARAM_FROM_NAME(NAME), size_t NAME##_len +#define CALL_SENTRY__STRING_CLONE_N(STR) \ + sentry__string_clonen_or_null(STR, STR##_len) +#define CALL_SENTRY__STRING_CLONE(STR) sentry__string_clone(STR) +#define CALL_SENTRY_VALUE_NEW_STRING(STR) sentry_value_new_string(STR) +#define CALL_SENTRY_VALUE_NEW_STRING_N(STR) \ + sentry_value_new_string_n(STR, STR##_len) /** * A string builder, which can be used as a mutable, growable string buffer. */ @@ -124,6 +133,12 @@ sentry__string_clonen(const char *str, size_t n) return rv; } +static inline char * +sentry__string_clonen_or_null(const char *str, size_t n) +{ + return str ? sentry__string_clonen(str, n) : NULL; +} + /** * Duplicates a zero terminated string. */ @@ -133,6 +148,27 @@ sentry__string_clone(const char *str) return str ? sentry__string_clonen(str, strlen(str)) : NULL; } +static inline char * +sentry__string_clone_max(const char *str, size_t max_len) +{ + if (!str) { + return NULL; + } + size_t str_len = strlen(str); + size_t min_len = str_len < max_len ? str_len : max_len; + return sentry__string_clonen(str, min_len); +} + +static inline char * +sentry__string_clone_max_n(const char *str, size_t str_len, size_t max_len) +{ + if (!str) { + return NULL; + } + size_t min_len = str_len < max_len ? str_len : max_len; + return sentry__string_clonen(str, min_len); +} + /** * Converts a string to lowercase. */ diff --git a/src/sentry_tracing.c b/src/sentry_tracing.c index 9b9139a175..bdd64abea2 100644 --- a/src/sentry_tracing.c +++ b/src/sentry_tracing.c @@ -6,64 +6,91 @@ #include "sentry_value.h" #include -sentry_value_t -sentry__value_new_span(sentry_value_t parent, const char *operation) -{ - sentry_value_t span = sentry_value_new_object(); - - sentry_value_set_by_key(span, "op", sentry_value_new_string(operation)); - - sentry_uuid_t span_id = sentry_uuid_new_v4(); - sentry_value_set_by_key( - span, "span_id", sentry__value_new_span_uuid(&span_id)); - - sentry_value_set_by_key(span, "status", sentry_value_new_string("ok")); - - if (!sentry_value_is_null(parent)) { - sentry_value_set_by_key(span, "trace_id", - sentry_value_get_by_key_owned(parent, "trace_id")); - sentry_value_set_by_key(span, "parent_span_id", - sentry_value_get_by_key_owned(parent, "span_id")); - sentry_value_set_by_key( - span, "sampled", sentry_value_get_by_key_owned(parent, "sampled")); - } - - return span; -} - -sentry_value_t -sentry__value_transaction_context_new(const char *name, const char *operation) -{ - sentry_value_t transaction_context - = sentry__value_new_span(sentry_value_new_null(), operation); - - sentry_uuid_t trace_id = sentry_uuid_new_v4(); - sentry_value_set_by_key(transaction_context, "trace_id", - sentry__value_new_internal_uuid(&trace_id)); - - sentry_value_set_by_key( - transaction_context, "transaction", sentry_value_new_string(name)); - - return transaction_context; -} - -sentry_transaction_context_t * -sentry_transaction_context_new(const char *name, const char *operation) -{ - sentry_transaction_context_t *tx_cxt - = SENTRY_MAKE(sentry_transaction_context_t); - if (!tx_cxt) { - return NULL; - } - tx_cxt->inner = sentry__value_transaction_context_new(name, operation); - - if (sentry_value_is_null(tx_cxt->inner)) { - sentry_free(tx_cxt); - return NULL; +#define GEN_SENTRY__VALUE_NEW_SPAN(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ + sentry_value_t FN(sentry_value_t parent, GEN_STR_PARAM(operation)) \ + { \ + sentry_value_t span = sentry_value_new_object(); \ + \ + sentry_value_set_by_key(span, "op", VALUE_NEW_STR_FN(operation)); \ + \ + sentry_uuid_t span_id = sentry_uuid_new_v4(); \ + sentry_value_set_by_key( \ + span, "span_id", sentry__value_new_span_uuid(&span_id)); \ + \ + sentry_value_set_by_key( \ + span, "status", sentry_value_new_string("ok")); \ + \ + if (!sentry_value_is_null(parent)) { \ + sentry_value_set_by_key(span, "trace_id", \ + sentry_value_get_by_key_owned(parent, "trace_id")); \ + sentry_value_set_by_key(span, "parent_span_id", \ + sentry_value_get_by_key_owned(parent, "span_id")); \ + sentry_value_set_by_key(span, "sampled", \ + sentry_value_get_by_key_owned(parent, "sampled")); \ + } \ + \ + return span; \ + } + +GEN_SENTRY__VALUE_NEW_SPAN(sentry__value_new_span_n, PTR_LEN_PARAM_FROM_NAME, + CALL_SENTRY_VALUE_NEW_STRING_N) +GEN_SENTRY__VALUE_NEW_SPAN( + sentry__value_new_span, STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) +#define CALL_SENTRY__VALUE_NEW_SPAN_N(VAL, STR) \ + sentry__value_new_span_n(VAL, STR, STR##_len) +#define CALL_SENTRY__VALUE_NEW_SPAN(VAL, STR) sentry__value_new_span(VAL, STR) + +#define GEN_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW( \ + FN, GEN_STR_PARAM, NEW_SPAN_VALUE_FUN, NEW_STR_VALUE_FUN) \ + sentry_value_t FN(GEN_STR_PARAM(name), GEN_STR_PARAM(operation)) \ + { \ + sentry_value_t transaction_context \ + = NEW_SPAN_VALUE_FUN(sentry_value_new_null(), operation); \ + \ + sentry_uuid_t trace_id = sentry_uuid_new_v4(); \ + sentry_value_set_by_key(transaction_context, "trace_id", \ + sentry__value_new_internal_uuid(&trace_id)); \ + \ + sentry_value_set_by_key(transaction_context, "transaction", \ + sentry_value_new_string(name)); \ + \ + return transaction_context; \ + } + +GEN_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW( + sentry__value_transaction_context_new_n, PTR_LEN_PARAM_FROM_NAME, + CALL_SENTRY__VALUE_NEW_SPAN_N, CALL_SENTRY_VALUE_NEW_STRING_N) +GEN_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW(sentry__value_transaction_context_new, + STR_PARAM_FROM_NAME, CALL_SENTRY__VALUE_NEW_SPAN, + CALL_SENTRY_VALUE_NEW_STRING) +#define CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW_N(NAME, OP) \ + sentry__value_transaction_context_new_n(NAME, NAME##_len, OP, OP##_len) +#define CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW(NAME, OP) \ + sentry__value_transaction_context_new(NAME, OP) + +#define GEN_SENTRY_TRANSACTION_CONTEXT_NEW(FN, GEN_STR_PARAM, NEW_TXN_CTX_FN) \ + sentry_transaction_context_t *FN( \ + GEN_STR_PARAM(name), GEN_STR_PARAM(operation)) \ + { \ + sentry_transaction_context_t *tx_cxt \ + = SENTRY_MAKE(sentry_transaction_context_t); \ + if (!tx_cxt) { \ + return NULL; \ + } \ + tx_cxt->inner = NEW_TXN_CTX_FN(name, operation); \ + \ + if (sentry_value_is_null(tx_cxt->inner)) { \ + sentry_free(tx_cxt); \ + return NULL; \ + } \ + \ + return tx_cxt; \ } - return tx_cxt; -} +GEN_SENTRY_TRANSACTION_CONTEXT_NEW(sentry_transaction_context_new_n, + PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW_N) +GEN_SENTRY_TRANSACTION_CONTEXT_NEW(sentry_transaction_context_new, + STR_PARAM_FROM_NAME, CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW) void sentry__transaction_context_free(sentry_transaction_context_t *tx_cxt) @@ -76,7 +103,7 @@ sentry__transaction_context_free(sentry_transaction_context_t *tx_cxt) sentry_free(tx_cxt); } else { sentry_value_decref(tx_cxt->inner); - }; + } } void @@ -89,6 +116,16 @@ sentry_transaction_context_set_name( } } +void +sentry_transaction_context_set_name_n( + sentry_transaction_context_t *tx_cxt, const char *name, size_t name_len) +{ + if (tx_cxt) { + sentry_value_set_by_key(tx_cxt->inner, "transaction", + sentry_value_new_string_n(name, name_len)); + } +} + void sentry_transaction_context_set_operation( sentry_transaction_context_t *tx_cxt, const char *operation) @@ -99,6 +136,16 @@ sentry_transaction_context_set_operation( } } +void +sentry_transaction_context_set_operation_n(sentry_transaction_context_t *tx_cxt, + const char *operation, size_t operation_len) +{ + if (tx_cxt) { + sentry_value_set_by_key(tx_cxt->inner, "op", + sentry_value_new_string_n(operation, operation_len)); + } +} + void sentry_transaction_context_set_sampled( sentry_transaction_context_t *tx_cxt, int sampled) @@ -117,54 +164,67 @@ sentry_transaction_context_remove_sampled(sentry_transaction_context_t *tx_cxt) } } -void -sentry_transaction_context_update_from_header( - sentry_transaction_context_t *tx_cxt, const char *key, const char *value) -{ - if (!tx_cxt) { - return; - } - - // do case-insensitive header key comparison - const char sentry_trace[] = "sentry-trace"; - for (size_t i = 0; i < sizeof(sentry_trace); i++) { - if (tolower(key[i]) != sentry_trace[i]) { - return; - } - } - - // https://develop.sentry.dev/sdk/performance/#header-sentry-trace - // sentry-trace = traceid-spanid(-sampled)? - const char *trace_id_start = value; - const char *trace_id_end = strchr(trace_id_start, '-'); - if (!trace_id_end) { - return; - } - - sentry_value_t inner = tx_cxt->inner; - - char *s - = sentry__string_clonen(trace_id_start, trace_id_end - trace_id_start); - sentry_value_t trace_id = sentry__value_new_string_owned(s); - sentry_value_set_by_key(inner, "trace_id", trace_id); - - const char *span_id_start = trace_id_end + 1; - const char *span_id_end = strchr(span_id_start, '-'); - if (!span_id_end) { - // no sampled flag - sentry_value_t parent_span_id = sentry_value_new_string(span_id_start); - sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); - return; - } - // else: we have a sampled flag - - s = sentry__string_clonen(span_id_start, span_id_end - span_id_start); - sentry_value_t parent_span_id = sentry__value_new_string_owned(s); - sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); - - bool sampled = *(span_id_end + 1) == '1'; - sentry_value_set_by_key(inner, "sampled", sentry_value_new_bool(sampled)); -} +#define GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( \ + FN, GEN_STR_PARAM, STR_CHR_FN) \ + void FN(sentry_transaction_context_t *tx_cxt, GEN_STR_PARAM(key), \ + GEN_STR_PARAM(value)) \ + { \ + if (!tx_cxt) { \ + return; \ + } \ + \ + /* do case-insensitive header key comparison */ \ + const char sentry_trace[] = "sentry-trace"; \ + for (size_t i = 0; i < sizeof(sentry_trace); i++) { \ + if (tolower(key[i]) != sentry_trace[i]) { \ + return; \ + } \ + } \ + \ + /* https://develop.sentry.dev/sdk/performance/#header-sentry-trace \ + * sentry-trace = traceid-spanid(-sampled)? \ + */ \ + const char *trace_id_start = value; \ + const char *trace_id_end = STR_CHR_FN(trace_id_start, '-'); \ + if (!trace_id_end) { \ + return; \ + } \ + \ + sentry_value_t inner = tx_cxt->inner; \ + \ + char *s = sentry__string_clonen( \ + trace_id_start, trace_id_end - trace_id_start); \ + sentry_value_t trace_id = sentry__value_new_string_owned(s); \ + sentry_value_set_by_key(inner, "trace_id", trace_id); \ + \ + const char *span_id_start = trace_id_end + 1; \ + const char *span_id_end = strchr(span_id_start, '-'); \ + if (!span_id_end) { \ + /* no sampled flag */ \ + sentry_value_t parent_span_id \ + = sentry_value_new_string(span_id_start); \ + sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); \ + return; \ + } \ + /* else: we have a sampled flag */ \ + \ + s = sentry__string_clonen(span_id_start, span_id_end - span_id_start); \ + sentry_value_t parent_span_id = sentry__value_new_string_owned(s); \ + sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); \ + \ + bool sampled = *(span_id_end + 1) == '1'; \ + sentry_value_set_by_key( \ + inner, "sampled", sentry_value_new_bool(sampled)); \ + } + +#define CALL_STR_CHR(STR, CHR) strchr(STR, CHR) +#define CALL_MEM_CHR(STR, CHR) memchr(STR, value_len, CHR) +GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( + sentry_transaction_context_update_from_header_n, PTR_LEN_PARAM_FROM_NAME, + CALL_MEM_CHR) +GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( + sentry_transaction_context_update_from_header, STR_PARAM_FROM_NAME, + CALL_STR_CHR) sentry_transaction_t * sentry__transaction_new(sentry_value_t inner) @@ -203,7 +263,7 @@ sentry__transaction_decref(sentry_transaction_t *tx) sentry_free(tx); } else { sentry_value_decref(tx->inner); - }; + } } void @@ -227,7 +287,7 @@ sentry__span_decref(sentry_span_t *span) sentry_free(span); } else { sentry_value_decref(span->inner); - }; + } } sentry_span_t * @@ -250,36 +310,45 @@ sentry__span_new(sentry_transaction_t *tx, sentry_value_t inner) return span; } -sentry_value_t -sentry__value_span_new( - size_t max_spans, sentry_value_t parent, char *operation, char *description) -{ - if (!sentry_value_is_null(sentry_value_get_by_key(parent, "timestamp"))) { - SENTRY_DEBUG("span's parent is already finished, not creating span"); - goto fail; - } - - sentry_value_t spans = sentry_value_get_by_key(parent, "spans"); - // This only checks that the number of _completed_ spans matches the - // number of max spans. This means that the number of in-flight spans - // can exceed the max number of spans. - if (sentry_value_get_length(spans) >= max_spans) { - SENTRY_DEBUG("reached maximum number of spans for transaction, not " - "creating span"); - goto fail; - } - - sentry_value_t child = sentry__value_new_span(parent, operation); - sentry_value_set_by_key( - child, "description", sentry_value_new_string(description)); - sentry_value_set_by_key(child, "start_timestamp", - sentry__value_new_string_owned( - sentry__msec_time_to_iso8601(sentry__msec_time()))); - - return child; -fail: - return sentry_value_new_null(); -} +#define GEN_SENTRY__VALUE_SPAN_NEW( \ + FN, GEN_STR_PARAM, VALUE_NEW_SPAN_FN, VALUE_NEW_STR_FN) \ + sentry_value_t FN(size_t max_spans, sentry_value_t parent, \ + GEN_STR_PARAM(operation), GEN_STR_PARAM(description)) \ + { \ + if (!sentry_value_is_null( \ + sentry_value_get_by_key(parent, "timestamp"))) { \ + SENTRY_DEBUG( \ + "span's parent is already finished, not creating span"); \ + goto fail; \ + } \ + \ + sentry_value_t spans = sentry_value_get_by_key(parent, "spans"); \ + /* This only checks that the number of _completed_ spans matches the \ + * number of max spans. This means that the number of in-flight spans \ + * can exceed the max number of spans. */ \ + if (sentry_value_get_length(spans) >= max_spans) { \ + SENTRY_DEBUG( \ + "reached maximum number of spans for transaction, not " \ + "creating span"); \ + goto fail; \ + } \ + \ + sentry_value_t child = VALUE_NEW_SPAN_FN(parent, operation); \ + sentry_value_set_by_key( \ + child, "description", VALUE_NEW_STR_FN(description)); \ + sentry_value_set_by_key(child, "start_timestamp", \ + sentry__value_new_string_owned( \ + sentry__msec_time_to_iso8601(sentry__msec_time()))); \ + \ + return child; \ + fail: \ + return sentry_value_new_null(); \ + } + +GEN_SENTRY__VALUE_SPAN_NEW(sentry__value_span_new_n, PTR_LEN_PARAM_FROM_NAME, + CALL_SENTRY__VALUE_NEW_SPAN_N, CALL_SENTRY_VALUE_NEW_STRING_N) +GEN_SENTRY__VALUE_SPAN_NEW(sentry__value_span_new, STR_PARAM_FROM_NAME, + CALL_SENTRY__VALUE_NEW_SPAN, CALL_SENTRY_VALUE_NEW_STRING) sentry_value_t sentry__value_get_trace_context(sentry_value_t span) @@ -326,22 +395,47 @@ sentry_transaction_set_name(sentry_transaction_t *tx, const char *name) } } -static void -set_tag(sentry_value_t item, const char *tag, const char *value) +void +sentry_transaction_set_name_n( + sentry_transaction_t *tx, const char *name, size_t name_len) { - sentry_value_t tags = sentry_value_get_by_key(item, "tags"); - if (sentry_value_is_null(tags)) { - tags = sentry_value_new_object(); - sentry_value_set_by_key(item, "tags", tags); + if (tx) { + sentry_value_set_by_key(tx->inner, "transaction", + sentry_value_new_string_n(name, name_len)); } +} - char *s = sentry__string_clonen(value, 200); - if (s) { - sentry_value_set_by_key(tags, tag, sentry__value_new_string_owned(s)); - } else { - sentry_value_set_by_key(tags, tag, sentry_value_new_null()); +#define GEN_SET_TAG(FN, GEN_STR_PARAM, MAX_CLONE_FN, VALUE_SET_BY_KEY_FN) \ + static void FN( \ + sentry_value_t item, GEN_STR_PARAM(tag), GEN_STR_PARAM(value)) \ + { \ + sentry_value_t tags = sentry_value_get_by_key(item, "tags"); \ + if (sentry_value_is_null(tags)) { \ + tags = sentry_value_new_object(); \ + sentry_value_set_by_key(item, "tags", tags); \ + } \ + \ + char *s = MAX_CLONE_FN(value, 200); \ + if (s) { \ + VALUE_SET_BY_KEY_FN(tags, tag, sentry__value_new_string_owned(s)); \ + } else { \ + VALUE_SET_BY_KEY_FN(tags, tag, sentry_value_new_null()); \ + } \ } -} + +#define CALL_SENTRY__STRING_CLONE_MAX(STR, MAX_LEN) \ + sentry__string_clone_max(STR, MAX_LEN) +#define CALL_SENTRY__STRING_CLONE_MAX_N(STR, MAX_LEN) \ + sentry__string_clone_max_n(STR, STR##_len, MAX_LEN) +#define CALL_SENTRY_VALUE_SET_BY_KEY(VAL, K, V) \ + sentry_value_set_by_key(VAL, K, V) +#define CALL_SENTRY_VALUE_SET_BY_KEY_N(VAL, K, V) \ + sentry_value_set_by_key_n(VAL, K, K##_len, V) + +GEN_SET_TAG(set_tag, STR_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE_MAX, + CALL_SENTRY_VALUE_SET_BY_KEY) +GEN_SET_TAG(set_tag_n, PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE_MAX_N, + CALL_SENTRY_VALUE_SET_BY_KEY_N) void sentry_transaction_set_tag( @@ -352,6 +446,15 @@ sentry_transaction_set_tag( } } +void +sentry_transaction_set_tag_n(sentry_transaction_t *tx, const char *tag, + size_t tag_len, const char *value, size_t value_len) +{ + if (tx) { + set_tag_n(tx->inner, tag, tag_len, value, value_len); + } +} + void sentry_span_set_tag(sentry_span_t *span, const char *tag, const char *value) { @@ -360,6 +463,15 @@ sentry_span_set_tag(sentry_span_t *span, const char *tag, const char *value) } } +void +sentry_span_set_tag_n(sentry_span_t *span, const char *tag, size_t tag_len, + const char *value, size_t value_len) +{ + if (span) { + set_tag_n(span->inner, tag, tag_len, value, value_len); + } +} + static void remove_tag(sentry_value_t item, const char *tag) { @@ -369,6 +481,15 @@ remove_tag(sentry_value_t item, const char *tag) } } +static void +remove_tag_n(sentry_value_t item, const char *tag, size_t tag_len) +{ + sentry_value_t tags = sentry_value_get_by_key(item, "tags"); + if (!sentry_value_is_null(tags)) { + sentry_value_remove_by_key_n(tags, tag, tag_len); + } +} + void sentry_transaction_remove_tag(sentry_transaction_t *tx, const char *tag) { @@ -377,6 +498,15 @@ sentry_transaction_remove_tag(sentry_transaction_t *tx, const char *tag) } } +void +sentry_transaction_remove_tag_n( + sentry_transaction_t *tx, const char *tag, size_t tag_len) +{ + if (tx) { + remove_tag_n(tx->inner, tag, tag_len); + } +} + void sentry_span_remove_tag(sentry_span_t *span, const char *tag) { @@ -385,6 +515,14 @@ sentry_span_remove_tag(sentry_span_t *span, const char *tag) } } +void +sentry_span_remove_tag_n(sentry_span_t *span, const char *tag, size_t tag_len) +{ + if (span) { + remove_tag_n(span->inner, tag, tag_len); + } +} + static void set_data(sentry_value_t item, const char *key, sentry_value_t value) { @@ -396,6 +534,18 @@ set_data(sentry_value_t item, const char *key, sentry_value_t value) sentry_value_set_by_key(data, key, value); } +static void +set_data_n( + sentry_value_t item, const char *key, size_t key_len, sentry_value_t value) +{ + sentry_value_t data = sentry_value_get_by_key(item, "data"); + if (sentry_value_is_null(data)) { + data = sentry_value_new_object(); + sentry_value_set_by_key(item, "data", data); + } + sentry_value_set_by_key_n(data, key, key_len, value); +} + void sentry_transaction_set_data( sentry_transaction_t *tx, const char *key, sentry_value_t value) @@ -405,6 +555,15 @@ sentry_transaction_set_data( } } +void +sentry_transaction_set_data_n(sentry_transaction_t *tx, const char *key, + size_t key_len, sentry_value_t value) +{ + if (tx) { + set_data_n(tx->inner, key, key_len, value); + } +} + void sentry_span_set_data(sentry_span_t *span, const char *key, sentry_value_t value) { @@ -413,6 +572,15 @@ sentry_span_set_data(sentry_span_t *span, const char *key, sentry_value_t value) } } +void +sentry_span_set_data_n( + sentry_span_t *span, const char *key, size_t key_len, sentry_value_t value) +{ + if (span) { + set_data_n(span->inner, key, key_len, value); + } +} + static void remove_data(sentry_value_t item, const char *key) { @@ -422,6 +590,15 @@ remove_data(sentry_value_t item, const char *key) } } +static void +remove_data_n(sentry_value_t item, const char *key, size_t key_len) +{ + sentry_value_t data = sentry_value_get_by_key(item, "data"); + if (!sentry_value_is_null(data)) { + sentry_value_remove_by_key_n(data, key, key_len); + } +} + void sentry_transaction_remove_data(sentry_transaction_t *tx, const char *key) { @@ -430,6 +607,15 @@ sentry_transaction_remove_data(sentry_transaction_t *tx, const char *key) } } +void +sentry_transaction_remove_data_n( + sentry_transaction_t *tx, const char *key, size_t key_len) +{ + if (tx) { + remove_data_n(tx->inner, key, key_len); + } +} + void sentry_span_remove_data(sentry_span_t *span, const char *key) { @@ -438,6 +624,14 @@ sentry_span_remove_data(sentry_span_t *span, const char *key) } } +void +sentry_span_remove_data_n(sentry_span_t *span, const char *key, size_t key_len) +{ + if (span) { + remove_data_n(span->inner, key, key_len); + } +} + sentry_value_t sentry_status_to_string(sentry_span_status_t status) { @@ -481,7 +675,7 @@ sentry_status_to_string(sentry_span_status_t status) } } -void +static void set_status(sentry_value_t item, sentry_span_status_t status) { sentry_value_set_by_key(item, "status", sentry_status_to_string(status)); diff --git a/src/sentry_tracing.h b/src/sentry_tracing.h index e04e5ee2fd..5f7036324d 100644 --- a/src/sentry_tracing.h +++ b/src/sentry_tracing.h @@ -36,7 +36,15 @@ void sentry__span_incref(sentry_span_t *span); void sentry__span_decref(sentry_span_t *span); sentry_value_t sentry__value_span_new(size_t max_spans, sentry_value_t parent, - char *operation, char *description); + const char *operation, const char *description); +sentry_value_t sentry__value_span_new_n(size_t max_spans, sentry_value_t parent, + const char *operation, size_t operation_len, const char *description, + size_t description_len); +#define CALL_SENTRY__VALUE_SPAN_NEW_N(MAX_SPANS, PARENT, OP, DESC) \ + sentry__value_span_new_n(MAX_SPANS, PARENT, OP, OP##_len, DESC, DESC##_len) +#define CALL_SENTRY__VALUE_SPAN_NEW(MAX_SPANS, PARENT, OP, DESC) \ + sentry__value_span_new(MAX_SPANS, PARENT, OP, DESC) + sentry_span_t *sentry__span_new( sentry_transaction_t *parent_tx, sentry_value_t inner); diff --git a/src/sentry_utils.c b/src/sentry_utils.c index 2319fc9889..1cd104989c 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -212,67 +212,73 @@ sentry__url_cleanup(sentry_url_t *url) memset(url, 0, sizeof(sentry_url_t)); } -sentry_dsn_t * -sentry__dsn_new(const char *raw_dsn) -{ - sentry_url_t url; - memset(&url, 0, sizeof(sentry_url_t)); - size_t path_len; - char *project_id; - - sentry_dsn_t *dsn = SENTRY_MAKE(sentry_dsn_t); - if (!dsn) { - return NULL; - } - memset(dsn, 0, sizeof(sentry_dsn_t)); - dsn->refcount = 1; - - dsn->raw = sentry__string_clone(raw_dsn); - if (!dsn->raw || !dsn->raw[0] || sentry__url_parse(&url, dsn->raw) != 0) { - goto exit; - } - - if (sentry__string_eq(url.scheme, "https")) { - dsn->is_secure = 1; - } else if (sentry__string_eq(url.scheme, "http")) { - dsn->is_secure = 0; - } else { - goto exit; - } - - dsn->host = url.host; - url.host = NULL; - dsn->public_key = url.username; - url.username = NULL; - dsn->secret_key = url.password; - url.password = NULL; - dsn->port = url.port; - - path_len = strlen(url.path); - while (path_len > 0 && url.path[path_len - 1] == '/') { - url.path[path_len - 1] = '\0'; - path_len--; - } - - project_id = strrchr(url.path, '/'); - if (!project_id || strlen(project_id + 1) == 0) { - goto exit; - } - - dsn->project_id = sentry__string_clone(project_id + 1); - *project_id = 0; - - dsn->path = url.path; - url.path = NULL; - - if (dsn->public_key && dsn->host && dsn->path) { - dsn->is_valid = true; - } - -exit: - sentry__url_cleanup(&url); - return dsn; -} +#define GEN_SENTRY__DSN_NEW(FN, GEN_STR_PARAM, STR_CLONE_FN) \ + sentry_dsn_t *FN(GEN_STR_PARAM(raw_dsn)) \ + { \ + sentry_url_t url; \ + memset(&url, 0, sizeof(sentry_url_t)); \ + size_t path_len; \ + char *project_id; \ + \ + sentry_dsn_t *dsn = SENTRY_MAKE(sentry_dsn_t); \ + if (!dsn) { \ + return NULL; \ + } \ + memset(dsn, 0, sizeof(sentry_dsn_t)); \ + dsn->refcount = 1; \ + \ + dsn->raw = STR_CLONE_FN(raw_dsn); \ + if (!dsn->raw || !dsn->raw[0] \ + || sentry__url_parse(&url, dsn->raw) != 0) { \ + goto exit; \ + } \ + \ + if (sentry__string_eq(url.scheme, "https")) { \ + dsn->is_secure = 1; \ + } else if (sentry__string_eq(url.scheme, "http")) { \ + dsn->is_secure = 0; \ + } else { \ + goto exit; \ + } \ + \ + dsn->host = url.host; \ + url.host = NULL; \ + dsn->public_key = url.username; \ + url.username = NULL; \ + dsn->secret_key = url.password; \ + url.password = NULL; \ + dsn->port = url.port; \ + \ + path_len = strlen(url.path); \ + while (path_len > 0 && url.path[path_len - 1] == '/') { \ + url.path[path_len - 1] = '\0'; \ + path_len--; \ + } \ + \ + project_id = strrchr(url.path, '/'); \ + if (!project_id || strlen(project_id + 1) == 0) { \ + goto exit; \ + } \ + \ + dsn->project_id = sentry__string_clone(project_id + 1); \ + *project_id = 0; \ + \ + dsn->path = url.path; \ + url.path = NULL; \ + \ + if (dsn->public_key && dsn->host && dsn->path) { \ + dsn->is_valid = true; \ + } \ + \ + exit: \ + sentry__url_cleanup(&url); \ + return dsn; \ + } + +GEN_SENTRY__DSN_NEW( + sentry__dsn_new_n, PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE_N) +GEN_SENTRY__DSN_NEW( + sentry__dsn_new, STR_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE) sentry_dsn_t * sentry__dsn_incref(sentry_dsn_t *dsn) diff --git a/src/sentry_utils.h b/src/sentry_utils.h index 703b53c3f2..6f96eea647 100644 --- a/src/sentry_utils.h +++ b/src/sentry_utils.h @@ -63,6 +63,7 @@ typedef struct sentry_dsn_s { * DSN has been successfully parsed. */ sentry_dsn_t *sentry__dsn_new(const char *dsn); +sentry_dsn_t *sentry__dsn_new_n(const char *dsn, size_t raw_dsn_len); /** * Increases the reference-count of the DSN. diff --git a/src/sentry_uuid.c b/src/sentry_uuid.c index ad5e349996..bd1ee66dae 100644 --- a/src/sentry_uuid.c +++ b/src/sentry_uuid.c @@ -25,13 +25,13 @@ sentry_uuid_new_v4(void) } sentry_uuid_t -sentry_uuid_from_string(const char *str) +sentry_uuid_from_string_n(const char *str, size_t str_len) { sentry_uuid_t rv; memset(&rv, 0, sizeof(rv)); size_t i = 0; - size_t len = strlen(str); + size_t len = str_len; size_t pos = 0; bool is_nibble = true; char nibble = 0; @@ -65,6 +65,12 @@ sentry_uuid_from_string(const char *str) return rv; } +sentry_uuid_t +sentry_uuid_from_string(const char *str) +{ + return str ? sentry_uuid_from_string_n(str, strlen(str)) + : sentry_uuid_nil(); +} sentry_uuid_t sentry_uuid_from_bytes(const char bytes[16]) { diff --git a/src/sentry_value.c b/src/sentry_value.c index 9d78efd9ec..c86cc7710a 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -21,6 +21,7 @@ #include "sentry_alloc.h" #include "sentry_core.h" #include "sentry_json.h" +#include "sentry_slice.h" #include "sentry_string.h" #include "sentry_sync.h" #include "sentry_utils.h" @@ -320,15 +321,22 @@ sentry_value_new_bool(int value) } sentry_value_t -sentry_value_new_string(const char *value) +sentry_value_new_string_n(const char *value, size_t len) { - char *s = sentry__string_clone(value); + char *s = sentry__string_clonen_or_null(value, len); if (!s) { return sentry_value_new_null(); } return sentry__value_new_string_owned(s); } +sentry_value_t +sentry_value_new_string(const char *value) +{ + return value ? sentry_value_new_string_n(value, strlen(value)) + : sentry_value_new_null(); +} + sentry_value_t sentry_value_new_list(void) { @@ -440,8 +448,13 @@ sentry_value_get_type(sentry_value_t value) } int -sentry_value_set_by_key(sentry_value_t value, const char *k, sentry_value_t v) +sentry_value_set_by_key_n( + sentry_value_t value, const char *k, size_t k_len, sentry_value_t v) { + if (!k) { + goto fail; + } + sentry_slice_t k_slice = { k, k_len }; thing_t *thing = value_as_unfrozen_thing(value); if (!thing || thing_get_type(thing) != THING_TYPE_OBJECT) { goto fail; @@ -449,7 +462,7 @@ sentry_value_set_by_key(sentry_value_t value, const char *k, sentry_value_t v) obj_t *o = thing->payload._ptr; for (size_t i = 0; i < o->len; i++) { obj_pair_t *pair = &o->pairs[i]; - if (sentry__string_eq(pair->k, k)) { + if (sentry__slice_eqs(k_slice, pair->k)) { sentry_value_decref(pair->v); pair->v = v; return 0; @@ -462,7 +475,7 @@ sentry_value_set_by_key(sentry_value_t value, const char *k, sentry_value_t v) } obj_pair_t pair; - pair.k = sentry__string_clone(k); + pair.k = sentry__slice_to_owned(k_slice); if (!pair.k) { goto fail; } @@ -476,8 +489,23 @@ sentry_value_set_by_key(sentry_value_t value, const char *k, sentry_value_t v) } int -sentry_value_remove_by_key(sentry_value_t value, const char *k) +sentry_value_set_by_key(sentry_value_t value, const char *k, sentry_value_t v) { + if (k) { + return sentry_value_set_by_key_n(value, k, strlen(k), v); + } + + sentry_value_decref(v); + return 1; +} + +int +sentry_value_remove_by_key_n(sentry_value_t value, const char *k, size_t k_len) +{ + if (!k) { + return 1; + } + sentry_slice_t k_slice = { k, k_len }; thing_t *thing = value_as_unfrozen_thing(value); if (!thing || thing_get_type(thing) != THING_TYPE_OBJECT) { return 1; @@ -485,7 +513,7 @@ sentry_value_remove_by_key(sentry_value_t value, const char *k) obj_t *o = thing->payload._ptr; for (size_t i = 0; i < o->len; i++) { obj_pair_t *pair = &o->pairs[i]; - if (sentry__string_eq(pair->k, k)) { + if (sentry__slice_eqs(k_slice, pair->k)) { sentry_free(pair->k); sentry_value_decref(pair->v); memmove(o->pairs + i, o->pairs + i + 1, @@ -497,6 +525,16 @@ sentry_value_remove_by_key(sentry_value_t value, const char *k) return 1; } +int +sentry_value_remove_by_key(sentry_value_t value, const char *k) +{ + if (k) { + return sentry_value_remove_by_key_n(value, k, strlen(k)); + } + + return 1; +} + int sentry_value_append(sentry_value_t value, sentry_value_t v) { @@ -683,9 +721,31 @@ sentry_value_remove_by_index(sentry_value_t value, size_t index) return 0; } +sentry_value_t +sentry_value_get_by_key_n(sentry_value_t value, const char *k, size_t k_len) +{ + if (!k) { + return sentry_value_new_null(); + } + const thing_t *thing = value_as_thing(value); + if (thing && thing_get_type(thing) == THING_TYPE_OBJECT) { + obj_t *o = thing->payload._ptr; + for (size_t i = 0; i < o->len; i++) { + obj_pair_t *pair = &o->pairs[i]; + if (sentry__slice_eqs((sentry_slice_t) { k, k_len }, pair->k)) { + return pair->v; + } + } + } + return sentry_value_new_null(); +} + sentry_value_t sentry_value_get_by_key(sentry_value_t value, const char *k) { + if (!k) { + return sentry_value_new_null(); + } const thing_t *thing = value_as_thing(value); if (thing && thing_get_type(thing) == THING_TYPE_OBJECT) { obj_t *o = thing->payload._ptr; @@ -699,10 +759,23 @@ sentry_value_get_by_key(sentry_value_t value, const char *k) return sentry_value_new_null(); } +sentry_value_t +sentry_value_get_by_key_owned_n( + sentry_value_t value, const char *k, size_t k_len) +{ + sentry_value_t rv = sentry_value_get_by_key_n(value, k, k_len); + sentry_value_incref(rv); + return rv; +} + sentry_value_t sentry_value_get_by_key_owned(sentry_value_t value, const char *k) { - sentry_value_t rv = sentry_value_get_by_key(value, k); + if (k) { + return sentry_value_get_by_key_owned_n(value, k, strlen(k)); + } + + sentry_value_t rv = sentry_value_new_null(); sentry_value_incref(rv); return rv; } @@ -1068,71 +1141,103 @@ sentry_value_new_event(void) return rv; } -sentry_value_t -sentry_value_new_message_event( - sentry_level_t level, const char *logger, const char *text) -{ - sentry_value_t rv = sentry_value_new_event(); - sentry_value_set_by_key(rv, "level", sentry__value_new_level(level)); - if (logger) { - sentry_value_set_by_key(rv, "logger", sentry_value_new_string(logger)); - } - if (text) { - sentry_value_t container = sentry_value_new_object(); - sentry_value_set_by_key( - container, "formatted", sentry_value_new_string(text)); - sentry_value_set_by_key(rv, "message", container); +#define CALL_SENTRY_VALUE_NEW_STRING_N(STR) \ + sentry_value_new_string_n(STR, STR##_len) +#define CALL_SENTRY_VALUE_NEW_STRING(STR) sentry_value_new_string(STR) + +#define GEN_SENTRY_VALUE_NEW_MESSAGE_EVENT( \ + FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ + sentry_value_t FN( \ + sentry_level_t level, GEN_STR_PARAM(logger), GEN_STR_PARAM(text)) \ + { \ + sentry_value_t rv = sentry_value_new_event(); \ + sentry_value_set_by_key(rv, "level", sentry__value_new_level(level)); \ + if (logger) { \ + sentry_value_set_by_key(rv, "logger", VALUE_NEW_STR_FN(logger)); \ + } \ + if (text) { \ + sentry_value_t container = sentry_value_new_object(); \ + sentry_value_set_by_key( \ + container, "formatted", VALUE_NEW_STR_FN(text)); \ + sentry_value_set_by_key(rv, "message", container); \ + } \ + return rv; \ } - return rv; -} -sentry_value_t -sentry_value_new_breadcrumb(const char *type, const char *message) -{ - sentry_value_t rv = sentry_value_new_object(); - sentry_value_set_by_key(rv, "timestamp", - sentry__value_new_string_owned( - sentry__msec_time_to_iso8601(sentry__msec_time()))); +GEN_SENTRY_VALUE_NEW_MESSAGE_EVENT(sentry_value_new_message_event_n, + PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING_N) - if (type) { - sentry_value_set_by_key(rv, "type", sentry_value_new_string(type)); - } - if (message) { - sentry_value_set_by_key( - rv, "message", sentry_value_new_string(message)); - } - return rv; -} +GEN_SENTRY_VALUE_NEW_MESSAGE_EVENT(sentry_value_new_message_event, + STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) -sentry_value_t -sentry_value_new_exception(const char *type, const char *value) +static void +timestamp_value(sentry_value_t value) { - sentry_value_t exc = sentry_value_new_object(); - sentry_value_set_by_key(exc, "type", sentry_value_new_string(type)); - sentry_value_set_by_key(exc, "value", sentry_value_new_string(value)); - return exc; + sentry_value_set_by_key(value, "timestamp", + sentry__value_new_string_owned( + sentry__msec_time_to_iso8601(sentry__msec_time()))); } -sentry_value_t -sentry_value_new_thread(uint64_t id, const char *name) -{ - sentry_value_t thread = sentry_value_new_object(); - - // NOTE: values end up as JSON, which has no support for `u64`. - char buf[20 + 1]; - size_t written - = (size_t)snprintf(buf, sizeof(buf), "%llu", (unsigned long long)id); - if (written < sizeof(buf)) { - buf[written] = '\0'; - sentry_value_set_by_key(thread, "id", sentry_value_new_string(buf)); - } - - if (name) { - sentry_value_set_by_key(thread, "name", sentry_value_new_string(name)); - } - - return thread; -} +#define GEN_SENTRY_VALUE_NEW_BREADCRUMB(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ + sentry_value_t FN(GEN_STR_PARAM(type), GEN_STR_PARAM(message)) \ + { \ + sentry_value_t rv = sentry_value_new_object(); \ + timestamp_value(rv); \ + \ + if (type) { \ + sentry_value_set_by_key(rv, "type", VALUE_NEW_STR_FN(type)); \ + } \ + if (message) { \ + sentry_value_set_by_key(rv, "message", VALUE_NEW_STR_FN(message)); \ + } \ + return rv; \ + } + +GEN_SENTRY_VALUE_NEW_BREADCRUMB(sentry_value_new_breadcrumb, + STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) +GEN_SENTRY_VALUE_NEW_BREADCRUMB(sentry_value_new_breadcrumb_n, + PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING_N) + +#define GEN_SENTRY_VALUE_NEW_EXCEPTION(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ + sentry_value_t FN(GEN_STR_PARAM(type), GEN_STR_PARAM(value)) \ + { \ + sentry_value_t exc = sentry_value_new_object(); \ + sentry_value_set_by_key(exc, "type", VALUE_NEW_STR_FN(type)); \ + sentry_value_set_by_key(exc, "value", VALUE_NEW_STR_FN(value)); \ + return exc; \ + } + +GEN_SENTRY_VALUE_NEW_EXCEPTION(sentry_value_new_exception, STR_PARAM_FROM_NAME, + CALL_SENTRY_VALUE_NEW_STRING) +GEN_SENTRY_VALUE_NEW_EXCEPTION(sentry_value_new_exception_n, + PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING_N) + +#define GEN_SENTRY_VALUE_NEW_THREAD(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ + sentry_value_t FN(uint64_t id, GEN_STR_PARAM(name)) \ + { \ + sentry_value_t thread = sentry_value_new_object(); \ + \ + /* NOTE: values end up as JSON, which has no support for `u64`. */ \ + char buf[20 + 1]; \ + size_t written = (size_t)snprintf( \ + buf, sizeof(buf), "%llu", (unsigned long long)id); \ + if (written < sizeof(buf)) { \ + buf[written] = '\0'; \ + sentry_value_set_by_key( \ + thread, "id", sentry_value_new_string(buf)); \ + } \ + \ + if (name) { \ + sentry_value_set_by_key(thread, "name", VALUE_NEW_STR_FN(name)); \ + } \ + \ + return thread; \ + } + +GEN_SENTRY_VALUE_NEW_THREAD( + sentry_value_new_thread, STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) +GEN_SENTRY_VALUE_NEW_THREAD(sentry_value_new_thread_n, PTR_LEN_PARAM_FROM_NAME, + CALL_SENTRY_VALUE_NEW_STRING_N) sentry_value_t sentry_value_new_stacktrace(void **ips, size_t len) diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index bd4d2d065d..bbf4e61428 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -35,7 +35,8 @@ SENTRY_TEST(lazy_attachments) sentry_options_set_transport(options, sentry_new_function_transport( send_envelope_test_attachments, &testdata)); - sentry_options_set_release(options, "prod"); + char rel[4] = { 't', 'e', 's', 't' }; + sentry_options_set_release_n(options, rel, sizeof(rel)); sentry_options_add_attachment(options, PREFIX ".existing-file-attachment"); sentry_options_add_attachment( @@ -53,6 +54,7 @@ SENTRY_TEST(lazy_attachments) char *serialized = sentry_stringbuilder_take_string(&testdata.serialized_envelope); + TEST_CHECK(strstr(serialized, "\"release\":\"test\"") != NULL); TEST_CHECK(strstr(serialized, "{\"type\":\"attachment\",\"length\":3," "\"filename\":\".existing-file-attachment\"}\n" diff --git a/tests/unit/test_basic.c b/tests/unit/test_basic.c index d8a51e4618..77a895e32a 100644 --- a/tests/unit/test_basic.c +++ b/tests/unit/test_basic.c @@ -176,14 +176,18 @@ SENTRY_TEST(crashed_last_run) TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), -1); options = sentry_options_new(); - sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + const char *dsn_str = "https://foo@sentry.invalid/42"; + const char dsn[29] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'f', 'o', + 'o', '@', 's', 'e', 'n', 't', 'r', 'y', '.', 'i', 'n', 'v', 'a', 'l', + 'i', 'd', '/', '4', '2' }; + sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); sentry_close(); TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 0); options = sentry_options_new(); - sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); // simulate a crash TEST_CHECK(sentry__write_crash_marker(options)); @@ -201,7 +205,7 @@ SENTRY_TEST(crashed_last_run) TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); options = sentry_options_new(); - sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); sentry_close(); diff --git a/tests/unit/test_session.c b/tests/unit/test_session.c index fbe586a02a..ebaaed389b 100644 --- a/tests/unit/test_session.c +++ b/tests/unit/test_session.c @@ -47,7 +47,7 @@ send_envelope(const sentry_envelope_t *envelope, void *data) "my_release"); TEST_CHECK_STRING_EQUAL( sentry_value_as_string(sentry_value_get_by_key(attrs, "environment")), - "my_environment"); + "test"); sentry_value_decref(session); } @@ -67,6 +67,10 @@ SENTRY_TEST(session_basics) TEST_CHECK_STRING_EQUAL( sentry_options_get_environment(options), "production"); sentry_options_set_environment(options, "my_environment"); + TEST_CHECK_STRING_EQUAL( + sentry_options_get_environment(options), "my_environment"); + char env[] = { 't', 'e', 's', 't' }; + sentry_options_set_environment_n(options, env, sizeof(env)); sentry_init(options); // a session was already started by automatic session tracking diff --git a/tests/unit/test_tracing.c b/tests/unit/test_tracing.c index a960273e03..7c25651685 100644 --- a/tests/unit/test_tracing.c +++ b/tests/unit/test_tracing.c @@ -94,9 +94,19 @@ SENTRY_TEST(basic_transaction) sentry_transaction_context_set_name(opaque_tx_cxt, ""); CHECK_STRING_PROPERTY(tx_cxt, "transaction", ""); + char txn_ctx_name[] = { 'h', 'o', 'n', 'k', '.', 'b', 'e', 'e', 'p' }; + sentry_transaction_context_set_name_n( + opaque_tx_cxt, txn_ctx_name, sizeof(txn_ctx_name)); + CHECK_STRING_PROPERTY(tx_cxt, "transaction", "honk.beep"); + sentry_transaction_context_set_operation(opaque_tx_cxt, ""); CHECK_STRING_PROPERTY(tx_cxt, "op", ""); + char txn_ctx_op[] = { 'b', 'e', 'e', 'p', 'b', 'e', 'e', 'p' }; + sentry_transaction_context_set_operation_n( + opaque_tx_cxt, txn_ctx_op, sizeof(txn_ctx_op)); + CHECK_STRING_PROPERTY(tx_cxt, "op", "beepbeep"); + sentry_transaction_context_set_sampled(opaque_tx_cxt, 1); TEST_CHECK( sentry_value_is_true(sentry_value_get_by_key(tx_cxt, "sampled")) @@ -807,5 +817,169 @@ SENTRY_TEST(distributed_headers) sentry_close(); } +void +check_after_set(sentry_value_t inner, const char *inner_key, + const char *item_key, const char *expected) +{ + sentry_value_t inner_tags = sentry_value_get_by_key(inner, inner_key); + TEST_CHECK_INT_EQUAL(1, sentry_value_get_length(inner_tags)); + TEST_CHECK( + sentry_value_get_type(sentry_value_get_by_key(inner_tags, item_key)) + == SENTRY_VALUE_TYPE_STRING); + TEST_CHECK_STRING_EQUAL(expected, + sentry_value_as_string(sentry_value_get_by_key(inner_tags, item_key))); +} + +void +check_after_remove( + sentry_value_t inner, const char *inner_key, const char *item_key) +{ + sentry_value_t inner_tags = sentry_value_get_by_key(inner, inner_key); + TEST_CHECK_INT_EQUAL(0, sentry_value_get_length(inner_tags)); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(inner_tags, item_key))); +} + +SENTRY_TEST(txn_tagging) +{ + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + + sentry_transaction_set_tag(txn, "os.name", "Linux"); + check_after_set(txn->inner, "tags", "os.name", "Linux"); + + sentry_transaction_remove_tag(txn, "os.name"); + check_after_remove(txn->inner, "tags", "os.name"); +} + +SENTRY_TEST(span_tagging) +{ + sentry_span_t *span + = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), + sentry_value_new_object()); + + sentry_span_set_tag(span, "os.name", "Linux"); + check_after_set(span->inner, "tags", "os.name", "Linux"); + + sentry_span_remove_tag(span, "os.name"); + check_after_remove(span->inner, "tags", "os.name"); +} + +SENTRY_TEST(txn_tagging_n) +{ + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + + char tag[] = { 'o', 's', '.', 'n', 'a', 'm', 'e' }; + char tag_val[] = { 'L', 'i', 'n', 'u', 'x' }; + sentry_transaction_set_tag_n( + txn, tag, sizeof(tag), tag_val, sizeof(tag_val)); + check_after_set(txn->inner, "tags", "os.name", "Linux"); + + sentry_transaction_remove_tag_n(txn, tag, sizeof(tag)); + check_after_remove(txn->inner, "tags", "os.name"); +} + +SENTRY_TEST(span_tagging_n) +{ + sentry_span_t *span + = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), + sentry_value_new_object()); + + char tag[] = { 'o', 's', '.', 'n', 'a', 'm', 'e' }; + char tag_val[] = { 'L', 'i', 'n', 'u', 'x' }; + sentry_span_set_tag_n(span, tag, sizeof(tag), tag_val, sizeof(tag_val)); + check_after_set(span->inner, "tags", "os.name", "Linux"); + + sentry_span_remove_tag_n(span, tag, sizeof(tag)); + check_after_remove(span->inner, "tags", "os.name"); +} + +SENTRY_TEST(txn_name) +{ + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + char *txn_name = "the_txn"; + sentry_transaction_set_name(txn, txn_name); + sentry_value_t txn_name_value + = sentry_value_get_by_key(txn->inner, "transaction"); + TEST_CHECK( + sentry_value_get_type(txn_name_value) == SENTRY_VALUE_TYPE_STRING); + TEST_CHECK_STRING_EQUAL(sentry_value_as_string(txn_name_value), txn_name); +} + +SENTRY_TEST(txn_data) +{ + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + + sentry_transaction_set_data( + txn, "os.name", sentry_value_new_string("Linux")); + check_after_set(txn->inner, "data", "os.name", "Linux"); + + sentry_transaction_remove_data(txn, "os.name"); + check_after_remove(txn->inner, "data", "os.name"); +} + +SENTRY_TEST(span_data) +{ + sentry_span_t *span + = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), + sentry_value_new_object()); + + sentry_span_set_data(span, "os.name", sentry_value_new_string("Linux")); + check_after_set(span->inner, "data", "os.name", "Linux"); + + sentry_span_remove_data(span, "os.name"); + check_after_remove(span->inner, "data", "os.name"); +} + +SENTRY_TEST(txn_name_n) +{ + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + char txn_name[] = { 't', 'h', 'e', '_', 't', 'x', 'n' }; + sentry_transaction_set_name_n(txn, txn_name, sizeof(txn_name)); + + sentry_value_t txn_name_value + = sentry_value_get_by_key(txn->inner, "transaction"); + TEST_CHECK( + sentry_value_get_type(txn_name_value) == SENTRY_VALUE_TYPE_STRING); + TEST_CHECK_STRING_EQUAL(sentry_value_as_string(txn_name_value), "the_txn"); +} + +SENTRY_TEST(txn_data_n) +{ + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + + char data_k[] = { 'o', 's', '.', 'n', 'a', 'm', 'e' }; + char data_v[] = { 'L', 'i', 'n', 'u', 'x' }; + sentry_value_t data_value + = sentry_value_new_string_n(data_v, sizeof(data_v)); + sentry_transaction_set_data_n(txn, data_k, sizeof(data_k), data_value); + check_after_set(txn->inner, "data", "os.name", "Linux"); + + sentry_transaction_remove_data_n(txn, data_k, sizeof(data_k)); + check_after_remove(txn->inner, "data", "os.name"); +} + +SENTRY_TEST(span_data_n) +{ + sentry_span_t *span + = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), + sentry_value_new_object()); + + char data_k[] = { 'o', 's', '.', 'n', 'a', 'm', 'e' }; + char data_v[] = { 'L', 'i', 'n', 'u', 'x' }; + sentry_value_t data_value + = sentry_value_new_string_n(data_v, sizeof(data_v)); + sentry_span_set_data_n(span, data_k, sizeof(data_k), data_value); + check_after_set(span->inner, "data", "os.name", "Linux"); + + sentry_span_remove_data_n(span, data_k, sizeof(data_k)); + check_after_remove(span->inner, "data", "os.name"); +} + #undef IS_NULL #undef CHECK_STRING_PROPERTY diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index 6a4044c13c..0eef663dd3 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -102,16 +102,30 @@ SENTRY_TEST(value_string) sentry_value_decref(val); } +SENTRY_TEST(value_string_n) +{ + sentry_value_t val = sentry_value_new_string_n(NULL, 0); + TEST_CHECK(sentry_value_is_null(val)); + TEST_CHECK(sentry_value_get_type(val) == SENTRY_VALUE_TYPE_NULL); + TEST_CHECK(sentry_value_is_true(val) == false); + sentry_value_decref(val); + + char non_null_term_empty_str[0] = {}; + val = sentry_value_new_string_n(non_null_term_empty_str, 0); + TEST_CHECK_STRING_EQUAL(sentry_value_as_string(val), ""); + TEST_CHECK(sentry_value_get_type(val) == SENTRY_VALUE_TYPE_STRING); + TEST_CHECK(sentry_value_is_true(val) == false); + sentry_value_decref(val); +} + SENTRY_TEST(value_unicode) { // https://xkcd.com/1813/ :-) - sentry_value_t val - = sentry_value_new_string("őá…–🤮🚀¿ 한글 테스트 \a\v"); - TEST_CHECK_STRING_EQUAL(sentry_value_as_string(val), - "őá…–🤮🚀¿ 한글 테스트 \a\v"); + sentry_value_t val = sentry_value_new_string("őá…–🤮🚀¿ 한글 테스트 \a\v"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(val), "őá…–🤮🚀¿ 한글 테스트 \a\v"); // json does not need to escape unicode, except for control characters - TEST_CHECK_JSON_VALUE( - val, "\"őá…–🤮🚀¿ 한글 테스트 \\u0007\\u000b\""); + TEST_CHECK_JSON_VALUE(val, "\"őá…–🤮🚀¿ 한글 테스트 \\u0007\\u000b\""); sentry_value_decref(val); char zalgo[] = "z̴̢̈͜ä̴̺̟́ͅl̸̛̦͎̺͂̃̚͝g̷̦̲͊͋̄̌͝o̸͇̞̪͙̞͌̇̀̓̏͜"; val = sentry_value_new_string(zalgo); @@ -547,6 +561,92 @@ SENTRY_TEST(value_collections_leak) sentry_value_decref(obj); } +SENTRY_TEST(value_set_by_null_key) +{ + sentry_value_t value = sentry_value_new_object(); + sentry_value_t payload = sentry_value_new_object(); + + TEST_CHECK(sentry_value_refcount(payload) == 1); + TEST_CHECK_INT_EQUAL(1, sentry_value_set_by_key(value, NULL, payload)); + TEST_CHECK(sentry_value_refcount(payload) == 0); + TEST_CHECK(sentry_value_get_length(value) == 0); + + payload = sentry_value_new_object(); + TEST_CHECK(sentry_value_refcount(payload) == 1); + TEST_CHECK_INT_EQUAL(1, sentry_value_set_by_key_n(value, NULL, 0, payload)); + TEST_CHECK(sentry_value_refcount(payload) == 0); + TEST_CHECK(sentry_value_get_length(value) == 0); + + payload = sentry_value_new_object(); + TEST_CHECK(sentry_value_refcount(payload) == 1); + TEST_CHECK_INT_EQUAL( + 1, sentry_value_set_by_key_n(value, NULL, 10, payload)); + TEST_CHECK(sentry_value_get_length(value) == 0); + TEST_CHECK(sentry_value_refcount(payload) == 0); + + sentry_value_decref(value); +} + +SENTRY_TEST(value_remove_by_null_key) +{ + sentry_value_t value = sentry_value_new_object(); + + TEST_CHECK_INT_EQUAL(0, + sentry_value_set_by_key(value, "some_key", sentry_value_new_object())); + TEST_CHECK(sentry_value_get_length(value) == 1); + + TEST_CHECK_INT_EQUAL(1, sentry_value_remove_by_key(value, NULL)); + TEST_CHECK_INT_EQUAL(1, sentry_value_get_length(value)); + TEST_CHECK_INT_EQUAL(1, sentry_value_remove_by_key_n(value, NULL, 0)); + TEST_CHECK_INT_EQUAL(1, sentry_value_get_length(value)); + TEST_CHECK_INT_EQUAL(1, sentry_value_remove_by_key_n(value, NULL, 10)); + TEST_CHECK_INT_EQUAL(1, sentry_value_get_length(value)); + + sentry_value_decref(value); +} + +SENTRY_TEST(value_get_by_null_key) +{ + sentry_value_t value = sentry_value_new_object(); + + const char *some_key = "some_key"; + TEST_CHECK_INT_EQUAL( + 0, sentry_value_set_by_key(value, some_key, sentry_value_new_object())); + TEST_CHECK(sentry_value_get_length(value) == 1); + + sentry_value_t rv = sentry_value_get_by_key(value, NULL); + TEST_CHECK(sentry_value_is_null(rv)); + TEST_CHECK_INT_EQUAL(1, sentry_value_refcount(rv)); + + rv = sentry_value_get_by_key_owned(value, NULL); + TEST_CHECK(sentry_value_is_null(rv)); + TEST_CHECK_INT_EQUAL(1, sentry_value_refcount(rv)); + sentry_value_decref(rv); + TEST_CHECK_INT_EQUAL(1, sentry_value_refcount(rv)); + + rv = sentry_value_get_by_key_owned(value, some_key); + TEST_CHECK(!sentry_value_is_null(rv)); + TEST_CHECK_INT_EQUAL(2, sentry_value_refcount(rv)); + sentry_value_decref(rv); + TEST_CHECK_INT_EQUAL(1, sentry_value_refcount(rv)); + + // if `k_len` != any length of keys stored in the object this won't + // segfault because the `sentry_slice_t` equality check already fails due to + // the length-inequality and never reaches `memcmp()`. + TEST_CHECK(sentry_value_is_null(sentry_value_get_by_key_n(value, NULL, 0))); + // If `k_len' == any key-length, we'd segfault without a NULL-check. + TEST_CHECK(sentry_value_is_null( + sentry_value_get_by_key_n(value, NULL, strlen(some_key)))); + + rv = sentry_value_get_by_key_owned_n(value, NULL, strlen(some_key)); + TEST_CHECK(sentry_value_is_null(rv)); + TEST_CHECK_INT_EQUAL(1, sentry_value_refcount(rv)); + sentry_value_decref(rv); + TEST_CHECK_INT_EQUAL(1, sentry_value_refcount(rv)); + + sentry_value_decref(value); +} + SENTRY_TEST(value_set_stacktrace) { sentry_value_t exc diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index c60d465545..4120d4b587 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -61,12 +61,22 @@ XX(sampling_transaction) XX(serialize_envelope) XX(session_basics) XX(slice) +XX(span_data) +XX(span_data_n) +XX(span_tagging) +XX(span_tagging_n) XX(spans_on_scope) XX(symbolizer) XX(task_queue) XX(transaction_name_backfill_on_finish) XX(transactions_skip_before_send) XX(transport_sampling_transactions) +XX(txn_data) +XX(txn_data_n) +XX(txn_name) +XX(txn_name_n) +XX(txn_tagging) +XX(txn_tagging_n) XX(uninitialized) XX(unsampled_spans) XX(unwinder) @@ -79,6 +89,7 @@ XX(value_bool) XX(value_collections_leak) XX(value_double) XX(value_freezing) +XX(value_get_by_null_key) XX(value_int32) XX(value_json_deeply_nested) XX(value_json_escaping) @@ -91,7 +102,10 @@ XX(value_null) XX(value_object) XX(value_object_merge) XX(value_object_merge_nested) +XX(value_remove_by_null_key) +XX(value_set_by_null_key) XX(value_set_stacktrace) XX(value_string) +XX(value_string_n) XX(value_unicode) XX(value_wrong_type) From 6da96ca26b9a3beaffcf91f69252abeb5d2b7df6 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 28 Mar 2023 17:18:01 +0200 Subject: [PATCH 02/36] fix GEN_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW --- src/sentry_tracing.c | 4 ++-- tests/unit/test_tracing.c | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sentry_tracing.c b/src/sentry_tracing.c index bdd64abea2..3b9d1ee577 100644 --- a/src/sentry_tracing.c +++ b/src/sentry_tracing.c @@ -51,8 +51,8 @@ GEN_SENTRY__VALUE_NEW_SPAN( sentry_value_set_by_key(transaction_context, "trace_id", \ sentry__value_new_internal_uuid(&trace_id)); \ \ - sentry_value_set_by_key(transaction_context, "transaction", \ - sentry_value_new_string(name)); \ + sentry_value_set_by_key( \ + transaction_context, "transaction", NEW_STR_VALUE_FUN(name)); \ \ return transaction_context; \ } diff --git a/tests/unit/test_tracing.c b/tests/unit/test_tracing.c index 7c25651685..2f578c8698 100644 --- a/tests/unit/test_tracing.c +++ b/tests/unit/test_tracing.c @@ -205,9 +205,13 @@ SENTRY_TEST(basic_function_transport_transaction) // consent was not given TEST_CHECK(!sentry_uuid_is_nil(&event_id)); sentry_user_consent_give(); - - tx_cxt = sentry_transaction_context_new("honk", "beep"); + char name[] = { 'h', 'o', 'n', 'k' }; + char op[] = { 'b', 'e', 'e', 'p' }; + tx_cxt + = sentry_transaction_context_new_n(name, sizeof(name), op, sizeof(op)); tx = sentry_transaction_start(tx_cxt, sentry_value_new_null()); + CHECK_STRING_PROPERTY(tx->inner, "transaction", "honk"); + CHECK_STRING_PROPERTY(tx->inner, "op", "beep"); event_id = sentry_transaction_finish(tx); TEST_CHECK(!sentry_uuid_is_nil(&event_id)); From df6f50109b5e19ddc1bd0281911546b1484eb2dc Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 11:28:01 +0200 Subject: [PATCH 03/36] Make tests run on Windows --- src/path/sentry_path_windows.c | 16 ++++++++++++++++ src/sentry_tracing.c | 5 ++++- tests/unit/test_value.c | 12 +++++------- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/path/sentry_path_windows.c b/src/path/sentry_path_windows.c index ea2a7097e7..4a2c42ccd8 100644 --- a/src/path/sentry_path_windows.c +++ b/src/path/sentry_path_windows.c @@ -205,6 +205,22 @@ sentry__path_from_str(const char *s) return rv; } +sentry_path_t * +sentry__path_from_str_n(const char *s, size_t s_len) +{ + sentry_path_t *rv = SENTRY_MAKE(sentry_path_t); + if (!rv) { + return NULL; + } + rv->path = sentry_malloc(sizeof(wchar_t) * (s_len + 1)); + if (!rv->path) { + sentry_free(rv); + return NULL; + } + MultiByteToWideChar(CP_ACP, 0, s, -1, rv->path, (int)s_len); + return rv; +} + sentry_path_t * sentry__path_from_str_owned(char *s) { diff --git a/src/sentry_tracing.c b/src/sentry_tracing.c index 3b9d1ee577..931aa5ead6 100644 --- a/src/sentry_tracing.c +++ b/src/sentry_tracing.c @@ -217,14 +217,17 @@ sentry_transaction_context_remove_sampled(sentry_transaction_context_t *tx_cxt) inner, "sampled", sentry_value_new_bool(sampled)); \ } +#pragma warning(push) +#pragma warning(disable : 4100) #define CALL_STR_CHR(STR, CHR) strchr(STR, CHR) -#define CALL_MEM_CHR(STR, CHR) memchr(STR, value_len, CHR) +#define CALL_MEM_CHR(STR, CHR) memchr(STR, (int)value_len, CHR) GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( sentry_transaction_context_update_from_header_n, PTR_LEN_PARAM_FROM_NAME, CALL_MEM_CHR) GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( sentry_transaction_context_update_from_header, STR_PARAM_FROM_NAME, CALL_STR_CHR) +#pragma warning(pop) sentry_transaction_t * sentry__transaction_new(sentry_value_t inner) diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index 0eef663dd3..beeefab344 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -110,11 +110,12 @@ SENTRY_TEST(value_string_n) TEST_CHECK(sentry_value_is_true(val) == false); sentry_value_decref(val); - char non_null_term_empty_str[0] = {}; - val = sentry_value_new_string_n(non_null_term_empty_str, 0); - TEST_CHECK_STRING_EQUAL(sentry_value_as_string(val), ""); + char non_null_term_empty_str[] + = { 'h', 'e', 'l','l','o'}; + val = sentry_value_new_string_n(non_null_term_empty_str, sizeof(non_null_term_empty_str)); + TEST_CHECK_STRING_EQUAL(sentry_value_as_string(val), "hello"); TEST_CHECK(sentry_value_get_type(val) == SENTRY_VALUE_TYPE_STRING); - TEST_CHECK(sentry_value_is_true(val) == false); + TEST_CHECK(sentry_value_is_true(val) == true); sentry_value_decref(val); } @@ -568,13 +569,11 @@ SENTRY_TEST(value_set_by_null_key) TEST_CHECK(sentry_value_refcount(payload) == 1); TEST_CHECK_INT_EQUAL(1, sentry_value_set_by_key(value, NULL, payload)); - TEST_CHECK(sentry_value_refcount(payload) == 0); TEST_CHECK(sentry_value_get_length(value) == 0); payload = sentry_value_new_object(); TEST_CHECK(sentry_value_refcount(payload) == 1); TEST_CHECK_INT_EQUAL(1, sentry_value_set_by_key_n(value, NULL, 0, payload)); - TEST_CHECK(sentry_value_refcount(payload) == 0); TEST_CHECK(sentry_value_get_length(value) == 0); payload = sentry_value_new_object(); @@ -582,7 +581,6 @@ SENTRY_TEST(value_set_by_null_key) TEST_CHECK_INT_EQUAL( 1, sentry_value_set_by_key_n(value, NULL, 10, payload)); TEST_CHECK(sentry_value_get_length(value) == 0); - TEST_CHECK(sentry_value_refcount(payload) == 0); sentry_value_decref(value); } From 9af0b2bbf4ca407da6c06800c655aa4cbedea9d8 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 12:15:35 +0200 Subject: [PATCH 04/36] Fix pytest macOS version assertions --- Makefile | 4 +++- tests/assertions.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6925df596c..2dc7c99146 100644 --- a/Makefile +++ b/Makefile @@ -25,8 +25,10 @@ test-unit: update-test-discovery CMakeLists.txt ./unit-build/sentry_test_unit .PHONY: test-unit +# SYSTEM_VERSION_COMPAT=0 is required (starting with BigSur) to get the correct macOS version for context assertions: +# https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-release-notes#Third-Party-Apps test-integration: setup-venv - .venv/bin/pytest tests --verbose + SYSTEM_VERSION_COMPAT=0 .venv/bin/pytest tests --verbose .PHONY: test-integration test-leaks: update-test-discovery CMakeLists.txt diff --git a/tests/assertions.py b/tests/assertions.py index 89fe1eec98..6bae5f60d6 100644 --- a/tests/assertions.py +++ b/tests/assertions.py @@ -7,7 +7,7 @@ from .conditions import is_android -VERSION_RE = re.compile(r"(\d+\.\d+\.\d+)(?:[-\.]?)(.*)") +VERSION_RE = re.compile(r"(\d+\.\d+\.\d+)[-.]?(.*)") def matches(actual, expected): @@ -95,7 +95,7 @@ def assert_meta( ) assert event["contexts"]["os"]["build"] is not None - if sdk_override != None: + if sdk_override is not None: expected_sdk["name"] = sdk_override assert_matches(event, expected) From 2cf44f5e6c29725fe588093180583d59eb7bf71d Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 12:18:59 +0200 Subject: [PATCH 05/36] Make ignored warning work on clang/gcc --- src/sentry_tracing.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sentry_tracing.c b/src/sentry_tracing.c index 931aa5ead6..8d47746a78 100644 --- a/src/sentry_tracing.c +++ b/src/sentry_tracing.c @@ -217,8 +217,14 @@ sentry_transaction_context_remove_sampled(sentry_transaction_context_t *tx_cxt) inner, "sampled", sentry_value_new_bool(sampled)); \ } -#pragma warning(push) -#pragma warning(disable : 4100) +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4100) // unreferenced formal parameter +#endif + #define CALL_STR_CHR(STR, CHR) strchr(STR, CHR) #define CALL_MEM_CHR(STR, CHR) memchr(STR, (int)value_len, CHR) GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( @@ -227,7 +233,12 @@ GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( sentry_transaction_context_update_from_header, STR_PARAM_FROM_NAME, CALL_STR_CHR) -#pragma warning(pop) + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif sentry_transaction_t * sentry__transaction_new(sentry_value_t inner) From 4744ebe8a682e41fdc04129348e3d01ddc6900b3 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 12:19:36 +0200 Subject: [PATCH 06/36] reformat test_value.c --- tests/unit/test_value.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index beeefab344..76cf60028a 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -110,9 +110,9 @@ SENTRY_TEST(value_string_n) TEST_CHECK(sentry_value_is_true(val) == false); sentry_value_decref(val); - char non_null_term_empty_str[] - = { 'h', 'e', 'l','l','o'}; - val = sentry_value_new_string_n(non_null_term_empty_str, sizeof(non_null_term_empty_str)); + char non_null_term_empty_str[] = { 'h', 'e', 'l', 'l', 'o' }; + val = sentry_value_new_string_n( + non_null_term_empty_str, sizeof(non_null_term_empty_str)); TEST_CHECK_STRING_EQUAL(sentry_value_as_string(val), "hello"); TEST_CHECK(sentry_value_get_type(val) == SENTRY_VALUE_TYPE_STRING); TEST_CHECK(sentry_value_is_true(val) == true); From 17ba2bbf118093fc615421896c88742de978e371 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 14:35:09 +0200 Subject: [PATCH 07/36] Update pytest deps --- tests/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/requirements.txt b/tests/requirements.txt index dd2fd18e86..4d181eb9d0 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,3 +1,3 @@ -black==22.3.0 -pytest==6.2.5 -pytest-httpserver==1.0.1 +black==23.3.0 +pytest==7.2.2 +pytest-httpserver==1.0.6 From 1b702a881b4c7f0208a6fe0505b77f3804439e9b Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 14:46:39 +0200 Subject: [PATCH 08/36] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69c253cc5a..952f1c4977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +**Features**: + +- Extend API with ptr/len-string interfaces. ([#827](https://github.com/getsentry/sentry-native/pull/827)) + ## 0.6.1 **Fixes**: From f77ac2452190e5fe0ae8fc614b0ac9e807661e36 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 15:09:58 +0200 Subject: [PATCH 09/36] Fix linter woes --- .github/workflows/ci.yml | 5 ++++- Makefile | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa8c1bb9a8..a5d03e81af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - run: make style + - run: | + sudo apt update + sudo apt install clang-format-15 + make style-15 build-ios: name: Xcode Build for iOS diff --git a/Makefile b/Makefile index 2dc7c99146..2497c88290 100644 --- a/Makefile +++ b/Makefile @@ -85,3 +85,9 @@ style: setup-venv @.venv/bin/python ./scripts/check-clang-format.py -r examples include src tests/unit @.venv/bin/black --diff --check tests .PHONY: style + +# TODO: workaround for clang-format changes in version 15+ were local formatting breaks with clang-format 14 on CI +style-15: setup-venv + @.venv/bin/python ./scripts/check-clang-format.py --clang-format-executable /usr/bin/clang-format-15 -r examples include src tests/unit + @.venv/bin/black --diff --check tests +.PHONY: style-15 From 649ed397c1bd919660bb5c319e59cbd98197cffb Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 15:13:40 +0200 Subject: [PATCH 10/36] clang-format 15 changes (puh) --- src/sentry_sync.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sentry_sync.h b/src/sentry_sync.h index 0741c30702..73531235b5 100644 --- a/src/sentry_sync.h +++ b/src/sentry_sync.h @@ -167,7 +167,10 @@ typedef HANDLE sentry_threadid_t; typedef struct sentry__winmutex_s sentry_mutex_t; # define SENTRY__MUTEX_INIT \ { \ - INIT_ONCE_STATIC_INIT, { 0 } \ + INIT_ONCE_STATIC_INIT, \ + { \ + 0 \ + } \ } # define sentry__mutex_init(Lock) sentry__winmutex_init(Lock) # define sentry__mutex_lock(Lock) sentry__winmutex_lock(Lock) From 277ba18773e04cba26551358f7b15d0e13078390 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 15:26:38 +0200 Subject: [PATCH 11/36] Fix code-checker issue in test_basic.c --- tests/unit/test_basic.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_basic.c b/tests/unit/test_basic.c index 77a895e32a..fc508bbd20 100644 --- a/tests/unit/test_basic.c +++ b/tests/unit/test_basic.c @@ -177,10 +177,11 @@ SENTRY_TEST(crashed_last_run) options = sentry_options_new(); const char *dsn_str = "https://foo@sentry.invalid/42"; - const char dsn[29] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'f', 'o', - 'o', '@', 's', 'e', 'n', 't', 'r', 'y', '.', 'i', 'n', 'v', 'a', 'l', - 'i', 'd', '/', '4', '2' }; + const char dsn[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'f', 'o', 'o', + '@', 's', 'e', 'n', 't', 'r', 'y', '.', 'i', 'n', 'v', 'a', 'l', 'i', + 'd', '/', '4', '2' }; sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); + TEST_CHECK_STRING_EQUAL(sentry_options_get_dsn(options), dsn_str); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); sentry_close(); From b7f870048ffd296e1b423a87fee3d12a68badb3a Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 15:47:13 +0200 Subject: [PATCH 12/36] Fix span/txn ownership in test_tracing --- tests/unit/test_tracing.c | 49 +++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/tests/unit/test_tracing.c b/tests/unit/test_tracing.c index 2f578c8698..d684796860 100644 --- a/tests/unit/test_tracing.c +++ b/tests/unit/test_tracing.c @@ -854,19 +854,24 @@ SENTRY_TEST(txn_tagging) sentry_transaction_remove_tag(txn, "os.name"); check_after_remove(txn->inner, "tags", "os.name"); + + sentry__transaction_decref(txn); } SENTRY_TEST(span_tagging) { - sentry_span_t *span - = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), - sentry_value_new_object()); + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + sentry_span_t *span = sentry__span_new(txn, sentry_value_new_object()); sentry_span_set_tag(span, "os.name", "Linux"); check_after_set(span->inner, "tags", "os.name", "Linux"); sentry_span_remove_tag(span, "os.name"); check_after_remove(span->inner, "tags", "os.name"); + + sentry__span_decref(span); + sentry__transaction_decref(txn); } SENTRY_TEST(txn_tagging_n) @@ -882,13 +887,15 @@ SENTRY_TEST(txn_tagging_n) sentry_transaction_remove_tag_n(txn, tag, sizeof(tag)); check_after_remove(txn->inner, "tags", "os.name"); + + sentry__transaction_decref(txn); } SENTRY_TEST(span_tagging_n) { - sentry_span_t *span - = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), - sentry_value_new_object()); + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + sentry_span_t *span = sentry__span_new(txn, sentry_value_new_object()); char tag[] = { 'o', 's', '.', 'n', 'a', 'm', 'e' }; char tag_val[] = { 'L', 'i', 'n', 'u', 'x' }; @@ -897,12 +904,16 @@ SENTRY_TEST(span_tagging_n) sentry_span_remove_tag_n(span, tag, sizeof(tag)); check_after_remove(span->inner, "tags", "os.name"); + + sentry__span_decref(span); + sentry__transaction_decref(txn); } SENTRY_TEST(txn_name) { sentry_transaction_t *txn = sentry__transaction_new(sentry_value_new_object()); + char *txn_name = "the_txn"; sentry_transaction_set_name(txn, txn_name); sentry_value_t txn_name_value @@ -910,6 +921,8 @@ SENTRY_TEST(txn_name) TEST_CHECK( sentry_value_get_type(txn_name_value) == SENTRY_VALUE_TYPE_STRING); TEST_CHECK_STRING_EQUAL(sentry_value_as_string(txn_name_value), txn_name); + + sentry__transaction_decref(txn); } SENTRY_TEST(txn_data) @@ -923,19 +936,24 @@ SENTRY_TEST(txn_data) sentry_transaction_remove_data(txn, "os.name"); check_after_remove(txn->inner, "data", "os.name"); + + sentry__transaction_decref(txn); } SENTRY_TEST(span_data) { - sentry_span_t *span - = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), - sentry_value_new_object()); + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + sentry_span_t *span = sentry__span_new(txn, sentry_value_new_object()); sentry_span_set_data(span, "os.name", sentry_value_new_string("Linux")); check_after_set(span->inner, "data", "os.name", "Linux"); sentry_span_remove_data(span, "os.name"); check_after_remove(span->inner, "data", "os.name"); + + sentry__span_decref(span); + sentry__transaction_decref(txn); } SENTRY_TEST(txn_name_n) @@ -950,6 +968,8 @@ SENTRY_TEST(txn_name_n) TEST_CHECK( sentry_value_get_type(txn_name_value) == SENTRY_VALUE_TYPE_STRING); TEST_CHECK_STRING_EQUAL(sentry_value_as_string(txn_name_value), "the_txn"); + + sentry__transaction_decref(txn); } SENTRY_TEST(txn_data_n) @@ -966,13 +986,15 @@ SENTRY_TEST(txn_data_n) sentry_transaction_remove_data_n(txn, data_k, sizeof(data_k)); check_after_remove(txn->inner, "data", "os.name"); + + sentry__transaction_decref(txn); } SENTRY_TEST(span_data_n) { - sentry_span_t *span - = sentry__span_new(sentry__transaction_new(sentry_value_new_object()), - sentry_value_new_object()); + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + sentry_span_t *span = sentry__span_new(txn, sentry_value_new_object()); char data_k[] = { 'o', 's', '.', 'n', 'a', 'm', 'e' }; char data_v[] = { 'L', 'i', 'n', 'u', 'x' }; @@ -983,6 +1005,9 @@ SENTRY_TEST(span_data_n) sentry_span_remove_data_n(span, data_k, sizeof(data_k)); check_after_remove(span->inner, "data", "os.name"); + + sentry__span_decref(span); + sentry__transaction_decref(txn); } #undef IS_NULL From 336cec02bb30ffa539944691e90533c155cef4af Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 15:50:04 +0200 Subject: [PATCH 13/36] fix typo --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2497c88290..f8c5971de9 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ style: setup-venv @.venv/bin/black --diff --check tests .PHONY: style -# TODO: workaround for clang-format changes in version 15+ were local formatting breaks with clang-format 14 on CI +# TODO: workaround for clang-format 15+ where local formatting breaks with clang-format-14 based style checks on CI style-15: setup-venv @.venv/bin/python ./scripts/check-clang-format.py --clang-format-executable /usr/bin/clang-format-15 -r examples include src tests/unit @.venv/bin/black --diff --check tests From 52062433c38e47d7cdffe7d7e42aef791e7463a4 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 29 Mar 2023 17:14:51 +0200 Subject: [PATCH 14/36] minor integration-test clean-ups after battling said test --- tests/test_integration_http.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/tests/test_integration_http.py b/tests/test_integration_http.py index 2bca41e6d9..400b639bdf 100644 --- a/tests/test_integration_http.py +++ b/tests/test_integration_http.py @@ -1,13 +1,10 @@ -import time import pytest -import subprocess -import sys import os import time import itertools import uuid import json -from . import make_dsn, check_output, run, Envelope +from . import make_dsn, run, Envelope from .conditions import has_http, has_breakpad, has_files from .assertions import ( assert_attachment, @@ -217,7 +214,7 @@ def test_inproc_crash_http(cmake, httpserver): ["log", "start-session", "attachment", "crash"], env=env, ) - assert child.returncode # well, its a crash after all + assert child.returncode # well, it's a crash after all run( tmp_path, @@ -254,7 +251,7 @@ def test_inproc_reinstall(cmake, httpserver): ["log", "reinstall", "crash"], env=env, ) - assert child.returncode # well, its a crash after all + assert child.returncode # well, it's a crash after all run( tmp_path, @@ -279,8 +276,7 @@ def test_inproc_dump_inflight(cmake, httpserver): child = run( tmp_path, "sentry_example", ["log", "capture-multiple", "crash"], env=env ) - assert child.returncode # well, its a crash after all - + assert child.returncode # well, it's a crash after all run(tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env) # we trigger 10 normal events, and 1 crash @@ -303,7 +299,7 @@ def test_breakpad_crash_http(cmake, httpserver): ["log", "start-session", "attachment", "crash"], env=env, ) - assert child.returncode # well, its a crash after all + assert child.returncode # well, it's a crash after all run( tmp_path, @@ -341,7 +337,7 @@ def test_breakpad_reinstall(cmake, httpserver): ["log", "reinstall", "crash"], env=env, ) - assert child.returncode # well, its a crash after all + assert child.returncode # well, it's a crash after all run( tmp_path, @@ -367,7 +363,7 @@ def test_breakpad_dump_inflight(cmake, httpserver): child = run( tmp_path, "sentry_example", ["log", "capture-multiple", "crash"], env=env ) - assert child.returncode # well, its a crash after all + assert child.returncode # well, it's a crash after all run(tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env) @@ -405,6 +401,7 @@ def delayed(req): env=env, check=True, ) + assert child.returncode == 0 httpserver.clear_all_handlers() httpserver.clear_log() @@ -419,6 +416,9 @@ def delayed(req): assert len(httpserver.log) == 10 +RFC3339_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" + + def test_transaction_only(cmake, httpserver): tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "none"}) @@ -450,10 +450,10 @@ def test_transaction_only(cmake, httpserver): (event,) = envelope.items assert event.headers["type"] == "transaction" - json = event.payload.json + payload = event.payload.json # See https://develop.sentry.dev/sdk/performance/trace-context/#trace-context - trace_context = json["contexts"]["trace"] + trace_context = payload["contexts"]["trace"] assert ( trace_context["op"] == "Short and stout here is my handle and here is my spout" @@ -469,8 +469,7 @@ def test_transaction_only(cmake, httpserver): assert trace_context["span_id"] assert trace_context["status"] == "ok" - RFC3339_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" - start_timestamp = time.strptime(json["start_timestamp"], RFC3339_FORMAT) + start_timestamp = time.strptime(payload["start_timestamp"], RFC3339_FORMAT) assert start_timestamp - timestamp = time.strptime(json["timestamp"], RFC3339_FORMAT) + timestamp = time.strptime(payload["timestamp"], RFC3339_FORMAT) assert timestamp >= start_timestamp From f7781d826b153f5113b036dc9aeaf823642af5f0 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 18 Apr 2023 20:49:36 +0200 Subject: [PATCH 15/36] get rid of macros and increase coverage --- src/path/sentry_path_unix.c | 28 +-- src/sentry_core.c | 60 ++--- src/sentry_envelope.c | 41 ++-- src/sentry_string.h | 20 -- src/sentry_tracing.c | 430 +++++++++++++++++------------------- src/sentry_tracing.h | 8 +- src/sentry_utils.c | 140 ++++++------ src/sentry_value.c | 205 ++++++++--------- tests/unit/test_envelopes.c | 70 +++++- tests/unit/test_path.c | 7 + tests/unit/test_tracing.c | 102 ++++++++- tests/unit/test_utils.c | 34 ++- tests/unit/test_value.c | 109 +++++++++ tests/unit/tests.inc | 16 ++ 14 files changed, 773 insertions(+), 497 deletions(-) diff --git a/src/path/sentry_path_unix.c b/src/path/sentry_path_unix.c index 063ed0b0de..91d18e179e 100644 --- a/src/path/sentry_path_unix.c +++ b/src/path/sentry_path_unix.c @@ -168,20 +168,22 @@ sentry__path_dir(const sentry_path_t *path) return sentry__path_from_str_owned(newpathbuf); } -#define GEN_SENTRY__PATH_FROM_STR(FN, GEN_STR_PARAM, STR_CLONE_FN) \ - sentry_path_t *FN(GEN_STR_PARAM(s)) \ - { \ - char *path = STR_CLONE_FN(s); \ - if (!path) { \ - return NULL; \ - } \ - /* NOTE: function will free `path` on error */ \ - return sentry__path_from_str_owned(path); \ +sentry_path_t * +sentry__path_from_str_n(const char *s, size_t s_len) +{ + char *path = sentry__string_clonen_or_null(s, s_len); + if (!path) { + return NULL; } -GEN_SENTRY__PATH_FROM_STR(sentry__path_from_str_n, PTR_LEN_PARAM_FROM_NAME, - CALL_SENTRY__STRING_CLONE_N) -GEN_SENTRY__PATH_FROM_STR( - sentry__path_from_str, STR_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE) + /* NOTE: function will free `path` on error */ + return sentry__path_from_str_owned(path); +} + +sentry_path_t * +sentry__path_from_str(const char *s) +{ + return s ? sentry__path_from_str_n(s, strlen(s)) : NULL; +} sentry_path_t * sentry__path_from_str_owned(char *s) diff --git a/src/sentry_core.c b/src/sentry_core.c index a6547d07ba..110f0737d0 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -932,33 +932,39 @@ sentry_set_span(sentry_span_t *span) } } -#define GEN_SENTRY_TRANSACTION_START_CHILD( \ - FN, STR_PARAM_GEN, NEW_SPAN_VALUE_FN) \ - sentry_span_t *FN(sentry_transaction_t *opaque_parent, \ - STR_PARAM_GEN(operation), STR_PARAM_GEN(description)) \ - { \ - if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) { \ - SENTRY_DEBUG("no transaction available to create a child under"); \ - return NULL; \ - } \ - sentry_value_t parent = opaque_parent->inner; \ - \ - /* TODO: consider snapshotting this value during tx creation and \ - * storing in tx and span */ \ - size_t max_spans = SENTRY_SPANS_MAX; \ - SENTRY_WITH_OPTIONS (options) { \ - max_spans = options->max_spans; \ - } \ - \ - sentry_value_t span \ - = NEW_SPAN_VALUE_FN(max_spans, parent, operation, description); \ - return sentry__span_new(opaque_parent, span); \ - } - -GEN_SENTRY_TRANSACTION_START_CHILD(sentry_transaction_start_child, - STR_PARAM_FROM_NAME, CALL_SENTRY__VALUE_SPAN_NEW) -GEN_SENTRY_TRANSACTION_START_CHILD(sentry_transaction_start_child_n, - PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__VALUE_SPAN_NEW_N) +sentry_span_t * +sentry_transaction_start_child_n(sentry_transaction_t *opaque_parent, + const char *operation, size_t operation_len, const char *description, + size_t description_len) +{ + if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) { + SENTRY_DEBUG("no transaction available to create a child under"); + return NULL; + } + sentry_value_t parent = opaque_parent->inner; + + /* TODO: consider snapshotting this value during tx creation and + * storing in tx and span */ + size_t max_spans = SENTRY_SPANS_MAX; + SENTRY_WITH_OPTIONS (options) { + max_spans = options->max_spans; + } + + sentry_value_t span = sentry__value_span_new_n(max_spans, parent, + (sentry_slice_t) { operation, operation_len }, + (sentry_slice_t) { description, description_len }); + return sentry__span_new(opaque_parent, span); +} + +sentry_span_t * +sentry_transaction_start_child(sentry_transaction_t *opaque_parent, + const char *operation, const char *description) +{ + const size_t operation_len = operation ? strlen(operation) : 0; + const size_t description_len = description ? strlen(description) : 0; + return sentry_transaction_start_child_n( + opaque_parent, operation, operation_len, description, description_len); +} sentry_span_t * sentry_span_start_child(sentry_span_t *opaque_parent, const char *operation, diff --git a/src/sentry_envelope.c b/src/sentry_envelope.c index 3cab2cd20f..3898f3f0b3 100644 --- a/src/sentry_envelope.c +++ b/src/sentry_envelope.c @@ -458,21 +458,32 @@ sentry_envelope_write_to_path( return rv; } -#define GEN_SENTRY_ENVELOPE_WRITE_TO_FILE(FN, GEN_STR_PARAM, PATH_FROM_STR_FN) \ - int FN(const sentry_envelope_t *envelope, GEN_STR_PARAM(path)) \ - { \ - sentry_path_t *path_obj = PATH_FROM_STR_FN(path); \ - \ - int rv = sentry_envelope_write_to_path(envelope, path_obj); \ - \ - sentry__path_free(path_obj); \ - \ - return rv; \ - } -GEN_SENTRY_ENVELOPE_WRITE_TO_FILE(sentry_envelope_write_to_file_n, - PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__PATH_FROM_STR_N) -GEN_SENTRY_ENVELOPE_WRITE_TO_FILE(sentry_envelope_write_to_file, - STR_PARAM_FROM_NAME, CALL_SENTRY__PATH_FROM_STR) +int +sentry_envelope_write_to_file_n( + const sentry_envelope_t *envelope, const char *path, size_t path_len) +{ + if (!envelope || !path) { + return 1; + } + sentry_path_t *path_obj = sentry__path_from_str_n(path, path_len); + + int rv = sentry_envelope_write_to_path(envelope, path_obj); + + sentry__path_free(path_obj); + + return rv; +} + +int +sentry_envelope_write_to_file( + const sentry_envelope_t *envelope, const char *path) +{ + if (!envelope || !path) { + return 1; + } + + return sentry_envelope_write_to_file_n(envelope, path, strlen(path)); +} #ifdef SENTRY_UNITTEST size_t diff --git a/src/sentry_string.h b/src/sentry_string.h index 72708a7d55..9d566229c6 100644 --- a/src/sentry_string.h +++ b/src/sentry_string.h @@ -7,15 +7,6 @@ #include #include -#define STR_PARAM_FROM_NAME(NAME) const char *NAME -#define PTR_LEN_PARAM_FROM_NAME(NAME) \ - STR_PARAM_FROM_NAME(NAME), size_t NAME##_len -#define CALL_SENTRY__STRING_CLONE_N(STR) \ - sentry__string_clonen_or_null(STR, STR##_len) -#define CALL_SENTRY__STRING_CLONE(STR) sentry__string_clone(STR) -#define CALL_SENTRY_VALUE_NEW_STRING(STR) sentry_value_new_string(STR) -#define CALL_SENTRY_VALUE_NEW_STRING_N(STR) \ - sentry_value_new_string_n(STR, STR##_len) /** * A string builder, which can be used as a mutable, growable string buffer. */ @@ -148,17 +139,6 @@ sentry__string_clone(const char *str) return str ? sentry__string_clonen(str, strlen(str)) : NULL; } -static inline char * -sentry__string_clone_max(const char *str, size_t max_len) -{ - if (!str) { - return NULL; - } - size_t str_len = strlen(str); - size_t min_len = str_len < max_len ? str_len : max_len; - return sentry__string_clonen(str, min_len); -} - static inline char * sentry__string_clone_max_n(const char *str, size_t str_len, size_t max_len) { diff --git a/src/sentry_tracing.c b/src/sentry_tracing.c index 8d47746a78..779fb278cb 100644 --- a/src/sentry_tracing.c +++ b/src/sentry_tracing.c @@ -1,96 +1,86 @@ #include "sentry_tracing.h" +#include "sentry.h" #include "sentry_alloc.h" #include "sentry_logger.h" +#include "sentry_slice.h" #include "sentry_string.h" #include "sentry_utils.h" #include "sentry_value.h" #include -#define GEN_SENTRY__VALUE_NEW_SPAN(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ - sentry_value_t FN(sentry_value_t parent, GEN_STR_PARAM(operation)) \ - { \ - sentry_value_t span = sentry_value_new_object(); \ - \ - sentry_value_set_by_key(span, "op", VALUE_NEW_STR_FN(operation)); \ - \ - sentry_uuid_t span_id = sentry_uuid_new_v4(); \ - sentry_value_set_by_key( \ - span, "span_id", sentry__value_new_span_uuid(&span_id)); \ - \ - sentry_value_set_by_key( \ - span, "status", sentry_value_new_string("ok")); \ - \ - if (!sentry_value_is_null(parent)) { \ - sentry_value_set_by_key(span, "trace_id", \ - sentry_value_get_by_key_owned(parent, "trace_id")); \ - sentry_value_set_by_key(span, "parent_span_id", \ - sentry_value_get_by_key_owned(parent, "span_id")); \ - sentry_value_set_by_key(span, "sampled", \ - sentry_value_get_by_key_owned(parent, "sampled")); \ - } \ - \ - return span; \ - } - -GEN_SENTRY__VALUE_NEW_SPAN(sentry__value_new_span_n, PTR_LEN_PARAM_FROM_NAME, - CALL_SENTRY_VALUE_NEW_STRING_N) -GEN_SENTRY__VALUE_NEW_SPAN( - sentry__value_new_span, STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) -#define CALL_SENTRY__VALUE_NEW_SPAN_N(VAL, STR) \ - sentry__value_new_span_n(VAL, STR, STR##_len) -#define CALL_SENTRY__VALUE_NEW_SPAN(VAL, STR) sentry__value_new_span(VAL, STR) - -#define GEN_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW( \ - FN, GEN_STR_PARAM, NEW_SPAN_VALUE_FUN, NEW_STR_VALUE_FUN) \ - sentry_value_t FN(GEN_STR_PARAM(name), GEN_STR_PARAM(operation)) \ - { \ - sentry_value_t transaction_context \ - = NEW_SPAN_VALUE_FUN(sentry_value_new_null(), operation); \ - \ - sentry_uuid_t trace_id = sentry_uuid_new_v4(); \ - sentry_value_set_by_key(transaction_context, "trace_id", \ - sentry__value_new_internal_uuid(&trace_id)); \ - \ - sentry_value_set_by_key( \ - transaction_context, "transaction", NEW_STR_VALUE_FUN(name)); \ - \ - return transaction_context; \ - } - -GEN_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW( - sentry__value_transaction_context_new_n, PTR_LEN_PARAM_FROM_NAME, - CALL_SENTRY__VALUE_NEW_SPAN_N, CALL_SENTRY_VALUE_NEW_STRING_N) -GEN_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW(sentry__value_transaction_context_new, - STR_PARAM_FROM_NAME, CALL_SENTRY__VALUE_NEW_SPAN, - CALL_SENTRY_VALUE_NEW_STRING) -#define CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW_N(NAME, OP) \ - sentry__value_transaction_context_new_n(NAME, NAME##_len, OP, OP##_len) -#define CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW(NAME, OP) \ - sentry__value_transaction_context_new(NAME, OP) - -#define GEN_SENTRY_TRANSACTION_CONTEXT_NEW(FN, GEN_STR_PARAM, NEW_TXN_CTX_FN) \ - sentry_transaction_context_t *FN( \ - GEN_STR_PARAM(name), GEN_STR_PARAM(operation)) \ - { \ - sentry_transaction_context_t *tx_cxt \ - = SENTRY_MAKE(sentry_transaction_context_t); \ - if (!tx_cxt) { \ - return NULL; \ - } \ - tx_cxt->inner = NEW_TXN_CTX_FN(name, operation); \ - \ - if (sentry_value_is_null(tx_cxt->inner)) { \ - sentry_free(tx_cxt); \ - return NULL; \ - } \ - \ - return tx_cxt; \ +sentry_value_t +sentry__value_new_span_n(sentry_value_t parent, sentry_slice_t operation) +{ + sentry_value_t span = sentry_value_new_object(); + + sentry_value_set_by_key( + span, "op", sentry_value_new_string_n(operation.ptr, operation.len)); + + sentry_uuid_t span_id = sentry_uuid_new_v4(); + sentry_value_set_by_key( + span, "span_id", sentry__value_new_span_uuid(&span_id)); + + sentry_value_set_by_key(span, "status", sentry_value_new_string("ok")); + + if (!sentry_value_is_null(parent)) { + sentry_value_set_by_key(span, "trace_id", + sentry_value_get_by_key_owned(parent, "trace_id")); + sentry_value_set_by_key(span, "parent_span_id", + sentry_value_get_by_key_owned(parent, "span_id")); + sentry_value_set_by_key( + span, "sampled", sentry_value_get_by_key_owned(parent, "sampled")); } -GEN_SENTRY_TRANSACTION_CONTEXT_NEW(sentry_transaction_context_new_n, - PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW_N) -GEN_SENTRY_TRANSACTION_CONTEXT_NEW(sentry_transaction_context_new, - STR_PARAM_FROM_NAME, CALL_SENTRY__VALUE_TRANSACTION_CONTEXT_NEW) + return span; +} + +sentry_value_t +sentry__value_transaction_context_new_n( + sentry_slice_t name, sentry_slice_t operation) +{ + sentry_value_t transaction_context + = sentry__value_new_span_n(sentry_value_new_null(), operation); + + sentry_uuid_t trace_id = sentry_uuid_new_v4(); + sentry_value_set_by_key(transaction_context, "trace_id", + sentry__value_new_internal_uuid(&trace_id)); + + sentry_value_set_by_key(transaction_context, "transaction", + sentry_value_new_string_n(name.ptr, name.len)); + + return transaction_context; +} + +sentry_transaction_context_t * +sentry_transaction_context_new_n(const char *name, size_t name_len, + const char *operation, size_t operation_len) +{ + sentry_transaction_context_t *tx_cxt + = SENTRY_MAKE(sentry_transaction_context_t); + if (!tx_cxt) { + return NULL; + } + tx_cxt->inner = sentry__value_transaction_context_new_n( + (sentry_slice_t) { name, name_len }, + (sentry_slice_t) { operation, operation_len }); + + if (sentry_value_is_null(tx_cxt->inner)) { + sentry_free(tx_cxt); + return NULL; + } + + return tx_cxt; +} + +sentry_transaction_context_t * +sentry_transaction_context_new(const char *name, const char *operation) +{ + size_t name_len = name ? strlen(name) : 0; + size_t operation_len = operation ? strlen(operation) : 0; + + return sentry_transaction_context_new_n( + name, name_len, operation, operation_len); +} void sentry__transaction_context_free(sentry_transaction_context_t *tx_cxt) @@ -164,81 +154,70 @@ sentry_transaction_context_remove_sampled(sentry_transaction_context_t *tx_cxt) } } -#define GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( \ - FN, GEN_STR_PARAM, STR_CHR_FN) \ - void FN(sentry_transaction_context_t *tx_cxt, GEN_STR_PARAM(key), \ - GEN_STR_PARAM(value)) \ - { \ - if (!tx_cxt) { \ - return; \ - } \ - \ - /* do case-insensitive header key comparison */ \ - const char sentry_trace[] = "sentry-trace"; \ - for (size_t i = 0; i < sizeof(sentry_trace); i++) { \ - if (tolower(key[i]) != sentry_trace[i]) { \ - return; \ - } \ - } \ - \ - /* https://develop.sentry.dev/sdk/performance/#header-sentry-trace \ - * sentry-trace = traceid-spanid(-sampled)? \ - */ \ - const char *trace_id_start = value; \ - const char *trace_id_end = STR_CHR_FN(trace_id_start, '-'); \ - if (!trace_id_end) { \ - return; \ - } \ - \ - sentry_value_t inner = tx_cxt->inner; \ - \ - char *s = sentry__string_clonen( \ - trace_id_start, trace_id_end - trace_id_start); \ - sentry_value_t trace_id = sentry__value_new_string_owned(s); \ - sentry_value_set_by_key(inner, "trace_id", trace_id); \ - \ - const char *span_id_start = trace_id_end + 1; \ - const char *span_id_end = strchr(span_id_start, '-'); \ - if (!span_id_end) { \ - /* no sampled flag */ \ - sentry_value_t parent_span_id \ - = sentry_value_new_string(span_id_start); \ - sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); \ - return; \ - } \ - /* else: we have a sampled flag */ \ - \ - s = sentry__string_clonen(span_id_start, span_id_end - span_id_start); \ - sentry_value_t parent_span_id = sentry__value_new_string_owned(s); \ - sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); \ - \ - bool sampled = *(span_id_end + 1) == '1'; \ - sentry_value_set_by_key( \ - inner, "sampled", sentry_value_new_bool(sampled)); \ - } - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-parameter" -#elif defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4100) // unreferenced formal parameter -#endif - -#define CALL_STR_CHR(STR, CHR) strchr(STR, CHR) -#define CALL_MEM_CHR(STR, CHR) memchr(STR, (int)value_len, CHR) -GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( - sentry_transaction_context_update_from_header_n, PTR_LEN_PARAM_FROM_NAME, - CALL_MEM_CHR) -GEN_SENTRY_TRANSACTION_CONTEXT_UPDATE_FROM_HEADER( - sentry_transaction_context_update_from_header, STR_PARAM_FROM_NAME, - CALL_STR_CHR) - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#elif defined(_MSC_VER) -# pragma warning(pop) -#endif +void +sentry_transaction_context_update_from_header_n( + sentry_transaction_context_t *tx_cxt, const char *key, size_t key_len, + const char *value, size_t value_len) +{ + if (!tx_cxt) { + return; + } + + // do case-insensitive header key comparison + const char sentry_trace[] = "sentry-trace"; + const size_t sentry_trace_len = sizeof(sentry_trace) - 1; + if (key_len != sentry_trace_len) { + return; + } + for (size_t i = 0; i < sentry_trace_len; i++) { + if (tolower(key[i]) != sentry_trace[i]) { + return; + } + } + + // https://develop.sentry.dev/sdk/performance/#header-sentry-trace + // sentry-trace = traceid-spanid(-sampled)? + const char *trace_id_start = value; + const char *trace_id_end = memchr(trace_id_start, '-', value_len); + if (!trace_id_end) { + return; + } + + sentry_value_t inner = tx_cxt->inner; + + char *s + = sentry__string_clonen(trace_id_start, trace_id_end - trace_id_start); + sentry_value_t trace_id = sentry__value_new_string_owned(s); + sentry_value_set_by_key(inner, "trace_id", trace_id); + + const char *span_id_start = trace_id_end + 1; + const char *span_id_end = strchr(span_id_start, '-'); + if (!span_id_end) { + // no sampled flag + sentry_value_t parent_span_id = sentry_value_new_string(span_id_start); + sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); + return; + } + // else: we have a sampled flag + + s = sentry__string_clonen(span_id_start, span_id_end - span_id_start); + sentry_value_t parent_span_id = sentry__value_new_string_owned(s); + sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); + + bool sampled = *(span_id_end + 1) == '1'; + sentry_value_set_by_key(inner, "sampled", sentry_value_new_bool(sampled)); +} + +void +sentry_transaction_context_update_from_header( + sentry_transaction_context_t *tx_cxt, const char *key, const char *value) +{ + size_t key_len = key ? strlen(key) : 0; + size_t value_len = value ? strlen(value) : 0; + + sentry_transaction_context_update_from_header_n( + tx_cxt, key, key_len, value, value_len); +} sentry_transaction_t * sentry__transaction_new(sentry_value_t inner) @@ -324,45 +303,47 @@ sentry__span_new(sentry_transaction_t *tx, sentry_value_t inner) return span; } -#define GEN_SENTRY__VALUE_SPAN_NEW( \ - FN, GEN_STR_PARAM, VALUE_NEW_SPAN_FN, VALUE_NEW_STR_FN) \ - sentry_value_t FN(size_t max_spans, sentry_value_t parent, \ - GEN_STR_PARAM(operation), GEN_STR_PARAM(description)) \ - { \ - if (!sentry_value_is_null( \ - sentry_value_get_by_key(parent, "timestamp"))) { \ - SENTRY_DEBUG( \ - "span's parent is already finished, not creating span"); \ - goto fail; \ - } \ - \ - sentry_value_t spans = sentry_value_get_by_key(parent, "spans"); \ - /* This only checks that the number of _completed_ spans matches the \ - * number of max spans. This means that the number of in-flight spans \ - * can exceed the max number of spans. */ \ - if (sentry_value_get_length(spans) >= max_spans) { \ - SENTRY_DEBUG( \ - "reached maximum number of spans for transaction, not " \ - "creating span"); \ - goto fail; \ - } \ - \ - sentry_value_t child = VALUE_NEW_SPAN_FN(parent, operation); \ - sentry_value_set_by_key( \ - child, "description", VALUE_NEW_STR_FN(description)); \ - sentry_value_set_by_key(child, "start_timestamp", \ - sentry__value_new_string_owned( \ - sentry__msec_time_to_iso8601(sentry__msec_time()))); \ - \ - return child; \ - fail: \ - return sentry_value_new_null(); \ - } - -GEN_SENTRY__VALUE_SPAN_NEW(sentry__value_span_new_n, PTR_LEN_PARAM_FROM_NAME, - CALL_SENTRY__VALUE_NEW_SPAN_N, CALL_SENTRY_VALUE_NEW_STRING_N) -GEN_SENTRY__VALUE_SPAN_NEW(sentry__value_span_new, STR_PARAM_FROM_NAME, - CALL_SENTRY__VALUE_NEW_SPAN, CALL_SENTRY_VALUE_NEW_STRING) +sentry_value_t +sentry__value_span_new_n(size_t max_spans, sentry_value_t parent, + sentry_slice_t operation, sentry_slice_t description) +{ + if (!sentry_value_is_null(sentry_value_get_by_key(parent, "timestamp"))) { + SENTRY_DEBUG("span's parent is already finished, not creating span"); + goto fail; + } + + sentry_value_t spans = sentry_value_get_by_key(parent, "spans"); + // This only checks that the number of _completed_ spans matches the + // number of max spans. This means that the number of in-flight spans + // can exceed the max number of spans. + if (sentry_value_get_length(spans) >= max_spans) { + SENTRY_DEBUG("reached maximum number of spans for transaction, not " + "creating span"); + goto fail; + } + + sentry_value_t child = sentry__value_new_span_n(parent, operation); + sentry_value_set_by_key(child, "description", + sentry_value_new_string_n(description.ptr, description.len)); + sentry_value_set_by_key(child, "start_timestamp", + sentry__value_new_string_owned( + sentry__msec_time_to_iso8601(sentry__msec_time()))); + + return child; +fail: + return sentry_value_new_null(); +} + +sentry_value_t +sentry__value_span_new(size_t max_spans, sentry_value_t parent, + const char *operation, const char *description) +{ + const size_t operation_len = operation ? strlen(operation) : 0; + const size_t description_len = description ? strlen(description) : 0; + return sentry__value_span_new_n(max_spans, parent, + (sentry_slice_t) { operation, operation_len }, + (sentry_slice_t) { description, description_len }); +} sentry_value_t sentry__value_get_trace_context(sentry_value_t span) @@ -419,37 +400,28 @@ sentry_transaction_set_name_n( } } -#define GEN_SET_TAG(FN, GEN_STR_PARAM, MAX_CLONE_FN, VALUE_SET_BY_KEY_FN) \ - static void FN( \ - sentry_value_t item, GEN_STR_PARAM(tag), GEN_STR_PARAM(value)) \ - { \ - sentry_value_t tags = sentry_value_get_by_key(item, "tags"); \ - if (sentry_value_is_null(tags)) { \ - tags = sentry_value_new_object(); \ - sentry_value_set_by_key(item, "tags", tags); \ - } \ - \ - char *s = MAX_CLONE_FN(value, 200); \ - if (s) { \ - VALUE_SET_BY_KEY_FN(tags, tag, sentry__value_new_string_owned(s)); \ - } else { \ - VALUE_SET_BY_KEY_FN(tags, tag, sentry_value_new_null()); \ - } \ +static void +set_tag_n(sentry_value_t item, sentry_slice_t tag, sentry_slice_t value) +{ + sentry_value_t tags = sentry_value_get_by_key(item, "tags"); + if (sentry_value_is_null(tags)) { + tags = sentry_value_new_object(); + sentry_value_set_by_key(item, "tags", tags); } + char *s = sentry__string_clone_max_n(value.ptr, value.len, 200); + sentry_value_t tag_value + = s ? sentry__value_new_string_owned(s) : sentry_value_new_null(); + sentry_value_set_by_key_n(tags, tag.ptr, tag.len, tag_value); +} -#define CALL_SENTRY__STRING_CLONE_MAX(STR, MAX_LEN) \ - sentry__string_clone_max(STR, MAX_LEN) -#define CALL_SENTRY__STRING_CLONE_MAX_N(STR, MAX_LEN) \ - sentry__string_clone_max_n(STR, STR##_len, MAX_LEN) -#define CALL_SENTRY_VALUE_SET_BY_KEY(VAL, K, V) \ - sentry_value_set_by_key(VAL, K, V) -#define CALL_SENTRY_VALUE_SET_BY_KEY_N(VAL, K, V) \ - sentry_value_set_by_key_n(VAL, K, K##_len, V) - -GEN_SET_TAG(set_tag, STR_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE_MAX, - CALL_SENTRY_VALUE_SET_BY_KEY) -GEN_SET_TAG(set_tag_n, PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE_MAX_N, - CALL_SENTRY_VALUE_SET_BY_KEY_N) +static void +set_tag(sentry_value_t item, const char *tag, const char *value) +{ + const size_t tag_len = tag ? strlen(tag) : 0; + const size_t value_len = value ? strlen(value) : 0; + set_tag_n(item, (sentry_slice_t) { tag, tag_len }, + (sentry_slice_t) { value, value_len }); +} void sentry_transaction_set_tag( @@ -465,7 +437,8 @@ sentry_transaction_set_tag_n(sentry_transaction_t *tx, const char *tag, size_t tag_len, const char *value, size_t value_len) { if (tx) { - set_tag_n(tx->inner, tag, tag_len, value, value_len); + set_tag_n(tx->inner, (sentry_slice_t) { tag, tag_len }, + (sentry_slice_t) { value, value_len }); } } @@ -482,7 +455,8 @@ sentry_span_set_tag_n(sentry_span_t *span, const char *tag, size_t tag_len, const char *value, size_t value_len) { if (span) { - set_tag_n(span->inner, tag, tag_len, value, value_len); + set_tag_n(span->inner, (sentry_slice_t) { tag, tag_len }, + (sentry_slice_t) { value, value_len }); } } diff --git a/src/sentry_tracing.h b/src/sentry_tracing.h index 5f7036324d..d312b1cd41 100644 --- a/src/sentry_tracing.h +++ b/src/sentry_tracing.h @@ -1,6 +1,7 @@ #ifndef SENTRY_TRACING_H_INCLUDED #define SENTRY_TRACING_H_INCLUDED +#include "sentry_slice.h" #include "sentry_value.h" /** @@ -38,12 +39,7 @@ void sentry__span_decref(sentry_span_t *span); sentry_value_t sentry__value_span_new(size_t max_spans, sentry_value_t parent, const char *operation, const char *description); sentry_value_t sentry__value_span_new_n(size_t max_spans, sentry_value_t parent, - const char *operation, size_t operation_len, const char *description, - size_t description_len); -#define CALL_SENTRY__VALUE_SPAN_NEW_N(MAX_SPANS, PARENT, OP, DESC) \ - sentry__value_span_new_n(MAX_SPANS, PARENT, OP, OP##_len, DESC, DESC##_len) -#define CALL_SENTRY__VALUE_SPAN_NEW(MAX_SPANS, PARENT, OP, DESC) \ - sentry__value_span_new(MAX_SPANS, PARENT, OP, DESC) + sentry_slice_t operation, sentry_slice_t description); sentry_span_t *sentry__span_new( sentry_transaction_t *parent_tx, sentry_value_t inner); diff --git a/src/sentry_utils.c b/src/sentry_utils.c index 1cd104989c..f3aacb04e3 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -4,11 +4,9 @@ #include "sentry_boot.h" #include "sentry_alloc.h" -#include "sentry_core.h" #include "sentry_string.h" #include "sentry_sync.h" #include "sentry_utils.h" -#include #include #include #include @@ -212,73 +210,77 @@ sentry__url_cleanup(sentry_url_t *url) memset(url, 0, sizeof(sentry_url_t)); } -#define GEN_SENTRY__DSN_NEW(FN, GEN_STR_PARAM, STR_CLONE_FN) \ - sentry_dsn_t *FN(GEN_STR_PARAM(raw_dsn)) \ - { \ - sentry_url_t url; \ - memset(&url, 0, sizeof(sentry_url_t)); \ - size_t path_len; \ - char *project_id; \ - \ - sentry_dsn_t *dsn = SENTRY_MAKE(sentry_dsn_t); \ - if (!dsn) { \ - return NULL; \ - } \ - memset(dsn, 0, sizeof(sentry_dsn_t)); \ - dsn->refcount = 1; \ - \ - dsn->raw = STR_CLONE_FN(raw_dsn); \ - if (!dsn->raw || !dsn->raw[0] \ - || sentry__url_parse(&url, dsn->raw) != 0) { \ - goto exit; \ - } \ - \ - if (sentry__string_eq(url.scheme, "https")) { \ - dsn->is_secure = 1; \ - } else if (sentry__string_eq(url.scheme, "http")) { \ - dsn->is_secure = 0; \ - } else { \ - goto exit; \ - } \ - \ - dsn->host = url.host; \ - url.host = NULL; \ - dsn->public_key = url.username; \ - url.username = NULL; \ - dsn->secret_key = url.password; \ - url.password = NULL; \ - dsn->port = url.port; \ - \ - path_len = strlen(url.path); \ - while (path_len > 0 && url.path[path_len - 1] == '/') { \ - url.path[path_len - 1] = '\0'; \ - path_len--; \ - } \ - \ - project_id = strrchr(url.path, '/'); \ - if (!project_id || strlen(project_id + 1) == 0) { \ - goto exit; \ - } \ - \ - dsn->project_id = sentry__string_clone(project_id + 1); \ - *project_id = 0; \ - \ - dsn->path = url.path; \ - url.path = NULL; \ - \ - if (dsn->public_key && dsn->host && dsn->path) { \ - dsn->is_valid = true; \ - } \ - \ - exit: \ - sentry__url_cleanup(&url); \ - return dsn; \ - } - -GEN_SENTRY__DSN_NEW( - sentry__dsn_new_n, PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE_N) -GEN_SENTRY__DSN_NEW( - sentry__dsn_new, STR_PARAM_FROM_NAME, CALL_SENTRY__STRING_CLONE) +sentry_dsn_t * +sentry__dsn_new_n(const char *raw_dsn, size_t raw_dsn_len) +{ + sentry_url_t url; + memset(&url, 0, sizeof(sentry_url_t)); + size_t path_len; + char *project_id; + + sentry_dsn_t *dsn = SENTRY_MAKE(sentry_dsn_t); + if (!dsn) { + return NULL; + } + memset(dsn, 0, sizeof(sentry_dsn_t)); + dsn->refcount = 1; + + dsn->raw = sentry__string_clonen_or_null(raw_dsn, raw_dsn_len); + if (!dsn->raw || !dsn->raw[0] || sentry__url_parse(&url, dsn->raw) != 0) { + goto exit; + } + + if (sentry__string_eq(url.scheme, "https")) { + dsn->is_secure = 1; + } else if (sentry__string_eq(url.scheme, "http")) { + dsn->is_secure = 0; + } else { + goto exit; + } + + dsn->host = url.host; + url.host = NULL; + dsn->public_key = url.username; + url.username = NULL; + dsn->secret_key = url.password; + url.password = NULL; + dsn->port = url.port; + + path_len = strlen(url.path); + while (path_len > 0 && url.path[path_len - 1] == '/') { + url.path[path_len - 1] = '\0'; + path_len--; + } + + project_id = strrchr(url.path, '/'); + if (!project_id || strlen(project_id + 1) == 0) { + goto exit; + } + + dsn->project_id = sentry__string_clone(project_id + 1); + *project_id = 0; + + dsn->path = url.path; + url.path = NULL; + + if (dsn->public_key && dsn->host && dsn->path) { + dsn->is_valid = true; + } + +exit: + sentry__url_cleanup(&url); + return dsn; +} + +sentry_dsn_t * +sentry__dsn_new(const char *raw_dsn) +{ + if (!raw_dsn) { + return NULL; + } + + return sentry__dsn_new_n(raw_dsn, strlen(raw_dsn)); +} sentry_dsn_t * sentry__dsn_incref(sentry_dsn_t *dsn) diff --git a/src/sentry_value.c b/src/sentry_value.c index c86cc7710a..945195574a 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1,11 +1,10 @@ -#include "sentry_boot.h" +#include "sentry.h" #include #include #include #include #include -#include #if defined(_MSC_VER) # pragma warning(push) @@ -743,20 +742,8 @@ sentry_value_get_by_key_n(sentry_value_t value, const char *k, size_t k_len) sentry_value_t sentry_value_get_by_key(sentry_value_t value, const char *k) { - if (!k) { - return sentry_value_new_null(); - } - const thing_t *thing = value_as_thing(value); - if (thing && thing_get_type(thing) == THING_TYPE_OBJECT) { - obj_t *o = thing->payload._ptr; - for (size_t i = 0; i < o->len; i++) { - obj_pair_t *pair = &o->pairs[i]; - if (sentry__string_eq(pair->k, k)) { - return pair->v; - } - } - } - return sentry_value_new_null(); + const size_t k_len = k ? strlen(k) : 0; + return sentry_value_get_by_key_n(value, k, k_len); } sentry_value_t @@ -1141,34 +1128,34 @@ sentry_value_new_event(void) return rv; } -#define CALL_SENTRY_VALUE_NEW_STRING_N(STR) \ - sentry_value_new_string_n(STR, STR##_len) -#define CALL_SENTRY_VALUE_NEW_STRING(STR) sentry_value_new_string(STR) - -#define GEN_SENTRY_VALUE_NEW_MESSAGE_EVENT( \ - FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ - sentry_value_t FN( \ - sentry_level_t level, GEN_STR_PARAM(logger), GEN_STR_PARAM(text)) \ - { \ - sentry_value_t rv = sentry_value_new_event(); \ - sentry_value_set_by_key(rv, "level", sentry__value_new_level(level)); \ - if (logger) { \ - sentry_value_set_by_key(rv, "logger", VALUE_NEW_STR_FN(logger)); \ - } \ - if (text) { \ - sentry_value_t container = sentry_value_new_object(); \ - sentry_value_set_by_key( \ - container, "formatted", VALUE_NEW_STR_FN(text)); \ - sentry_value_set_by_key(rv, "message", container); \ - } \ - return rv; \ +sentry_value_t +sentry_value_new_message_event_n(sentry_level_t level, const char *logger, + size_t logger_len, const char *text, size_t text_len) +{ + sentry_value_t rv = sentry_value_new_event(); + sentry_value_set_by_key(rv, "level", sentry__value_new_level(level)); + if (logger) { + sentry_value_set_by_key( + rv, "logger", sentry_value_new_string_n(logger, logger_len)); } + if (text) { + sentry_value_t container = sentry_value_new_object(); + sentry_value_set_by_key( + container, "formatted", sentry_value_new_string_n(text, text_len)); + sentry_value_set_by_key(rv, "message", container); + } + return rv; +} -GEN_SENTRY_VALUE_NEW_MESSAGE_EVENT(sentry_value_new_message_event_n, - PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING_N) - -GEN_SENTRY_VALUE_NEW_MESSAGE_EVENT(sentry_value_new_message_event, - STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) +sentry_value_t +sentry_value_new_message_event( + sentry_level_t level, const char *logger, const char *text) +{ + size_t logger_len = logger ? strlen(logger) : 0; + size_t text_len = text ? strlen(text) : 0; + return sentry_value_new_message_event_n( + level, logger, logger_len, text, text_len); +} static void timestamp_value(sentry_value_t value) @@ -1178,66 +1165,80 @@ timestamp_value(sentry_value_t value) sentry__msec_time_to_iso8601(sentry__msec_time()))); } -#define GEN_SENTRY_VALUE_NEW_BREADCRUMB(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ - sentry_value_t FN(GEN_STR_PARAM(type), GEN_STR_PARAM(message)) \ - { \ - sentry_value_t rv = sentry_value_new_object(); \ - timestamp_value(rv); \ - \ - if (type) { \ - sentry_value_set_by_key(rv, "type", VALUE_NEW_STR_FN(type)); \ - } \ - if (message) { \ - sentry_value_set_by_key(rv, "message", VALUE_NEW_STR_FN(message)); \ - } \ - return rv; \ - } - -GEN_SENTRY_VALUE_NEW_BREADCRUMB(sentry_value_new_breadcrumb, - STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) -GEN_SENTRY_VALUE_NEW_BREADCRUMB(sentry_value_new_breadcrumb_n, - PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING_N) - -#define GEN_SENTRY_VALUE_NEW_EXCEPTION(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ - sentry_value_t FN(GEN_STR_PARAM(type), GEN_STR_PARAM(value)) \ - { \ - sentry_value_t exc = sentry_value_new_object(); \ - sentry_value_set_by_key(exc, "type", VALUE_NEW_STR_FN(type)); \ - sentry_value_set_by_key(exc, "value", VALUE_NEW_STR_FN(value)); \ - return exc; \ - } - -GEN_SENTRY_VALUE_NEW_EXCEPTION(sentry_value_new_exception, STR_PARAM_FROM_NAME, - CALL_SENTRY_VALUE_NEW_STRING) -GEN_SENTRY_VALUE_NEW_EXCEPTION(sentry_value_new_exception_n, - PTR_LEN_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING_N) - -#define GEN_SENTRY_VALUE_NEW_THREAD(FN, GEN_STR_PARAM, VALUE_NEW_STR_FN) \ - sentry_value_t FN(uint64_t id, GEN_STR_PARAM(name)) \ - { \ - sentry_value_t thread = sentry_value_new_object(); \ - \ - /* NOTE: values end up as JSON, which has no support for `u64`. */ \ - char buf[20 + 1]; \ - size_t written = (size_t)snprintf( \ - buf, sizeof(buf), "%llu", (unsigned long long)id); \ - if (written < sizeof(buf)) { \ - buf[written] = '\0'; \ - sentry_value_set_by_key( \ - thread, "id", sentry_value_new_string(buf)); \ - } \ - \ - if (name) { \ - sentry_value_set_by_key(thread, "name", VALUE_NEW_STR_FN(name)); \ - } \ - \ - return thread; \ - } - -GEN_SENTRY_VALUE_NEW_THREAD( - sentry_value_new_thread, STR_PARAM_FROM_NAME, CALL_SENTRY_VALUE_NEW_STRING) -GEN_SENTRY_VALUE_NEW_THREAD(sentry_value_new_thread_n, PTR_LEN_PARAM_FROM_NAME, - CALL_SENTRY_VALUE_NEW_STRING_N) +sentry_value_t +sentry_value_new_breadcrumb_n( + const char *type, size_t type_len, const char *message, size_t message_len) +{ + sentry_value_t rv = sentry_value_new_object(); + timestamp_value(rv); + + if (type) { + sentry_value_set_by_key( + rv, "type", sentry_value_new_string_n(type, type_len)); + } + if (message) { + sentry_value_set_by_key( + rv, "message", sentry_value_new_string_n(message, message_len)); + } + return rv; +} + +sentry_value_t +sentry_value_new_breadcrumb(const char *type, const char *message) +{ + const size_t type_len = type ? strlen(type) : 0; + const size_t message_len = message ? strlen(message) : 0; + return sentry_value_new_breadcrumb_n(type, type_len, message, message_len); +} + +sentry_value_t +sentry_value_new_exception_n( + const char *type, size_t type_len, const char *value, size_t value_len) +{ + sentry_value_t exc = sentry_value_new_object(); + sentry_value_set_by_key( + exc, "type", sentry_value_new_string_n(type, type_len)); + sentry_value_set_by_key( + exc, "value", sentry_value_new_string_n(value, value_len)); + return exc; +} + +sentry_value_t +sentry_value_new_exception(const char *type, const char *value) +{ + const size_t type_len = type ? strlen(type) : 0; + const size_t value_len = value ? strlen(value) : 0; + return sentry_value_new_exception_n(type, type_len, value, value_len); +} + +sentry_value_t +sentry_value_new_thread_n(uint64_t id, const char *name, size_t name_len) +{ + sentry_value_t thread = sentry_value_new_object(); + + /* NOTE: values end up as JSON, which has no support for `u64`. */ + char buf[20 + 1]; + size_t written + = (size_t)snprintf(buf, sizeof(buf), "%llu", (unsigned long long)id); + if (written < sizeof(buf)) { + buf[written] = '\0'; + sentry_value_set_by_key(thread, "id", sentry_value_new_string(buf)); + } + + if (name) { + sentry_value_set_by_key( + thread, "name", sentry_value_new_string_n(name, name_len)); + } + + return thread; +} + +sentry_value_t +sentry_value_new_thread(uint64_t id, const char *name) +{ + const size_t name_len = name ? strlen(name) : 0; + return sentry_value_new_thread_n(id, name, name_len); +} sentry_value_t sentry_value_new_stacktrace(void **ips, size_t len) diff --git a/tests/unit/test_envelopes.c b/tests/unit/test_envelopes.c index 2e6128a9cb..5c8bf04501 100644 --- a/tests/unit/test_envelopes.c +++ b/tests/unit/test_envelopes.c @@ -1,9 +1,22 @@ +#include "sentry.h" #include "sentry_envelope.h" +#include "sentry_path.h" #include "sentry_testsupport.h" #include "sentry_transport.h" #include "sentry_utils.h" #include "sentry_value.h" +static char *const SERIALIZED_ENVELOPE_STR + = "{\"dsn\":\"https://foo@sentry.invalid/42\"," + "\"event_id\":\"c993afb6-b4ac-48a6-b61b-2558e601d65d\"}\n" + "{\"type\":\"event\",\"length\":71}\n" + "{\"event_id\":\"c993afb6-b4ac-48a6-b61b-2558e601d65d\",\"some-" + "context\":null}\n" + "{\"type\":\"minidump\",\"length\":4}\n" + "MDMP\n" + "{\"type\":\"attachment\",\"length\":12}\n" + "Hello World!"; + SENTRY_TEST(basic_http_request_preparation_for_event) { sentry_dsn_t *dsn = sentry__dsn_new("https://foo@sentry.invalid/42"); @@ -124,7 +137,8 @@ SENTRY_TEST(basic_http_request_preparation_for_minidump) sentry__dsn_decref(dsn); } -SENTRY_TEST(serialize_envelope) +sentry_envelope_t * +create_test_envelope() { sentry_options_t *options = sentry_options_new(); sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); @@ -145,25 +159,59 @@ SENTRY_TEST(serialize_envelope) char msg[] = "Hello World!"; sentry__envelope_add_from_buffer( envelope, msg, sizeof(msg) - 1, "attachment"); + return envelope; +} + +SENTRY_TEST(serialize_envelope) +{ + sentry_envelope_t *envelope = create_test_envelope(); sentry_stringbuilder_t sb; sentry__stringbuilder_init(&sb); sentry__envelope_serialize_into_stringbuilder(envelope, &sb); char *str = sentry__stringbuilder_into_string(&sb); - TEST_CHECK_STRING_EQUAL(str, - "{\"dsn\":\"https://foo@sentry.invalid/42\"," - "\"event_id\":\"c993afb6-b4ac-48a6-b61b-2558e601d65d\"}\n" - "{\"type\":\"event\",\"length\":71}\n" - "{\"event_id\":\"c993afb6-b4ac-48a6-b61b-2558e601d65d\",\"some-" - "context\":null}\n" - "{\"type\":\"minidump\",\"length\":4}\n" - "MDMP\n" - "{\"type\":\"attachment\",\"length\":12}\n" - "Hello World!"); + TEST_CHECK_STRING_EQUAL(str, SERIALIZED_ENVELOPE_STR); sentry_envelope_free(envelope); sentry_free(str); sentry_close(); } + +SENTRY_TEST(basic_write_envelope_to_file) +{ + sentry_envelope_t *envelope = create_test_envelope(); + const char *test_file_str = "sentry_test_envelope"; + const sentry_path_t *test_file_path = sentry__path_from_str(test_file_str); + int rv = sentry_envelope_write_to_file(envelope, test_file_str); + TEST_CHECK_INT_EQUAL(rv, 0); + TEST_CHECK(sentry__path_is_file(test_file_path)); + + size_t test_file_size; + char *test_file_content + = sentry__path_read_to_buffer(test_file_path, &test_file_size); + TEST_CHECK_INT_EQUAL(test_file_size, strlen(SERIALIZED_ENVELOPE_STR)); + TEST_CHECK_STRING_EQUAL(test_file_content, SERIALIZED_ENVELOPE_STR); + + sentry_free(test_file_content); + sentry__path_remove(test_file_path); + sentry_envelope_free(envelope); + sentry_close(); +} + +SENTRY_TEST(write_envelope_to_file_null) +{ + sentry_envelope_t *empty_envelope = sentry__envelope_new(); + + TEST_CHECK_INT_EQUAL( + sentry_envelope_write_to_file(NULL, "irrelevant/path"), 1); + TEST_CHECK_INT_EQUAL( + sentry_envelope_write_to_file(empty_envelope, NULL), 1); + TEST_CHECK_INT_EQUAL( + sentry_envelope_write_to_file_n(NULL, "irrelevant/path", 0), 1); + TEST_CHECK_INT_EQUAL( + sentry_envelope_write_to_file_n(empty_envelope, NULL, 0), 1); + + sentry_envelope_free(empty_envelope); +} diff --git a/tests/unit/test_path.c b/tests/unit/test_path.c index 3f25d77a52..1ae6f46bd5 100644 --- a/tests/unit/test_path.c +++ b/tests/unit/test_path.c @@ -58,6 +58,13 @@ SENTRY_TEST(path_joining_unix) #endif } +SENTRY_TEST(path_from_str_null) +{ + TEST_CHECK(NULL == sentry__path_from_str(NULL)); + TEST_CHECK(NULL == sentry__path_from_str_n(NULL, 0)); + TEST_CHECK(NULL == sentry__path_from_str_n(NULL, 10)); +} + SENTRY_TEST(path_joining_windows) { #ifndef SENTRY_PLATFORM_WINDOWS diff --git a/tests/unit/test_tracing.c b/tests/unit/test_tracing.c index d684796860..7f39626a67 100644 --- a/tests/unit/test_tracing.c +++ b/tests/unit/test_tracing.c @@ -1,3 +1,4 @@ +#include "sentry.h" #include "sentry_testsupport.h" #include "sentry_scope.h" @@ -711,6 +712,42 @@ forward_headers_to(const char *key, const char *value, void *userdata) sentry_transaction_context_update_from_header(tx_ctx, key, value); } +SENTRY_TEST(update_from_header_null_ctx) +{ + sentry_transaction_context_update_from_header( + NULL, "irrelevant-key", "irrelevant-value"); +} + +SENTRY_TEST(update_from_header_no_sampled_flag) +{ + sentry_options_t *options = sentry_options_new(); + sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + + sentry_options_set_traces_sample_rate(options, 1.0); + sentry_options_set_max_spans(options, 2); + sentry_init(options); + + sentry_transaction_context_update_from_header( + NULL, "irrelevant-key", "irrelevant-value"); + const char *trace_header + = "2674eb52d5874b13b560236d6c79ce8a-a0f9fdf04f1a63df"; + sentry_transaction_context_t *tx_ctx + = sentry_transaction_context_new("wow!", NULL); + sentry_transaction_context_update_from_header( + tx_ctx, "sentry-trace", trace_header); + sentry_transaction_t *tx + = sentry_transaction_start(tx_ctx, sentry_value_new_null()); + + CHECK_STRING_PROPERTY( + tx->inner, "trace_id", "2674eb52d5874b13b560236d6c79ce8a"); + CHECK_STRING_PROPERTY(tx->inner, "parent_span_id", "a0f9fdf04f1a63df"); + sentry_value_t sampled = sentry_value_get_by_key(tx->inner, "sampled"); + TEST_CHECK(sentry_value_get_type(sampled) == SENTRY_VALUE_TYPE_BOOL); + TEST_CHECK(sentry_value_is_true(sampled)); + + sentry_close(); +} + SENTRY_TEST(distributed_headers) { sentry_options_t *options = sentry_options_new(); @@ -729,9 +766,14 @@ SENTRY_TEST(distributed_headers) sentry_transaction_context_t *tx_ctx = sentry_transaction_context_new("wow!", NULL); - // check case insensitive headers, and bogus header names + // check case-insensitive headers, and bogus header names sentry_transaction_context_update_from_header( tx_ctx, "SeNtry-TrAcE", trace_header); + sentry_transaction_context_update_from_header( + tx_ctx, "sentry_trace", not_expected_header); + sentry_transaction_context_update_from_header( + tx_ctx, NULL, not_expected_header); + sentry_transaction_context_update_from_header(tx_ctx, "sentry-trace", NULL); sentry_transaction_context_update_from_header( tx_ctx, "nop", not_expected_header); sentry_transaction_context_update_from_header( @@ -830,8 +872,7 @@ check_after_set(sentry_value_t inner, const char *inner_key, TEST_CHECK( sentry_value_get_type(sentry_value_get_by_key(inner_tags, item_key)) == SENTRY_VALUE_TYPE_STRING); - TEST_CHECK_STRING_EQUAL(expected, - sentry_value_as_string(sentry_value_get_by_key(inner_tags, item_key))); + CHECK_STRING_PROPERTY(inner_tags, item_key, expected); } void @@ -840,8 +881,7 @@ check_after_remove( { sentry_value_t inner_tags = sentry_value_get_by_key(inner, inner_key); TEST_CHECK_INT_EQUAL(0, sentry_value_get_length(inner_tags)); - TEST_CHECK( - sentry_value_is_null(sentry_value_get_by_key(inner_tags, item_key))); + TEST_CHECK(IS_NULL(inner_tags, item_key)); } SENTRY_TEST(txn_tagging) @@ -1010,5 +1050,57 @@ SENTRY_TEST(span_data_n) sentry__transaction_decref(txn); } +SENTRY_TEST(sentry__value_span_new_requires_unfinished_parent) +{ + sentry_value_t parent = sentry_value_new_object(); + // timestamps are typically iso8601 strings, but this is irrelevant to + // `sentry__value_span_new` which just wants `timestamp` to not be null. + sentry_value_set_by_key(parent, "timestamp", sentry_value_new_object()); + sentry_value_t inner_span = sentry__value_span_new(0, parent, NULL, NULL); + TEST_CHECK(sentry_value_is_null(inner_span)); + + sentry_value_decref(parent); +} + +SENTRY_TEST(set_tag_allows_null_tag_and_value) +{ + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + sentry_transaction_set_tag(txn, NULL, NULL); + sentry_value_t tags = sentry_value_get_by_key(txn->inner, "tags"); + TEST_CHECK(!sentry_value_is_null(tags)); + TEST_CHECK(sentry_value_get_type(tags) == SENTRY_VALUE_TYPE_OBJECT); + TEST_CHECK(sentry_value_get_length(tags) == 0); + + sentry_transaction_set_tag(txn, "os.name", NULL); + tags = sentry_value_get_by_key(txn->inner, "tags"); + TEST_CHECK(!sentry_value_is_null(tags)); + TEST_CHECK(sentry_value_get_type(tags) == SENTRY_VALUE_TYPE_OBJECT); + TEST_CHECK(sentry_value_get_length(tags) == 1); + TEST_CHECK(IS_NULL(tags, "os.name")); + + sentry__transaction_decref(txn); +} + +SENTRY_TEST(set_tag_cuts_value_at_length_200) +{ + const char test_value[] + = "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789"; + + sentry_transaction_t *txn + = sentry__transaction_new(sentry_value_new_object()); + sentry_transaction_set_tag(txn, "cut-off", test_value); + sentry_value_t tags = sentry_value_get_by_key(txn->inner, "tags"); + TEST_CHECK(!sentry_value_is_null(tags)); + TEST_CHECK(sentry_value_get_type(tags) == SENTRY_VALUE_TYPE_OBJECT); + TEST_CHECK(sentry_value_get_length(tags) == 1); + TEST_CHECK_INT_EQUAL(strlen(sentry_value_as_string( + sentry_value_get_by_key(tags, "cut-off"))), + 200); +} + #undef IS_NULL #undef CHECK_STRING_PROPERTY diff --git a/tests/unit/test_utils.c b/tests/unit/test_utils.c index 855f59d3d7..57f1ffb4ce 100644 --- a/tests/unit/test_utils.c +++ b/tests/unit/test_utils.c @@ -249,4 +249,36 @@ SENTRY_TEST(check_version) TEST_CHECK(!sentry__check_min_version( (sentry_version_t) { .major = 7, .minor = 10, .patch = 6 }, (sentry_version_t) { .major = 7, .minor = 10, .patch = 7 })); -} \ No newline at end of file +} + +SENTRY_TEST(dsn_without_url_scheme_is_invalid) +{ + sentry_dsn_t *dsn = sentry__dsn_new("//without-scheme-separator"); + TEST_CHECK(dsn->is_valid == false); + sentry__dsn_decref(dsn); +} + +SENTRY_TEST(dsn_with_non_http_scheme_is_invalid) +{ + sentry_dsn_t *dsn = sentry__dsn_new("ftp://ftp-server/"); + TEST_CHECK(dsn->is_valid == false); + sentry__dsn_decref(dsn); +} + +SENTRY_TEST(dsn_without_project_id_is_invalid) +{ + sentry_dsn_t *dsn = sentry__dsn_new("https://foo@sentry.io/"); + TEST_CHECK(dsn->is_valid == false); + sentry__dsn_decref(dsn); +} + +SENTRY_TEST(dsn_with_ending_forward_slash_will_be_cleaned) +{ + sentry_dsn_t *dsn = sentry__dsn_new("https://foo@sentry.io/42/43/44////"); + + TEST_CHECK_STRING_EQUAL(dsn->path, "/42/43"); + TEST_CHECK_STRING_EQUAL(dsn->project_id, "44"); + TEST_CHECK(dsn->is_valid == true); + + sentry__dsn_decref(dsn); +} diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index 76cf60028a..a13dbc2944 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -1,3 +1,4 @@ +#include "sentry.h" #include "sentry_json.h" #include "sentry_testsupport.h" #include "sentry_value.h" @@ -662,3 +663,111 @@ SENTRY_TEST(value_set_stacktrace) sentry_value_decref(exc); } + +SENTRY_TEST(message_without_text_still_valid) +{ + sentry_value_t message_event = sentry_value_new_message_event( + SENTRY_LEVEL_WARNING, "some-logger", NULL); + + TEST_CHECK(!sentry_value_is_null(message_event)); + TEST_CHECK_STRING_EQUAL(sentry_value_as_string(sentry_value_get_by_key( + message_event, "logger")), + "some-logger"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(message_event, "level")), + "warning"); +} + +SENTRY_TEST(breadcrumb_without_type_or_message_still_valid) +{ + sentry_value_t breadcrumb = sentry_value_new_breadcrumb(NULL, NULL); + TEST_CHECK(!sentry_value_is_null(breadcrumb)); + TEST_CHECK(!sentry_value_is_null( + sentry_value_get_by_key(breadcrumb, "timestamp"))); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(breadcrumb, "type"))); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(breadcrumb, "message"))); + sentry_value_decref(breadcrumb); + + char *const test_type = "navigation"; + breadcrumb = sentry_value_new_breadcrumb(test_type, NULL); + TEST_CHECK(!sentry_value_is_null(breadcrumb)); + TEST_CHECK(!sentry_value_is_null( + sentry_value_get_by_key(breadcrumb, "timestamp"))); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(breadcrumb, "type")), + test_type); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(breadcrumb, "message"))); + sentry_value_decref(breadcrumb); + + char *const test_message = "a fork in the road, take it"; + breadcrumb = sentry_value_new_breadcrumb(NULL, test_message); + TEST_CHECK(!sentry_value_is_null(breadcrumb)); + TEST_CHECK(!sentry_value_is_null( + sentry_value_get_by_key(breadcrumb, "timestamp"))); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(breadcrumb, "type"))); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(breadcrumb, "message")), + test_message); + sentry_value_decref(breadcrumb); +} + +SENTRY_TEST(exception_without_type_or_value_still_valid) +{ + sentry_value_t exception = sentry_value_new_exception(NULL, NULL); + TEST_CHECK(!sentry_value_is_null(exception)); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(exception, "type"))); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(exception, "value"))); + sentry_value_decref(exception); + + char *const test_type = "EXC_BAD_ACCESS / KERN_INVALID_ADDRESS / 0x61"; + exception = sentry_value_new_exception(test_type, NULL); + TEST_CHECK(!sentry_value_is_null(exception)); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(exception, "type")), + test_type); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(exception, "value"))); + sentry_value_decref(exception); + + char *const test_value + = "Fatal Error: EXC_BAD_ACCESS / KERN_INVALID_ADDRESS / 0x61"; + exception = sentry_value_new_exception(NULL, test_value); + TEST_CHECK(!sentry_value_is_null(exception)); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(exception, "type"))); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(exception, "value")), + test_value); + sentry_value_decref(exception); +} + +SENTRY_TEST(thread_without_name_still_valid) +{ + sentry_value_t thread = sentry_value_new_thread(0xFF00FF00FF00FF00, NULL); + TEST_CHECK(!sentry_value_is_null(thread)); + TEST_CHECK(!sentry_value_is_null(sentry_value_get_by_key(thread, "id"))); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(thread, "id")), + "18374966859414961920"); + TEST_CHECK(sentry_value_is_null(sentry_value_get_by_key(thread, "name"))); + sentry_value_decref(thread); + + char *const test_name = "worker"; + thread = sentry_value_new_thread(0xAA00AA00AA00AA00, test_name); + TEST_CHECK(!sentry_value_is_null(thread)); + TEST_CHECK(!sentry_value_is_null(sentry_value_get_by_key(thread, "id"))); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(thread, "id")), + "12249977906276641280"); + TEST_CHECK(!sentry_value_is_null(sentry_value_get_by_key(thread, "name"))); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(thread, "name")), + test_name); + sentry_value_decref(thread); +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 4120d4b587..d6ebeb86bb 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -12,7 +12,9 @@ XX(basic_http_request_preparation_for_transaction) XX(basic_spans) XX(basic_tracing_context) XX(basic_transaction) +XX(basic_write_envelope_to_file) XX(bgworker_flush) +XX(breadcrumb_without_type_or_message_still_valid) XX(build_id_parser) XX(check_version) XX(child_spans) @@ -29,7 +31,12 @@ XX(dsn_parsing_complete) XX(dsn_parsing_invalid) XX(dsn_store_url_with_path) XX(dsn_store_url_without_path) +XX(dsn_with_ending_forward_slash_will_be_cleaned) +XX(dsn_with_non_http_scheme_is_invalid) +XX(dsn_without_project_id_is_invalid) +XX(dsn_without_url_scheme_is_invalid) XX(empty_transport) +XX(exception_without_type_or_value_still_valid) XX(fuzz_json) XX(init_failure) XX(internal_uuid_api) @@ -37,6 +44,7 @@ XX(invalid_dsn) XX(invalid_proxy) XX(iso_time) XX(lazy_attachments) +XX(message_without_text_still_valid) XX(module_addr) XX(module_finder) XX(mpack_newlines) @@ -49,6 +57,7 @@ XX(page_allocator) XX(path_basics) XX(path_current_exe) XX(path_directory) +XX(path_from_str_null) XX(path_joining_unix) XX(path_joining_windows) XX(path_relative_filename) @@ -58,8 +67,11 @@ XX(recursive_paths) XX(sampling_before_send) XX(sampling_decision) XX(sampling_transaction) +XX(sentry__value_span_new_requires_unfinished_parent) XX(serialize_envelope) XX(session_basics) +XX(set_tag_allows_null_tag_and_value) +XX(set_tag_cuts_value_at_length_200) XX(slice) XX(span_data) XX(span_data_n) @@ -68,6 +80,7 @@ XX(span_tagging_n) XX(spans_on_scope) XX(symbolizer) XX(task_queue) +XX(thread_without_name_still_valid) XX(transaction_name_backfill_on_finish) XX(transactions_skip_before_send) XX(transport_sampling_transactions) @@ -80,6 +93,8 @@ XX(txn_tagging_n) XX(uninitialized) XX(unsampled_spans) XX(unwinder) +XX(update_from_header_no_sampled_flag) +XX(update_from_header_null_ctx) XX(url_parsing_complete) XX(url_parsing_invalid) XX(url_parsing_partial) @@ -109,3 +124,4 @@ XX(value_string) XX(value_string_n) XX(value_unicode) XX(value_wrong_type) +XX(write_envelope_to_file_null) From df5d3299824be1eb27a02ac1733ad4a92845563d Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 18 Apr 2023 21:05:52 +0200 Subject: [PATCH 16/36] reintroduce locale header to sentry_utils.c --- src/sentry_utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sentry_utils.c b/src/sentry_utils.c index f3aacb04e3..0375275f50 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -7,6 +7,7 @@ #include "sentry_string.h" #include "sentry_sync.h" #include "sentry_utils.h" +#include #include #include #include From 0831089023b6f518d6976ef8e6e69163dfcbe1b0 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 18 Apr 2023 21:25:30 +0200 Subject: [PATCH 17/36] clean up txns in unit-tests --- tests/unit/test_envelopes.c | 3 ++- tests/unit/test_tracing.c | 3 +++ tests/unit/test_value.c | 4 +++- tests/unit/tests.inc | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_envelopes.c b/tests/unit/test_envelopes.c index 5c8bf04501..5bba048d8a 100644 --- a/tests/unit/test_envelopes.c +++ b/tests/unit/test_envelopes.c @@ -183,7 +183,7 @@ SENTRY_TEST(basic_write_envelope_to_file) { sentry_envelope_t *envelope = create_test_envelope(); const char *test_file_str = "sentry_test_envelope"; - const sentry_path_t *test_file_path = sentry__path_from_str(test_file_str); + sentry_path_t *test_file_path = sentry__path_from_str(test_file_str); int rv = sentry_envelope_write_to_file(envelope, test_file_str); TEST_CHECK_INT_EQUAL(rv, 0); TEST_CHECK(sentry__path_is_file(test_file_path)); @@ -196,6 +196,7 @@ SENTRY_TEST(basic_write_envelope_to_file) sentry_free(test_file_content); sentry__path_remove(test_file_path); + sentry__path_free(test_file_path); sentry_envelope_free(envelope); sentry_close(); } diff --git a/tests/unit/test_tracing.c b/tests/unit/test_tracing.c index 7f39626a67..d2d639f6f7 100644 --- a/tests/unit/test_tracing.c +++ b/tests/unit/test_tracing.c @@ -745,6 +745,7 @@ SENTRY_TEST(update_from_header_no_sampled_flag) TEST_CHECK(sentry_value_get_type(sampled) == SENTRY_VALUE_TYPE_BOOL); TEST_CHECK(sentry_value_is_true(sampled)); + sentry__transaction_decref(tx); sentry_close(); } @@ -1100,6 +1101,8 @@ SENTRY_TEST(set_tag_cuts_value_at_length_200) TEST_CHECK_INT_EQUAL(strlen(sentry_value_as_string( sentry_value_get_by_key(tags, "cut-off"))), 200); + + sentry__transaction_decref(txn); } #undef IS_NULL diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index a13dbc2944..3bbf4305b7 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -664,7 +664,7 @@ SENTRY_TEST(value_set_stacktrace) sentry_value_decref(exc); } -SENTRY_TEST(message_without_text_still_valid) +SENTRY_TEST(message_with_null_text_is_valid) { sentry_value_t message_event = sentry_value_new_message_event( SENTRY_LEVEL_WARNING, "some-logger", NULL); @@ -676,6 +676,8 @@ SENTRY_TEST(message_without_text_still_valid) TEST_CHECK_STRING_EQUAL( sentry_value_as_string(sentry_value_get_by_key(message_event, "level")), "warning"); + + sentry_value_decref(message_event); } SENTRY_TEST(breadcrumb_without_type_or_message_still_valid) diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index d6ebeb86bb..70f6c6f31a 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -44,7 +44,7 @@ XX(invalid_dsn) XX(invalid_proxy) XX(iso_time) XX(lazy_attachments) -XX(message_without_text_still_valid) +XX(message_with_null_text_is_valid) XX(module_addr) XX(module_finder) XX(mpack_newlines) From c0b5e7fd50263023c8761d5246b66d4ed79bddd6 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 18 Apr 2023 22:49:37 +0200 Subject: [PATCH 18/36] Cleanup curl after curl_easy_perform --- src/transports/sentry_transport_curl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transports/sentry_transport_curl.c b/src/transports/sentry_transport_curl.c index cb30d432cf..4009e74ff0 100644 --- a/src/transports/sentry_transport_curl.c +++ b/src/transports/sentry_transport_curl.c @@ -247,6 +247,7 @@ sentry__curl_send_task(void *_envelope, void *_state) } } + curl_easy_cleanup(curl); curl_slist_free_all(headers); sentry_free(info.retry_after); sentry_free(info.x_sentry_rate_limits); From 251ba77d12504d975b7206be367934674f11502d Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 18 Apr 2023 22:59:56 +0200 Subject: [PATCH 19/36] Use easy_reset instead of easy_cleanup to check macos clang leak --- src/transports/sentry_transport_curl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transports/sentry_transport_curl.c b/src/transports/sentry_transport_curl.c index 4009e74ff0..f4c8654d31 100644 --- a/src/transports/sentry_transport_curl.c +++ b/src/transports/sentry_transport_curl.c @@ -247,7 +247,7 @@ sentry__curl_send_task(void *_envelope, void *_state) } } - curl_easy_cleanup(curl); + curl_easy_reset(curl); curl_slist_free_all(headers); sentry_free(info.retry_after); sentry_free(info.x_sentry_rate_limits); From f2292f61556e78e0325ae9e09fddf26f2c16991f Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 19 Apr 2023 11:19:23 +0200 Subject: [PATCH 20/36] Further guards & fixes thx to unit-tests --- src/path/sentry_path_windows.c | 8 +++++++- tests/unit/test_envelopes.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/path/sentry_path_windows.c b/src/path/sentry_path_windows.c index 4a2c42ccd8..9605eb129f 100644 --- a/src/path/sentry_path_windows.c +++ b/src/path/sentry_path_windows.c @@ -191,6 +191,9 @@ sentry__path_join_wstr(const sentry_path_t *base, const wchar_t *other) sentry_path_t * sentry__path_from_str(const char *s) { + if (!s) { + return NULL; + } size_t len = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0); sentry_path_t *rv = SENTRY_MAKE(sentry_path_t); if (!rv) { @@ -208,6 +211,9 @@ sentry__path_from_str(const char *s) sentry_path_t * sentry__path_from_str_n(const char *s, size_t s_len) { + if (!s) { + return NULL; + } sentry_path_t *rv = SENTRY_MAKE(sentry_path_t); if (!rv) { return NULL; @@ -217,7 +223,7 @@ sentry__path_from_str_n(const char *s, size_t s_len) sentry_free(rv); return NULL; } - MultiByteToWideChar(CP_ACP, 0, s, -1, rv->path, (int)s_len); + MultiByteToWideChar(CP_ACP, 0, s, -1, rv->path, (int)s_len+1); return rv; } diff --git a/tests/unit/test_envelopes.c b/tests/unit/test_envelopes.c index 5bba048d8a..5a8f92e150 100644 --- a/tests/unit/test_envelopes.c +++ b/tests/unit/test_envelopes.c @@ -186,7 +186,7 @@ SENTRY_TEST(basic_write_envelope_to_file) sentry_path_t *test_file_path = sentry__path_from_str(test_file_str); int rv = sentry_envelope_write_to_file(envelope, test_file_str); TEST_CHECK_INT_EQUAL(rv, 0); - TEST_CHECK(sentry__path_is_file(test_file_path)); + TEST_ASSERT(sentry__path_is_file(test_file_path)); size_t test_file_size; char *test_file_content From c36527534bf2888965899a4068b04cc9db13f697 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 19 Apr 2023 11:31:00 +0200 Subject: [PATCH 21/36] Implement sentry_span_start_child_n --- src/sentry_core.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 110f0737d0..f4ee9065c5 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -967,8 +967,8 @@ sentry_transaction_start_child(sentry_transaction_t *opaque_parent, } sentry_span_t * -sentry_span_start_child(sentry_span_t *opaque_parent, const char *operation, - const char *description) +sentry_span_start_child_n(sentry_span_t *opaque_parent, const char *operation, + size_t operation_len, const char *description, size_t description_len) { if (!opaque_parent || sentry_value_is_null(opaque_parent->inner)) { SENTRY_DEBUG("no parent span available to create a child span under"); @@ -987,12 +987,23 @@ sentry_span_start_child(sentry_span_t *opaque_parent, const char *operation, max_spans = options->max_spans; } - sentry_value_t span - = sentry__value_span_new(max_spans, parent, operation, description); + sentry_value_t span = sentry__value_span_new_n(max_spans, parent, + (sentry_slice_t) { operation, operation_len }, + (sentry_slice_t) { description, description_len }); return sentry__span_new(opaque_parent->transaction, span); } +sentry_span_t * +sentry_span_start_child(sentry_span_t *opaque_parent, const char *operation, + const char *description) +{ + size_t operation_len = operation ? strlen(operation) : 0; + size_t description_len = description ? strlen(description) : 0; + return sentry_span_start_child_n( + opaque_parent, operation, operation_len, description, description_len); +} + void sentry_span_finish(sentry_span_t *opaque_span) { From e3d4508dd72f45f601b9076f5db0069b89d356e6 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 19 Apr 2023 11:47:37 +0200 Subject: [PATCH 22/36] use sentry_boot.h in sentry_value.c --- src/sentry_value.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry_value.c b/src/sentry_value.c index 945195574a..abc20c300d 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1,4 +1,4 @@ -#include "sentry.h" +#include "sentry_boot.h" #include #include From 32db9d5223d63b6aa9a1b83e8ec620ea3dc32e61 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 19 Apr 2023 11:51:28 +0200 Subject: [PATCH 23/36] Implement sentry_set_fingerprint_n --- src/sentry_core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sentry_core.c b/src/sentry_core.c index f4ee9065c5..e38e109d7c 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -728,6 +728,25 @@ sentry_remove_context_n(const char *key, size_t key_len) } } +void +sentry_set_fingerprint_n(const char *fingerprint, size_t fingerprint_len, ...) +{ + sentry_value_t fingerprint_value = sentry_value_new_list(); + + va_list va; + va_start(va, fingerprint_len); + for (; fingerprint; fingerprint = va_arg(va, const char *)) { + sentry_value_append(fingerprint_value, + sentry_value_new_string_n(fingerprint, fingerprint_len)); + } + va_end(va); + + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_value_decref(scope->fingerprint); + scope->fingerprint = fingerprint_value; + } +} + void sentry_set_fingerprint(const char *fingerprint, ...) { From 65963e140e7cdf921f43967df45b3f1f61b97f8e Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 19 Apr 2023 11:53:03 +0200 Subject: [PATCH 24/36] reformat to silence lint. --- src/path/sentry_path_windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/path/sentry_path_windows.c b/src/path/sentry_path_windows.c index 9605eb129f..0aaa78b133 100644 --- a/src/path/sentry_path_windows.c +++ b/src/path/sentry_path_windows.c @@ -223,7 +223,7 @@ sentry__path_from_str_n(const char *s, size_t s_len) sentry_free(rv); return NULL; } - MultiByteToWideChar(CP_ACP, 0, s, -1, rv->path, (int)s_len+1); + MultiByteToWideChar(CP_ACP, 0, s, -1, rv->path, (int)s_len + 1); return rv; } From 06184538c8d22e67729eee54a1ac510a7d7cf256 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 19 Apr 2023 12:11:33 +0200 Subject: [PATCH 25/36] get rid of sentry.h refs in unit-tests --- tests/unit/test_envelopes.c | 1 - tests/unit/test_tracing.c | 1 - tests/unit/test_value.c | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unit/test_envelopes.c b/tests/unit/test_envelopes.c index 5a8f92e150..e0032706cd 100644 --- a/tests/unit/test_envelopes.c +++ b/tests/unit/test_envelopes.c @@ -1,4 +1,3 @@ -#include "sentry.h" #include "sentry_envelope.h" #include "sentry_path.h" #include "sentry_testsupport.h" diff --git a/tests/unit/test_tracing.c b/tests/unit/test_tracing.c index d2d639f6f7..bdac0921fd 100644 --- a/tests/unit/test_tracing.c +++ b/tests/unit/test_tracing.c @@ -1,4 +1,3 @@ -#include "sentry.h" #include "sentry_testsupport.h" #include "sentry_scope.h" diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index 3bbf4305b7..92e195d580 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -1,4 +1,3 @@ -#include "sentry.h" #include "sentry_json.h" #include "sentry_testsupport.h" #include "sentry_value.h" @@ -177,7 +176,7 @@ SENTRY_TEST(value_list) sentry_value_decref(val); val = sentry_value_new_list(); - for (uint32_t i = 1; i <= 10; i++) { + for (int32_t i = 1; i <= 10; i++) { sentry_value_append(val, sentry_value_new_int32(i)); } sentry__value_append_bounded(val, sentry_value_new_int32(1010), 5); From 2b3a5f6713fbdc8e7528425aab30db0613d59992 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Wed, 19 Apr 2023 12:52:27 +0200 Subject: [PATCH 26/36] Implement remaining wchar_t options interfaces for windows. --- src/path/sentry_path_windows.c | 20 ++++++++++++++++---- src/sentry_options.c | 34 +++++++++++++++++++++++++++++----- src/sentry_path.h | 1 + 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/path/sentry_path_windows.c b/src/path/sentry_path_windows.c index 0aaa78b133..11bcb7ec31 100644 --- a/src/path/sentry_path_windows.c +++ b/src/path/sentry_path_windows.c @@ -135,16 +135,28 @@ sentry__path_dir(const sentry_path_t *path) } sentry_path_t * -sentry__path_from_wstr(const wchar_t *s) +sentry__path_from_wstr_n(const wchar_t *s, size_t s_len) { - size_t len = wcslen(s) + 1; - sentry_path_t *rv = path_with_len(len); + if (!s) { + return NULL; + } + sentry_path_t *rv = path_with_len(s_len + 1); if (rv) { - memcpy(rv->path, s, len * sizeof(wchar_t)); + memcpy(rv->path, s, s_len * sizeof(wchar_t)); + rv->path[s_len] = 0; } return rv; } +sentry_path_t * +sentry__path_from_wstr(const wchar_t *s) +{ + if (!s) { + return NULL; + } + return sentry__path_from_wstr_n(s, wcslen(s)); +} + sentry_path_t * sentry__path_join_wstr(const sentry_path_t *base, const wchar_t *other) { diff --git a/src/sentry_options.c b/src/sentry_options.c index fa32bf3c41..398aecc0ce 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -445,24 +445,48 @@ sentry_options_set_database_path_n( } #ifdef SENTRY_PLATFORM_WINDOWS +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)); +} + void sentry_options_add_attachmentw(sentry_options_t *opts, const wchar_t *path) { - add_attachment(opts, sentry__path_from_wstr(path)); + size_t path_len = path ? wcslen(path) : 0; + sentry_options_add_attachmentw_n(opts, path, path_len); } void -sentry_options_set_handler_pathw(sentry_options_t *opts, const wchar_t *path) +sentry_options_set_handler_pathw_n( + sentry_options_t *opts, const wchar_t *path, size_t path_len) { sentry__path_free(opts->handler_path); - opts->handler_path = sentry__path_from_wstr(path); + opts->handler_path = sentry__path_from_wstr_n(path, path_len); } void -sentry_options_set_database_pathw(sentry_options_t *opts, const wchar_t *path) +sentry_options_set_handler_pathw(sentry_options_t *opts, const wchar_t *path) +{ + size_t path_len = path ? wcslen(path) : 0; + sentry_options_set_handler_pathw_n(opts, path, path_len); +} + +void +sentry_options_set_database_pathw_n( + sentry_options_t *opts, const wchar_t *path, size_t path_len) { sentry__path_free(opts->database_path); - opts->database_path = sentry__path_from_wstr(path); + opts->database_path = sentry__path_from_wstr_n(path, path_len); +} + +void +sentry_options_set_database_pathw(sentry_options_t *opts, const wchar_t *path) +{ + size_t path_len = path ? wcslen(path) : 0; + sentry_options_set_database_pathw_n(opts, path, path_len); } #endif diff --git a/src/sentry_path.h b/src/sentry_path.h index d108c3735e..214076b0bc 100644 --- a/src/sentry_path.h +++ b/src/sentry_path.h @@ -209,6 +209,7 @@ void sentry__filelock_free(sentry_filelock_t *lock); * Create a new path from a Wide String. */ sentry_path_t *sentry__path_from_wstr(const wchar_t *s); +sentry_path_t *sentry__path_from_wstr_n(const wchar_t *s, size_t s_len); /** * Create another path by appending a new path segment. From 16c8c3021287559cbf73ae70f1a0b091a9615a04 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 24 Apr 2023 11:59:54 +0200 Subject: [PATCH 27/36] fix sentry__path_from_str[_n] on windows --- src/path/sentry_path_windows.c | 36 ++++++++++++++++----------------- src/sentry_path.h | 3 --- tests/unit/sentry_testsupport.h | 7 +++++++ tests/unit/test_path.c | 13 ++++++++++++ 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/path/sentry_path_windows.c b/src/path/sentry_path_windows.c index 11bcb7ec31..023b35bf4d 100644 --- a/src/path/sentry_path_windows.c +++ b/src/path/sentry_path_windows.c @@ -201,42 +201,42 @@ sentry__path_join_wstr(const sentry_path_t *base, const wchar_t *other) } sentry_path_t * -sentry__path_from_str(const char *s) +sentry__path_from_str_n(const char *s, size_t s_len) { if (!s) { return NULL; } - size_t len = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0); sentry_path_t *rv = SENTRY_MAKE(sentry_path_t); if (!rv) { return NULL; } - rv->path = sentry_malloc(sizeof(wchar_t) * len); + size_t src_size = sizeof(char) * s_len; + size_t dst_size = sizeof(wchar_t) * (s_len + 1); + rv->path = sentry_malloc(dst_size); if (!rv->path) { - sentry_free(rv); - return NULL; + goto error; } - MultiByteToWideChar(CP_ACP, 0, s, -1, rv->path, (int)len); + if (0 + == MultiByteToWideChar( + CP_ACP, 0, s, (int)src_size, rv->path, (int)s_len)) { + goto error; + } + rv->path[s_len] = 0; return rv; + +error: + sentry_free(rv); + return NULL; } sentry_path_t * -sentry__path_from_str_n(const char *s, size_t s_len) +sentry__path_from_str(const char *s) { if (!s) { return NULL; } - sentry_path_t *rv = SENTRY_MAKE(sentry_path_t); - if (!rv) { - return NULL; - } - rv->path = sentry_malloc(sizeof(wchar_t) * (s_len + 1)); - if (!rv->path) { - sentry_free(rv); - return NULL; - } - MultiByteToWideChar(CP_ACP, 0, s, -1, rv->path, (int)s_len + 1); - return rv; + + return sentry__path_from_str_n(s, strlen(s)); } sentry_path_t * diff --git a/src/sentry_path.h b/src/sentry_path.h index 214076b0bc..02e42d5fe0 100644 --- a/src/sentry_path.h +++ b/src/sentry_path.h @@ -54,9 +54,6 @@ sentry_path_t *sentry__path_dir(const sentry_path_t *path); */ sentry_path_t *sentry__path_from_str(const char *s); sentry_path_t *sentry__path_from_str_n(const char *s, size_t s_len); -#define CALL_SENTRY__PATH_FROM_STR(STR) sentry__path_from_str(STR) -#define CALL_SENTRY__PATH_FROM_STR_N(STR) \ - sentry__path_from_str_n(STR, STR##_len) /** * Create a new path from the given string. diff --git a/tests/unit/sentry_testsupport.h b/tests/unit/sentry_testsupport.h index 81927db1b7..bd6f112a76 100644 --- a/tests/unit/sentry_testsupport.h +++ b/tests/unit/sentry_testsupport.h @@ -23,6 +23,13 @@ TEST_MSG("Received: %s", Val); \ } while (0) +#define TEST_CHECK_WSTRING_EQUAL(Val, ReferenceVal) \ + do { \ + TEST_CHECK(wcscmp(Val, ReferenceVal) == 0); \ + TEST_MSG("Expected: %s", ReferenceVal); \ + TEST_MSG("Received: %s", Val); \ + } while (0) + #define TEST_CHECK_JSON_VALUE(Val, ReferenceJson) \ do { \ char *json = sentry_value_to_json(Val); \ diff --git a/tests/unit/test_path.c b/tests/unit/test_path.c index 1ae6f46bd5..8424d1f0b3 100644 --- a/tests/unit/test_path.c +++ b/tests/unit/test_path.c @@ -65,6 +65,19 @@ SENTRY_TEST(path_from_str_null) TEST_CHECK(NULL == sentry__path_from_str_n(NULL, 10)); } +SENTRY_TEST(path_from_str_n_wo_null_termination) +{ + // provide non-null-terminated path string with buffer character at the end. + char path_str[] = { 't', 'e', 's', 't', 'X' }; + sentry_path_t *test_path = sentry__path_from_str_n(path_str, 4); +#ifdef SENTRY_PLATFORM_WINDOWS + TEST_CHECK_WSTRING_EQUAL(test_path->path, L"test"); +#else + TEST_CHECK_STRING_EQUAL(test_path->path, "test"); +#endif + sentry__path_free(test_path); +} + SENTRY_TEST(path_joining_windows) { #ifndef SENTRY_PLATFORM_WINDOWS From 409c27d24081a8a7d627ac034e770930f2395bde Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 24 Apr 2023 12:29:29 +0200 Subject: [PATCH 28/36] sentry__path_from_str_n: use returned length of converted wide-chars. --- src/path/sentry_path_windows.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/path/sentry_path_windows.c b/src/path/sentry_path_windows.c index 023b35bf4d..b953af9a6b 100644 --- a/src/path/sentry_path_windows.c +++ b/src/path/sentry_path_windows.c @@ -216,12 +216,12 @@ sentry__path_from_str_n(const char *s, size_t s_len) if (!rv->path) { goto error; } - if (0 - == MultiByteToWideChar( - CP_ACP, 0, s, (int)src_size, rv->path, (int)s_len)) { + int conv_len = MultiByteToWideChar( + CP_ACP, 0, s, (int)src_size, rv->path, (int)s_len); + if (conv_len == 0) { goto error; } - rv->path[s_len] = 0; + rv->path[conv_len] = 0; return rv; error: From ded5a3fd0c60925997d839c6625da9c3b790c7a9 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 24 Apr 2023 12:54:41 +0200 Subject: [PATCH 29/36] fix sentry__string_clone[_n] naming --- src/sentry_core.c | 2 +- src/sentry_envelope.c | 2 +- src/sentry_json.c | 6 +++--- src/sentry_options.c | 13 ++++++------- src/sentry_slice.c | 2 +- src/sentry_string.h | 16 ++++++++++------ src/sentry_tracing.c | 4 ++-- src/sentry_utils.c | 18 +++++++++--------- src/sentry_value.c | 2 +- src/transports/sentry_transport_winhttp.c | 2 +- 10 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index e38e109d7c..54ddf242d9 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -794,7 +794,7 @@ sentry_set_transaction_n(const char *transaction, size_t transaction_len) SENTRY_WITH_SCOPE_MUT (scope) { sentry_free(scope->transaction); scope->transaction - = sentry__string_clonen_or_null(transaction, transaction_len); + = sentry__string_clone_n(transaction, transaction_len); if (scope->transaction_object) { sentry_transaction_set_name_n( diff --git a/src/sentry_envelope.c b/src/sentry_envelope.c index 3898f3f0b3..4b68a27871 100644 --- a/src/sentry_envelope.c +++ b/src/sentry_envelope.c @@ -322,7 +322,7 @@ sentry__envelope_add_from_buffer(sentry_envelope_t *envelope, const char *buf, // NOTE: function will check for the clone of `buf` internally and free it // on error return envelope_add_from_owned_buffer( - envelope, sentry__string_clonen(buf, buf_len), buf_len, type); + envelope, sentry__string_clone_n(buf, buf_len), buf_len, type); } sentry_envelope_item_t * diff --git a/src/sentry_json.c b/src/sentry_json.c index cf02c7f1b9..f83cd1886d 100644 --- a/src/sentry_json.c +++ b/src/sentry_json.c @@ -471,8 +471,8 @@ tokens_to_value(jsmntok_t *tokens, size_t token_count, const char *buf, break; } case JSMN_STRING: { - char *string - = sentry__string_clonen(buf + root->start, root->end - root->start); + char *string = sentry__string_clone_n_unchecked( + buf + root->start, root->end - root->start); if (decode_string_inplace(string)) { rv = sentry__value_new_string_owned(string); } else { @@ -492,7 +492,7 @@ tokens_to_value(jsmntok_t *tokens, size_t token_count, const char *buf, sentry_value_t child; NESTED_PARSE(&child); - char *key = sentry__string_clonen( + char *key = sentry__string_clone_n_unchecked( buf + token->start, token->end - token->start); if (decode_string_inplace(key)) { sentry_value_set_by_key(rv, key, child); diff --git a/src/sentry_options.c b/src/sentry_options.c index 398aecc0ce..4814bfefd2 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -173,7 +173,7 @@ sentry_options_set_release_n( sentry_options_t *opts, const char *release, size_t release_len) { sentry_free(opts->release); - opts->release = sentry__string_clonen_or_null(release, release_len); + opts->release = sentry__string_clone_n(release, release_len); } void @@ -194,8 +194,7 @@ sentry_options_set_environment_n( sentry_options_t *opts, const char *environment, size_t environment_len) { sentry_free(opts->environment); - opts->environment - = sentry__string_clonen_or_null(environment, environment_len); + opts->environment = sentry__string_clone_n(environment, environment_len); } void @@ -216,7 +215,7 @@ sentry_options_set_dist_n( sentry_options_t *opts, const char *dist, size_t dist_len) { sentry_free(opts->dist); - opts->dist = sentry__string_clonen_or_null(dist, dist_len); + opts->dist = sentry__string_clone_n(dist, dist_len); } void @@ -237,7 +236,7 @@ sentry_options_set_http_proxy_n( sentry_options_t *opts, const char *proxy, size_t proxy_len) { sentry_free(opts->http_proxy); - opts->http_proxy = sentry__string_clonen_or_null(proxy, proxy_len); + opts->http_proxy = sentry__string_clone_n(proxy, proxy_len); } void @@ -265,7 +264,7 @@ sentry_options_set_ca_certs_n( sentry_options_t *opts, const char *path, size_t path_len) { sentry_free(opts->ca_certs); - opts->ca_certs = sentry__string_clonen(path, path_len); + opts->ca_certs = sentry__string_clone_n(path, path_len); } const char * @@ -287,7 +286,7 @@ sentry_options_set_transport_thread_name_n( sentry_options_t *opts, const char *name, size_t name_len) { sentry_free(opts->transport_thread_name); - opts->transport_thread_name = sentry__string_clonen_or_null(name, name_len); + opts->transport_thread_name = sentry__string_clone_n(name, name_len); } const char * diff --git a/src/sentry_slice.c b/src/sentry_slice.c index 79894b7ded..0f68311b22 100644 --- a/src/sentry_slice.c +++ b/src/sentry_slice.c @@ -15,7 +15,7 @@ sentry__slice_from_str(const char *str) char * sentry__slice_to_owned(sentry_slice_t slice) { - return sentry__string_clonen(slice.ptr, slice.len); + return sentry__string_clone_n_unchecked(slice.ptr, slice.len); } bool diff --git a/src/sentry_string.h b/src/sentry_string.h index 9d566229c6..95e1e4f614 100644 --- a/src/sentry_string.h +++ b/src/sentry_string.h @@ -110,10 +110,11 @@ size_t sentry__stringbuilder_len(const sentry_stringbuilder_t *sb); void sentry__stringbuilder_set_len(sentry_stringbuilder_t *sb, size_t len); /** - * Duplicates a zero terminated string with a length limit. + * Duplicates a zero terminated string with a length limit. Does not check + * if `str` is NULL. */ static inline char * -sentry__string_clonen(const char *str, size_t n) +sentry__string_clone_n_unchecked(const char *str, size_t n) { size_t len = n + 1; char *rv = (char *)sentry_malloc(len); @@ -124,10 +125,13 @@ sentry__string_clonen(const char *str, size_t n) return rv; } +/** + * Duplicates a ptr/len string into a zero terminated string. + */ static inline char * -sentry__string_clonen_or_null(const char *str, size_t n) +sentry__string_clone_n(const char *str, size_t n) { - return str ? sentry__string_clonen(str, n) : NULL; + return str ? sentry__string_clone_n_unchecked(str, n) : NULL; } /** @@ -136,7 +140,7 @@ sentry__string_clonen_or_null(const char *str, size_t n) static inline char * sentry__string_clone(const char *str) { - return str ? sentry__string_clonen(str, strlen(str)) : NULL; + return str ? sentry__string_clone_n_unchecked(str, strlen(str)) : NULL; } static inline char * @@ -146,7 +150,7 @@ sentry__string_clone_max_n(const char *str, size_t str_len, size_t max_len) return NULL; } size_t min_len = str_len < max_len ? str_len : max_len; - return sentry__string_clonen(str, min_len); + return sentry__string_clone_n_unchecked(str, min_len); } /** diff --git a/src/sentry_tracing.c b/src/sentry_tracing.c index 779fb278cb..b32c30496a 100644 --- a/src/sentry_tracing.c +++ b/src/sentry_tracing.c @@ -186,7 +186,7 @@ sentry_transaction_context_update_from_header_n( sentry_value_t inner = tx_cxt->inner; char *s - = sentry__string_clonen(trace_id_start, trace_id_end - trace_id_start); + = sentry__string_clone_n(trace_id_start, trace_id_end - trace_id_start); sentry_value_t trace_id = sentry__value_new_string_owned(s); sentry_value_set_by_key(inner, "trace_id", trace_id); @@ -200,7 +200,7 @@ sentry_transaction_context_update_from_header_n( } // else: we have a sampled flag - s = sentry__string_clonen(span_id_start, span_id_end - span_id_start); + s = sentry__string_clone_n(span_id_start, span_id_end - span_id_start); sentry_value_t parent_span_id = sentry__value_new_string_owned(s); sentry_value_set_by_key(inner, "parent_span_id", parent_span_id); diff --git a/src/sentry_utils.c b/src/sentry_utils.c index 0375275f50..55f42be5c1 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -63,7 +63,7 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) if (!tmp) { goto error; } - url_out->scheme = sentry__string_clonen(ptr, tmp - ptr); + url_out->scheme = sentry__string_clone_n_unchecked(ptr, tmp - ptr); if (!url_out->scheme || !is_scheme_valid(url_out->scheme)) { goto error; @@ -96,13 +96,13 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) tmp = ptr; if (has_username) { SKIP_WHILE_NOT2(tmp, '@', ':'); - url_out->username = sentry__string_clonen(ptr, tmp - ptr); + url_out->username = sentry__string_clone_n_unchecked(ptr, tmp - ptr); ptr = tmp; if (*ptr == ':') { ptr++; tmp = ptr; SKIP_WHILE_NOT(tmp, '@'); - url_out->password = sentry__string_clonen(ptr, tmp - ptr); + url_out->password = sentry__string_clone_n_unchecked(ptr, tmp - ptr); ptr = tmp; } if (*ptr != '@') { @@ -125,7 +125,7 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) tmp++; } - url_out->host = sentry__string_clonen(ptr, tmp - ptr); + url_out->host = sentry__string_clone_n_unchecked(ptr, tmp - ptr); /* port */ ptr = tmp; @@ -133,7 +133,7 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) ptr++; tmp = ptr; SKIP_WHILE_NOT(tmp, '/'); - aux_buf = sentry__string_clonen(ptr, tmp - ptr); + aux_buf = sentry__string_clone_n_unchecked(ptr, tmp - ptr); char *end; url_out->port = (int)strtol(aux_buf, &end, 10); if (end != aux_buf + strlen(aux_buf)) { @@ -156,7 +156,7 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) /* path */ tmp = ptr; SKIP_WHILE_NOT2(tmp, '#', '?'); - url_out->path = sentry__string_clonen(ptr, tmp - ptr); + url_out->path = sentry__string_clone_n_unchecked(ptr, tmp - ptr); ptr = tmp; /* query */ @@ -164,7 +164,7 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) ptr++; tmp = ptr; SKIP_WHILE_NOT(tmp, '#'); - url_out->query = sentry__string_clonen(ptr, tmp - ptr); + url_out->query = sentry__string_clone_n_unchecked(ptr, tmp - ptr); ptr = tmp; } @@ -173,7 +173,7 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) ptr++; tmp = ptr; SKIP_WHILE_NOT(tmp, 0); - url_out->fragment = sentry__string_clonen(ptr, tmp - ptr); + url_out->fragment = sentry__string_clone_n_unchecked(ptr, tmp - ptr); } if (url_out->port == 0) { @@ -226,7 +226,7 @@ sentry__dsn_new_n(const char *raw_dsn, size_t raw_dsn_len) memset(dsn, 0, sizeof(sentry_dsn_t)); dsn->refcount = 1; - dsn->raw = sentry__string_clonen_or_null(raw_dsn, raw_dsn_len); + dsn->raw = sentry__string_clone_n(raw_dsn, raw_dsn_len); if (!dsn->raw || !dsn->raw[0] || sentry__url_parse(&url, dsn->raw) != 0) { goto exit; } diff --git a/src/sentry_value.c b/src/sentry_value.c index abc20c300d..9f4b39c15b 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -322,7 +322,7 @@ sentry_value_new_bool(int value) sentry_value_t sentry_value_new_string_n(const char *value, size_t len) { - char *s = sentry__string_clonen_or_null(value, len); + char *s = sentry__string_clone_n(value, len); if (!s) { return sentry_value_new_null(); } diff --git a/src/transports/sentry_transport_winhttp.c b/src/transports/sentry_transport_winhttp.c index 9d509f23d8..93848c3452 100644 --- a/src/transports/sentry_transport_winhttp.c +++ b/src/transports/sentry_transport_winhttp.c @@ -74,7 +74,7 @@ sentry__winhttp_transport_start( const char *ptr = opts->http_proxy + 7; const char *slash = strchr(ptr, '/'); if (slash) { - char *copy = sentry__string_clonen(ptr, slash - ptr); + char *copy = sentry__string_clone_n(ptr, slash - ptr); state->proxy = sentry__string_to_wstr(copy); sentry_free(copy); } else { From f9043398a9d7b37d4d5f637c5e49abb85f308c1d Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 24 Apr 2023 13:21:54 +0200 Subject: [PATCH 30/36] format --- src/sentry_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sentry_utils.c b/src/sentry_utils.c index 55f42be5c1..bb80a98f0a 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -102,7 +102,8 @@ sentry__url_parse(sentry_url_t *url_out, const char *url) ptr++; tmp = ptr; SKIP_WHILE_NOT(tmp, '@'); - url_out->password = sentry__string_clone_n_unchecked(ptr, tmp - ptr); + url_out->password + = sentry__string_clone_n_unchecked(ptr, tmp - ptr); ptr = tmp; } if (*ptr != '@') { From 6f72973cab82cf69e16f97ac54be99306d673d2d Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Mon, 24 Apr 2023 13:28:23 +0200 Subject: [PATCH 31/36] fix affected unixy functions after changes on windows --- src/path/sentry_path_unix.c | 2 +- src/transports/sentry_transport_curl.c | 2 +- tests/unit/tests.inc | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/path/sentry_path_unix.c b/src/path/sentry_path_unix.c index 91d18e179e..2fb46195c4 100644 --- a/src/path/sentry_path_unix.c +++ b/src/path/sentry_path_unix.c @@ -171,7 +171,7 @@ sentry__path_dir(const sentry_path_t *path) sentry_path_t * sentry__path_from_str_n(const char *s, size_t s_len) { - char *path = sentry__string_clonen_or_null(s, s_len); + char *path = sentry__string_clone_n(s, s_len); if (!path) { return NULL; } diff --git a/src/transports/sentry_transport_curl.c b/src/transports/sentry_transport_curl.c index f4c8654d31..230be55d6f 100644 --- a/src/transports/sentry_transport_curl.c +++ b/src/transports/sentry_transport_curl.c @@ -140,7 +140,7 @@ header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { size_t bytes = size * nitems; struct header_info *info = userdata; - char *header = sentry__string_clonen(buffer, bytes); + char *header = sentry__string_clone_n(buffer, bytes); if (!header) { return bytes; } diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 70f6c6f31a..94b1cbca5f 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -57,6 +57,7 @@ XX(page_allocator) XX(path_basics) XX(path_current_exe) XX(path_directory) +XX(path_from_str_n_wo_null_termination) XX(path_from_str_null) XX(path_joining_unix) XX(path_joining_windows) From afd70a63aa17914ceff2a615c63b249ec2d9e755 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Apr 2023 13:40:04 +0200 Subject: [PATCH 32/36] get rid of SYSTEM_VERSION_COMPAT in Makefile --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f8c5971de9..a936b143fd 100644 --- a/Makefile +++ b/Makefile @@ -25,10 +25,8 @@ test-unit: update-test-discovery CMakeLists.txt ./unit-build/sentry_test_unit .PHONY: test-unit -# SYSTEM_VERSION_COMPAT=0 is required (starting with BigSur) to get the correct macOS version for context assertions: -# https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-release-notes#Third-Party-Apps test-integration: setup-venv - SYSTEM_VERSION_COMPAT=0 .venv/bin/pytest tests --verbose + .venv/bin/pytest tests --verbose .PHONY: test-integration test-leaks: update-test-discovery CMakeLists.txt From 4b1ec837b5488d6bcb3aca7cdb992884233589eb Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Apr 2023 14:40:21 +0200 Subject: [PATCH 33/36] do curl_global_cleanup() after curl_easy_cleanup() in transport free this isn't going to fix our "leak", but it de-inits resources acquired by curl_global_init(). --- src/transports/sentry_transport_curl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transports/sentry_transport_curl.c b/src/transports/sentry_transport_curl.c index 230be55d6f..b9f52c8813 100644 --- a/src/transports/sentry_transport_curl.c +++ b/src/transports/sentry_transport_curl.c @@ -47,6 +47,7 @@ sentry__curl_bgworker_state_free(void *_state) curl_bgworker_state_t *state = _state; if (state->curl_handle) { curl_easy_cleanup(state->curl_handle); + curl_global_cleanup(); } sentry__dsn_decref(state->dsn); sentry__rate_limiter_free(state->ratelimiter); @@ -247,7 +248,6 @@ sentry__curl_send_task(void *_envelope, void *_state) } } - curl_easy_reset(curl); curl_slist_free_all(headers); sentry_free(info.retry_after); sentry_free(info.x_sentry_rate_limits); From 042329e5fbfe80292aa5634c928c461a3cd0d655 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Apr 2023 14:42:22 +0200 Subject: [PATCH 34/36] suppress SCDynamicStoreCopyProxiesWithOptions in LSAN the supposed leak-culprit to which we have no (de-)allocation control. --- tests/leaks.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/leaks.txt b/tests/leaks.txt index 2ba3e9dc8b..4ca4e4b684 100644 --- a/tests/leaks.txt +++ b/tests/leaks.txt @@ -3,3 +3,4 @@ # Adding a manual `[paths release]` "fixes" the `crashpad_handler` leak, but leads to a use-after-free in sentry. # https://github.com/getsentry/crashpad/blob/9cd1a4dadb51b31665f5e50c5ffc25bb9d10571a/client/crash_report_database_mac.mm#L705 leak:contentsOfDirectoryAtPath +leak:SCDynamicStoreCopyProxiesWithOptions From 381b4cbc79f5240444114fa6fff3c0193b6a8775 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Apr 2023 15:11:54 +0200 Subject: [PATCH 35/36] fix len-parameter name in header --- include/sentry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sentry.h b/include/sentry.h index d038b005e0..df9266cb61 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -957,7 +957,7 @@ SENTRY_API const char *sentry_options_get_environment( SENTRY_API void sentry_options_set_dist( sentry_options_t *opts, const char *dist); SENTRY_API void sentry_options_set_dist_n( - sentry_options_t *opts, const char *dist, size_t len); + sentry_options_t *opts, const char *dist, size_t dist_len); /** * Gets the dist. From 5a4664a56d189c5eec794331d17ff559b3de91c4 Mon Sep 17 00:00:00 2001 From: Mischan Toosarani-Hausberger Date: Tue, 25 Apr 2023 15:53:40 +0200 Subject: [PATCH 36/36] cosmetic cleanups. --- include/sentry.h | 2 +- src/path/sentry_path_unix.c | 2 +- src/sentry_core.c | 4 ++-- src/sentry_value.c | 6 +++--- tests/unit/test_attachments.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index df9266cb61..32cecb63a2 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -207,7 +207,6 @@ SENTRY_API sentry_value_t sentry_value_new_bool(int value); * Creates a new null terminated string. */ SENTRY_API sentry_value_t sentry_value_new_string(const char *value); - SENTRY_API sentry_value_t sentry_value_new_string_n( const char *value, size_t value_len); @@ -1171,6 +1170,7 @@ SENTRY_API void sentry_options_add_attachmentw( sentry_options_t *opts, const wchar_t *path); SENTRY_API void sentry_options_add_attachmentw_n( sentry_options_t *opts, const wchar_t *path, size_t path_len); + /** * Wide char version of `sentry_options_set_handler_path`. */ diff --git a/src/path/sentry_path_unix.c b/src/path/sentry_path_unix.c index 2fb46195c4..298913996b 100644 --- a/src/path/sentry_path_unix.c +++ b/src/path/sentry_path_unix.c @@ -175,7 +175,7 @@ sentry__path_from_str_n(const char *s, size_t s_len) if (!path) { return NULL; } - /* NOTE: function will free `path` on error */ + // NOTE: function will free `path` on error return sentry__path_from_str_owned(path); } diff --git a/src/sentry_core.c b/src/sentry_core.c index 54ddf242d9..8cbb39a031 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -962,8 +962,8 @@ sentry_transaction_start_child_n(sentry_transaction_t *opaque_parent, } sentry_value_t parent = opaque_parent->inner; - /* TODO: consider snapshotting this value during tx creation and - * storing in tx and span */ + // TODO: consider snapshotting this value during tx creation and storing in + // tx and span size_t max_spans = SENTRY_SPANS_MAX; SENTRY_WITH_OPTIONS (options) { max_spans = options->max_spans; diff --git a/src/sentry_value.c b/src/sentry_value.c index 9f4b39c15b..e46eb79f5e 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -320,9 +320,9 @@ sentry_value_new_bool(int value) } sentry_value_t -sentry_value_new_string_n(const char *value, size_t len) +sentry_value_new_string_n(const char *value, size_t value_len) { - char *s = sentry__string_clone_n(value, len); + char *s = sentry__string_clone_n(value, value_len); if (!s) { return sentry_value_new_null(); } @@ -1216,7 +1216,7 @@ sentry_value_new_thread_n(uint64_t id, const char *name, size_t name_len) { sentry_value_t thread = sentry_value_new_object(); - /* NOTE: values end up as JSON, which has no support for `u64`. */ + // NOTE: values end up as JSON, which has no support for `u64`. char buf[20 + 1]; size_t written = (size_t)snprintf(buf, sizeof(buf), "%llu", (unsigned long long)id); diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index bbf4e61428..62dcf0af72 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -35,7 +35,7 @@ SENTRY_TEST(lazy_attachments) sentry_options_set_transport(options, sentry_new_function_transport( send_envelope_test_attachments, &testdata)); - char rel[4] = { 't', 'e', 's', 't' }; + char rel[] = { 't', 'e', 's', 't' }; sentry_options_set_release_n(options, rel, sizeof(rel)); sentry_options_add_attachment(options, PREFIX ".existing-file-attachment");