diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e80756e4..04ffe37d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +**Features**: + +- Add `sentry_get_last_crash` to allow fetching `event_id` from last crash. ([#1711](https://github.com/getsentry/sentry-native/pull/1711)) + **Fixes**: - Reject overly deep msgpack payloads during deserialization. ([#1727](https://github.com/getsentry/sentry-native/pull/1727)) diff --git a/include/sentry.h b/include/sentry.h index a3ecfe260..c62877b15 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -3562,6 +3562,39 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_iter_headers( */ SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run(void); +/** + * Information about the crash from the last run. + */ +typedef struct sentry_last_crash_s { + /** + * The crash timestamp in microseconds since the Unix epoch, or 0 if it is + * unavailable. + */ + uint64_t timestamp; + /** + * The crash event ID, or a nil UUID if it is unavailable. + */ + sentry_uuid_t event_id; +} sentry_last_crash_t; + +/** + * Returns whether the application crashed on the last run, and populates + * `crash` with available information. + * + * Pass `sizeof(sentry_last_crash_t)` as `crash_size` so future SDK versions can + * add fields without breaking callers compiled against older headers. Call + * `sentry_clear_crashed_last_run()` to reset for the next app run. + * + * Note: This does not work with crashpad on macOS, similar to `on_crash`. + * + * Possible return values: + * 1 = the last run was a crash + * 0 = no crash recognized + * -1 = sentry_init() hasn't been called yet + */ +SENTRY_API int sentry_get_last_crash( + sentry_last_crash_t *crash, size_t crash_size); + /** * Clear the status of the "crashed-last-run". You should explicitly call * this after sentry_init() if you're using sentry_get_crashed_last_run(). diff --git a/src/backends/sentry_backend_breakpad.cpp b/src/backends/sentry_backend_breakpad.cpp index de10c55e1..c27cff502 100644 --- a/src/backends/sentry_backend_breakpad.cpp +++ b/src/backends/sentry_backend_breakpad.cpp @@ -132,12 +132,13 @@ breakpad_backend_callback(const google_breakpad::MinidumpDescriptor &descriptor, #else dump_path = sentry__path_new(descriptor.path()); #endif - sentry_value_t event = sentry_value_new_event(); + sentry_uuid_t event_id = sentry__new_event_id(); + sentry_value_t event = sentry__value_new_event_with_id(&event_id); sentry_value_set_by_key( event, "level", sentry__value_new_level(SENTRY_LEVEL_FATAL)); SENTRY_WITH_OPTIONS (options) { - sentry__write_crash_marker(options); + sentry__write_crash_marker(options, &event_id); bool should_handle = true; diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index bdfd50a9c..8181fb225 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -386,7 +386,7 @@ crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context) if (should_dump) { flush_scope_from_handler(options, crash_event); - sentry__write_crash_marker(options); + sentry__write_crash_marker(options, &state->crash_event_id); sentry__record_errors_on_current_session(1); sentry_session_t *session = sentry__end_current_session_with_status( diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index f3f9e0e48..fd33cb5fb 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -999,9 +999,10 @@ get_instruction_pointer(const sentry_ucontext_t *uctx) static sentry_value_t make_signal_event(const struct signal_slot *sig_slot, - const sentry_ucontext_t *uctx, sentry_handler_strategy_t strategy) + const sentry_ucontext_t *uctx, sentry_handler_strategy_t strategy, + const sentry_uuid_t *event_id) { - sentry_value_t event = sentry_value_new_event(); + sentry_value_t event = sentry__value_new_event_with_id(event_id); sentry_value_set_by_key( event, "level", sentry__value_new_level(SENTRY_LEVEL_FATAL)); @@ -1111,9 +1112,11 @@ process_ucontext_deferred(const sentry_ucontext_t *uctx, options ? sentry_options_get_handler_strategy(options) : #endif SENTRY_HANDLER_STRATEGY_DEFAULT; - sentry_value_t event = make_signal_event(sig_slot, uctx, strategy); + sentry_uuid_t event_id = sentry__new_event_id(); + sentry_value_t event + = make_signal_event(sig_slot, uctx, strategy, &event_id); bool should_handle = true; - sentry__write_crash_marker(options); + sentry__write_crash_marker(options, &event_id); if (options->on_crash_func && !skip_hooks) { SENTRY_DEBUG("invoking `on_crash` hook"); diff --git a/src/backends/sentry_backend_native.c b/src/backends/sentry_backend_native.c index fe1af9322..4cd05b9bf 100644 --- a/src/backends/sentry_backend_native.c +++ b/src/backends/sentry_backend_native.c @@ -986,10 +986,11 @@ native_backend_except(sentry_backend_t *backend, const sentry_ucontext_t *uctx) } // Write crash marker - sentry__write_crash_marker(options); + sentry_uuid_t event_id = sentry__new_event_id(); + sentry__write_crash_marker(options, &event_id); // Create crash event - sentry_value_t event = sentry_value_new_event(); + sentry_value_t event = sentry__value_new_event_with_id(&event_id); sentry_value_set_by_key( event, "level", sentry__value_new_level(SENTRY_LEVEL_FATAL)); diff --git a/src/sentry_core.c b/src/sentry_core.c index 3019f7884..da4d1946d 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1,6 +1,7 @@ #include "sentry_boot.h" #include +#include #include #include "sentry_attachment.h" @@ -44,6 +45,13 @@ static sentry_mutex_t g_options_lock = SENTRY__MUTEX_INIT; #endif /// see sentry_get_crashed_last_run() for the possible values static int g_last_crash = -1; +static sentry_last_crash_t g_last_crash_info; + +static inline bool +last_crash_has_field(size_t struct_size, size_t offset, size_t size) +{ + return offset <= struct_size && size <= struct_size - offset; +} const sentry_options_t * sentry__options_getref(void) @@ -194,7 +202,7 @@ sentry_init(sentry_options_t *options) last_crash = backend->get_last_crash_func(backend); } - g_last_crash = sentry__has_crash_marker(options); + g_last_crash = sentry__read_crash_marker(options, &g_last_crash_info); g_options = options; // *after* setting the global options, trigger a scope and consent flush, @@ -1745,6 +1753,28 @@ sentry_get_crashed_last_run(void) return g_last_crash; } +int +sentry_get_last_crash(sentry_last_crash_t *crash, size_t crash_size) +{ + if (crash && crash_size > 0) { + memset(crash, 0, crash_size); + + if (g_last_crash == 1 + && last_crash_has_field(crash_size, + offsetof(sentry_last_crash_t, timestamp), + sizeof(crash->timestamp))) { + crash->timestamp = g_last_crash_info.timestamp; + } + if (g_last_crash == 1 + && last_crash_has_field(crash_size, + offsetof(sentry_last_crash_t, event_id), + sizeof(crash->event_id))) { + crash->event_id = g_last_crash_info.event_id; + } + } + return g_last_crash; +} + int sentry_clear_crashed_last_run(void) { diff --git a/src/sentry_database.c b/src/sentry_database.c index ced802ebf..57547ef66 100644 --- a/src/sentry_database.c +++ b/src/sentry_database.c @@ -16,6 +16,58 @@ #include #include +static char * +read_metadata( + const sentry_path_t *path, sentry_slice_t *first, sentry_slice_t *second) +{ + size_t size = 0; + char *contents_buf = sentry__path_read_to_buffer(path, &size); + if (!contents_buf) { + return NULL; + } + + sentry_slice_t contents + = sentry__slice_trim((sentry_slice_t) { contents_buf, size }); + if (contents.len == 0) { + return contents_buf; + } + + size_t first_len = 0; + while (first_len < contents.len + && !isspace((unsigned char)contents.ptr[first_len])) { + first_len++; + } + *first = (sentry_slice_t) { contents.ptr, first_len }; + *second = sentry__slice_trim((sentry_slice_t) { + contents.ptr + first_len, contents.len - first_len }); + + return contents_buf; +} + +static int +write_metadata(const sentry_path_t *path, const char *first, size_t first_len, + const char *second, size_t second_len) +{ + bool has_second = second != NULL; + size_t buf_len = first_len + (has_second ? 1 + second_len + 1 : 0); + char *buf = sentry_malloc(buf_len); + if (!buf) { + return 1; + } + + memcpy(buf, first, first_len); + if (has_second) { + buf[first_len] = '\n'; + memcpy(buf + first_len + 1, second, second_len); + buf[first_len + 1 + second_len] = '\n'; + } + + int rv = sentry__path_write_buffer(path, buf, buf_len); + sentry_free(buf); + + return rv; +} + sentry_run_t * sentry__run_new(const sentry_path_t *database_path) { @@ -149,17 +201,13 @@ sentry__run_load_installation_id(sentry_run_t *run, const size_t uuid_len = 36; char uuid_str[37] = { 0 }; - size_t size = 0; - char *contents = sentry__path_read_to_buffer(id_path, &size); - if (contents && size >= uuid_len) { - // expect: "(\s+)?" - sentry_slice_t tail = { contents + uuid_len, size - uuid_len }; - sentry_slice_t key = sentry__slice_trim(tail); - if ((tail.len == 0 || isspace((unsigned char)tail.ptr[0])) - && sentry__slice_eqs(key, public_key)) { - memcpy(uuid_str, contents, uuid_len); - uuid_str[uuid_len] = '\0'; - } + sentry_slice_t first = { 0 }; + sentry_slice_t second = { 0 }; + char *contents = read_metadata(id_path, &first, &second); + // expect: "(\s+)?" + if (first.len == uuid_len && sentry__slice_eqs(second, public_key)) { + memcpy(uuid_str, first.ptr, uuid_len); + uuid_str[uuid_len] = '\0'; } sentry_free(contents); @@ -167,17 +215,10 @@ sentry__run_load_installation_id(sentry_run_t *run, sentry_uuid_t uuid = sentry_uuid_new_v4(); sentry_uuid_as_string(&uuid, uuid_str); - const size_t buf_len = uuid_len + 1 + key_len + 1; - char *buf = sentry_malloc(buf_len); - if (buf) { - memcpy(buf, uuid_str, uuid_len); - buf[uuid_len] = '\n'; - memcpy(buf + uuid_len + 1, public_key, key_len); - buf[uuid_len + 1 + key_len] = '\n'; - if (sentry__path_write_buffer(id_path, buf, buf_len) != 0) { - SENTRY_WARN("failed to persist installation ID"); - } - sentry_free(buf); + int rv + = write_metadata(id_path, uuid_str, uuid_len, public_key, key_len); + if (rv) { + SENTRY_WARN("failed to persist installation ID"); } } @@ -974,7 +1015,8 @@ sentry__cleanup_cache(const sentry_options_t *options) static const char *g_last_crash_filename = "last_crash"; bool -sentry__write_crash_marker(const sentry_options_t *options) +sentry__write_crash_marker( + const sentry_options_t *options, const sentry_uuid_t *event_id) { char *iso_time = sentry__usec_time_to_iso8601(sentry__usec_time()); if (!iso_time) { @@ -989,7 +1031,17 @@ sentry__write_crash_marker(const sentry_options_t *options) } size_t iso_time_len = strlen(iso_time); - int rv = sentry__path_write_buffer(marker_path, iso_time, iso_time_len); + char event_id_str[37]; + const char *event_id_value = NULL; + size_t event_id_len = 0; + if (event_id && !sentry_uuid_is_nil(event_id)) { + sentry_uuid_as_string(event_id, event_id_str); + event_id_value = event_id_str; + event_id_len = strlen(event_id_str); + } + + int rv = write_metadata( + marker_path, iso_time, iso_time_len, event_id_value, event_id_len); sentry_free(iso_time); sentry__path_free(marker_path); @@ -999,6 +1051,41 @@ sentry__write_crash_marker(const sentry_options_t *options) return !rv; } +int +sentry__read_crash_marker( + const sentry_options_t *options, sentry_last_crash_t *crash) +{ + if (crash) { + memset(crash, 0, sizeof(*crash)); + } + + sentry_path_t *marker_path + = sentry__path_join_str(options->database_path, g_last_crash_filename); + if (!marker_path) { + return 0; + } + + sentry_slice_t first = { 0 }; + sentry_slice_t second = { 0 }; + char *contents = read_metadata(marker_path, &first, &second); + int crashed = contents ? 1 : 0; + if (crash && first.len > 0) { + crash->timestamp = sentry__iso8601_to_usec(first.ptr, first.len); + } + + if (crash && (second.len == 32 || second.len == 36)) { + sentry_uuid_t parsed + = sentry_uuid_from_string_n(second.ptr, second.len); + if (!sentry_uuid_is_nil(&parsed)) { + crash->event_id = parsed; + } + } + + sentry_free(contents); + sentry__path_free(marker_path); + return crashed; +} + bool sentry__has_crash_marker(const sentry_options_t *options) { diff --git a/src/sentry_database.h b/src/sentry_database.h index d1c94ece6..51315ff1e 100644 --- a/src/sentry_database.h +++ b/src/sentry_database.h @@ -192,7 +192,14 @@ void sentry__cleanup_cache(const sentry_options_t *options); * This will write the current ISO8601 formatted timestamp into the * `/last_crash` file. */ -bool sentry__write_crash_marker(const sentry_options_t *options); +bool sentry__write_crash_marker( + const sentry_options_t *options, const sentry_uuid_t *event_id); + +/** + * This will read the crash information from the `/last_crash` file. + */ +int sentry__read_crash_marker( + const sentry_options_t *options, sentry_last_crash_t *crash); /** * This will check whether the `/last_crash` file exists. diff --git a/src/sentry_session.c b/src/sentry_session.c index e550a850a..953a62aa6 100644 --- a/src/sentry_session.c +++ b/src/sentry_session.c @@ -182,7 +182,7 @@ sentry__session_from_json(const char *buf, size_t buflen) rv->errors = (uint64_t)sentry_value_as_int32( sentry_value_get_by_key(value, "errors")); rv->started_us = sentry__iso8601_to_usec( - sentry_value_as_string(sentry_value_get_by_key(value, "started"))); + sentry_value_as_string(sentry_value_get_by_key(value, "started")), 0); double duration = sentry_value_as_double(sentry_value_get_by_key(value, "duration")); diff --git a/src/sentry_utils.c b/src/sentry_utils.c index f0d5e7d85..c838ded27 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -479,9 +479,9 @@ sentry__usec_time_to_iso8601(uint64_t time) #ifndef SENTRY_PLATFORM_PS uint64_t -sentry__iso8601_to_usec(const char *iso) +sentry__iso8601_to_usec(const char *iso, size_t iso_len) { - size_t len = sentry__guarded_strlen(iso); + size_t len = iso_len ? iso_len : sentry__guarded_strlen(iso); if (len != 20 && len != 27) { return 0; } diff --git a/src/sentry_utils.h b/src/sentry_utils.h index 74f3dc99a..08681c96c 100644 --- a/src/sentry_utils.h +++ b/src/sentry_utils.h @@ -249,7 +249,7 @@ char *sentry__usec_time_to_iso8601(uint64_t time); * This only accepts the format `YYYY-MM-DD'T'hh:mm:ss(.zzzzzz)'Z'`, which is * produced by the `sentry__usec_time_to_iso8601` function. */ -uint64_t sentry__iso8601_to_usec(const char *iso); +uint64_t sentry__iso8601_to_usec(const char *iso, size_t iso_len); /** * Locale independent (or rather, using "C" locale) `strtod`. diff --git a/tests/assertions.py b/tests/assertions.py index 5592f3989..eaa65f1f4 100644 --- a/tests/assertions.py +++ b/tests/assertions.py @@ -437,13 +437,17 @@ def assert_native_crash(envelope, exception_code=None): assert len(exc["stacktrace"]["frames"]) > 0 -def assert_crash_timestamp(has_files, tmp_path): +def assert_crash_timestamp(has_files, tmp_path, event_id=None): # The crash file should survive a `sentry_init` and should still be there # even after restarts. if has_files: with open("{}/.sentry-native/last_crash".format(tmp_path)) as f: - crash_timestamp = f.read() + crash_marker = f.read().split() + crash_timestamp = crash_marker[0] assert_timestamp(crash_timestamp) + if event_id is not None: + assert len(crash_marker) > 1 + assert crash_marker[1] == event_id def assert_before_send(envelope): diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index d8d9b5489..81b3517dc 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -31,6 +31,7 @@ assert_session, assert_gzip_file_header, assert_logs, + assert_crash_timestamp, assert_user_feedback, wait_for_file, ) @@ -425,6 +426,8 @@ def test_crashpad_dumping_crash(cmake, httpserver, run_args, build_args): expect_view_hierarchy="clear-attachments" not in run_args, ) event_id = attachments.event["event_id"] + if sys.platform != "darwin": + assert_crash_timestamp(True, tmp_path, event_id) if sys.platform == "win32": minidump = tmp_path / ".sentry-native" / "reports" / f"{event_id}.dmp" else: diff --git a/tests/test_integration_http.py b/tests/test_integration_http.py index 0b3352665..73301a892 100644 --- a/tests/test_integration_http.py +++ b/tests/test_integration_http.py @@ -32,6 +32,7 @@ assert_attachment_view_hierarchy, assert_before_breadcrumb, assert_no_breadcrumbs, + assert_crash_timestamp, ) from .conditions import ( has_http, @@ -487,6 +488,8 @@ def test_inproc_crash_http(cmake, httpserver, build_args): assert_gzip_file_header(body) envelope = Envelope.deserialize(body) + event = envelope.get_event() + assert_crash_timestamp(has_files, tmp_path, event["event_id"]) assert_session(envelope, {"init": True, "status": "crashed", "errors": 1}) @@ -589,6 +592,8 @@ def test_breakpad_crash_http(cmake, httpserver, build_args): assert_gzip_file_header(body) envelope = Envelope.deserialize(body) + event = envelope.get_event() + assert_crash_timestamp(has_files, tmp_path, event["event_id"]) assert_session(envelope, {"init": True, "status": "crashed", "errors": 1}) @@ -848,6 +853,8 @@ def test_native_crash_http(cmake, httpserver): assert len(httpserver.log) >= 1 req = httpserver.log[0][0] envelope = Envelope.deserialize(req.get_data()) + event = envelope.get_event() + assert_crash_timestamp(has_files, tmp_path, event["event_id"]) assert_minidump(envelope) assert_breadcrumb(envelope) diff --git a/tests/unit/test_basic.c b/tests/unit/test_basic.c index b8915d1af..480688640 100644 --- a/tests/unit/test_basic.c +++ b/tests/unit/test_basic.c @@ -174,9 +174,9 @@ SENTRY_TEST(crash_marker) // We can also verify this with has_crash_marker TEST_CHECK(!sentry__has_crash_marker(options)); - TEST_CHECK(sentry__write_crash_marker(options)); + TEST_CHECK(sentry__write_crash_marker(options, NULL)); TEST_CHECK(sentry__has_crash_marker(options)); - TEST_CHECK(sentry__write_crash_marker(options)); + TEST_CHECK(sentry__write_crash_marker(options, NULL)); TEST_CHECK(sentry__has_crash_marker(options)); TEST_CHECK(sentry__clear_crash_marker(options)); @@ -193,6 +193,11 @@ SENTRY_TEST(crashed_last_run) { // fails before init() is called TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 1); + sentry_last_crash_t last_crash = { 0 }; + TEST_CHECK_INT_EQUAL( + sentry_get_last_crash(&last_crash, sizeof(last_crash)), -1); + TEST_CHECK_INT_EQUAL(last_crash.timestamp, 0); + TEST_CHECK(sentry_uuid_is_nil(&last_crash.event_id)); // clear any leftover from previous test runs { @@ -214,18 +219,28 @@ SENTRY_TEST(crashed_last_run) sentry_close(); TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 0); + last_crash = (sentry_last_crash_t) { 0 }; + TEST_CHECK_INT_EQUAL( + sentry_get_last_crash(&last_crash, sizeof(last_crash)), 0); + TEST_CHECK_INT_EQUAL(last_crash.timestamp, 0); + TEST_CHECK(sentry_uuid_is_nil(&last_crash.event_id)); } { SENTRY_TEST_OPTIONS_NEW(options); sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); - // simulate a crash - TEST_CHECK(sentry__write_crash_marker(options)); + // simulate a crash with an old timestamp-only marker + TEST_CHECK(sentry__write_crash_marker(options, NULL)); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); + last_crash = (sentry_last_crash_t) { 0 }; + TEST_CHECK_INT_EQUAL( + sentry_get_last_crash(&last_crash, sizeof(last_crash)), 1); + TEST_CHECK(last_crash.timestamp > 0); + TEST_CHECK(sentry_uuid_is_nil(&last_crash.event_id)); // clear the status and re-init TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0); @@ -236,6 +251,39 @@ SENTRY_TEST(crashed_last_run) TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); } + { + sentry_uuid_t event_id + = sentry_uuid_from_string("4c035723-8638-4c3a-923f-2ab9d08b4018"); + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); + + // simulate a crash with a marker containing the event ID + TEST_CHECK(sentry__write_crash_marker(options, &event_id)); + + TEST_CHECK_INT_EQUAL(sentry_init(options), 0); + + TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); + TEST_CHECK_INT_EQUAL(sentry_get_last_crash(NULL, 0), 1); + last_crash = (sentry_last_crash_t) { 0 }; + TEST_CHECK_INT_EQUAL( + sentry_get_last_crash(&last_crash, sizeof(last_crash)), 1); + TEST_CHECK(last_crash.timestamp > 0); + char last_crash_event_id_str[37]; + sentry_uuid_as_string(&last_crash.event_id, last_crash_event_id_str); + TEST_CHECK_STRING_EQUAL( + last_crash_event_id_str, "4c035723-8638-4c3a-923f-2ab9d08b4018"); + + last_crash = (sentry_last_crash_t) { 0 }; + TEST_CHECK_INT_EQUAL( + sentry_get_last_crash(&last_crash, sizeof(last_crash.timestamp)), + 1); + TEST_CHECK(last_crash.timestamp > 0); + TEST_CHECK(sentry_uuid_is_nil(&last_crash.event_id)); + + TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0); + sentry_close(); + } + { SENTRY_TEST_OPTIONS_NEW(options); sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); @@ -243,6 +291,11 @@ SENTRY_TEST(crashed_last_run) sentry_close(); TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 0); + last_crash = (sentry_last_crash_t) { 0 }; + TEST_CHECK_INT_EQUAL( + sentry_get_last_crash(&last_crash, sizeof(last_crash)), 0); + TEST_CHECK_INT_EQUAL(last_crash.timestamp, 0); + TEST_CHECK(sentry_uuid_is_nil(&last_crash.event_id)); } } diff --git a/tests/unit/test_utils.c b/tests/unit/test_utils.c index c8f736a54..e98b3f818 100644 --- a/tests/unit/test_utils.c +++ b/tests/unit/test_utils.c @@ -21,9 +21,9 @@ SENTRY_TEST(iso_time) uint64_t usec; char *str; - usec = sentry__iso8601_to_usec("1970-01-01T00:00:10Z"); + usec = sentry__iso8601_to_usec("1970-01-01T00:00:10Z", 0); TEST_CHECK_INT_EQUAL(usec, 10 * 1000000); - usec = sentry__iso8601_to_usec("2020-04-27T11:02:36.050505Z"); + usec = sentry__iso8601_to_usec("2020-04-27T11:02:36.050505Z", 0); TEST_CHECK_INT_EQUAL(usec, 1587985356050505); str = sentry__usec_time_to_iso8601(usec); TEST_ASSERT(!!str); @@ -33,7 +33,7 @@ SENTRY_TEST(iso_time) usec = sentry__usec_time(); str = sentry__usec_time_to_iso8601(usec); TEST_ASSERT(!!str); - uint64_t roundtrip = sentry__iso8601_to_usec(str); + uint64_t roundtrip = sentry__iso8601_to_usec(str, 0); sentry_free(str); TEST_CHECK_INT_EQUAL(roundtrip, usec); }