Repository: getsentry/sentry-cocoa
Pull request #5064: fix: Crash in setMeasurement when name is nil
Author: login: philipphofmann
Created: 2025-04-08T09:18:57Z | Merged: 2025-04-10T08:55:06Z



## :scroll: Description

Although the name for setMeasurement is nonnull, we saw occurrences when it was nil, which led to crashes. Now, when the name is nil, the SDK discards the measurement and logs an error.

## :bulb: Motivation and Context

A customer reported these crashes.

## :green_heart: How did you test it?
Unit tests

## :pencil: Checklist

You have to check all boxes before merging:

- [x] I added tests to verify the changes.
- [x] No new PII added or SDK only sends newly added PII if `sendDefaultPII` is enabled.
- [x] I updated the docs if needed.
- [x] I updated the wizard if needed.
- [x] Review from the native team if needed.
- [x] No breaking change or entry added to the changelog.
- [x] No breaking change for hybrid SDKs or communicated to hybrid SDKs.



Diff:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 46c71cb3663..ffa8ac6991e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+## Unreleased
+
+### Fixes
+
+- Crash in setMeasurement when name is nil (#5064)
+- Make setMeasurement thread safe (#5067)
+
 ## 8.49.0
 
 ### Features
diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj
index 7b787fedbfb..ef42675d0e1 100644
--- a/Sentry.xcodeproj/project.pbxproj
+++ b/Sentry.xcodeproj/project.pbxproj
@@ -93,6 +93,7 @@
 		621F61F12BEA073A005E654F /* SentryEnabledFeaturesBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621F61F02BEA073A005E654F /* SentryEnabledFeaturesBuilder.swift */; };
 		62212B872D520CB00062C2FA /* SentryEventCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62212B862D520CB00062C2FA /* SentryEventCodable.swift */; };
 		6221BBCA2CAA932100C627CA /* SentryANRType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6221BBC92CAA932100C627CA /* SentryANRType.swift */; };
+		62277BBC2DA5183500EF06B7 /* SentryTracer+Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 62277BBB2DA5183500EF06B7 /* SentryTracer+Test.m */; };
 		622C08DB29E554B9002571D4 /* SentrySpanContext+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 622C08D929E554B9002571D4 /* SentrySpanContext+Private.h */; };
 		62375FB92B47F9F000CC55F1 /* SentryDependencyContainerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62375FB82B47F9F000CC55F1 /* SentryDependencyContainerTests.swift */; };
 		623C45B02A651D8200D9E88B /* SentryCoreDataTracker+Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 623C45AF2A651D8200D9E88B /* SentryCoreDataTracker+Test.m */; };
@@ -1172,6 +1173,7 @@
 		621F61F02BEA073A005E654F /* SentryEnabledFeaturesBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryEnabledFeaturesBuilder.swift; sourceTree = "<group>"; };
 		62212B862D520CB00062C2FA /* SentryEventCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryEventCodable.swift; sourceTree = "<group>"; };
 		6221BBC92CAA932100C627CA /* SentryANRType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryANRType.swift; sourceTree = "<group>"; };
+		62277BBB2DA5183500EF06B7 /* SentryTracer+Test.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SentryTracer+Test.m"; sourceTree = "<group>"; };
 		622C08D929E554B9002571D4 /* SentrySpanContext+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentrySpanContext+Private.h"; path = "include/SentrySpanContext+Private.h"; sourceTree = "<group>"; };
 		62375FB82B47F9F000CC55F1 /* SentryDependencyContainerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryDependencyContainerTests.swift; sourceTree = "<group>"; };
 		623C45AE2A651C4500D9E88B /* SentryCoreDataTracker+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryCoreDataTracker+Test.h"; sourceTree = "<group>"; };
@@ -3170,6 +3172,7 @@
 				8E70B0FC25CB72BE002B3155 /* SentrySpanTests.swift */,
 				D88817DB26D72B7B00BF2251 /* SentryTraceContextTests.swift */,
 				7BBEB16026AEE5EF00C06C03 /* SentryTracer+Test.h */,
+				62277BBB2DA5183500EF06B7 /* SentryTracer+Test.m */,
 				8EAC7FF7265C8910005B44E5 /* SentryTracerTests.swift */,
 				62950F0F29E7FE0100A42624 /* SentryTransactionContextTests.swift */,
 				7B6C5ED5264E62CA0010D138 /* SentryTransactionTests.swift */,
@@ -5373,6 +5376,7 @@
 				7B72D23A28D074BC0014798A /* TestExtensions.swift in Sources */,
 				7BBD18BB24530D2600427C76 /* SentryFileManagerTests.swift in Sources */,
 				63FE722020DA66EC00CDBAE8 /* SentryCrashObjC_Tests.m in Sources */,
+				62277BBC2DA5183500EF06B7 /* SentryTracer+Test.m in Sources */,
 				7B58816727FC5D790098B121 /* SentryDiscardReasonMapperTests.swift in Sources */,
 				63FE720320DA66EC00CDBAE8 /* SentryCrashCPU_Tests.m in Sources */,
 				63FE721020DA66EC00CDBAE8 /* SentryCrashCachedData_Tests.m in Sources */,
diff --git a/Sources/Sentry/SentryTracer.m b/Sources/Sentry/SentryTracer.m
index 8494513fb0a..594ad764e81 100644
--- a/Sources/Sentry/SentryTracer.m
+++ b/Sources/Sentry/SentryTracer.m
@@ -438,14 +438,30 @@ - (nullable SentryTraceContext *)traceContext
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value
 {
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value];
-    _measurements[name] = measurement;
+
+    [self setMeasurement:name measurement:measurement];
 }
 
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value unit:(SentryMeasurementUnit *)unit
 {
+
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value
                                                                                    unit:unit];
-    _measurements[name] = measurement;
+    [self setMeasurement:name measurement:measurement];
+}
+
+- (void)setMeasurement:(NSString *)name measurement:(SentryMeasurementValue *)measurement
+{
+    // Although name is nonnull we saw edge cases where it was nil and then leading to crashes. If
+    // the name is nil we can discard the measurement
+    if (name == nil) {
+        SENTRY_LOG_ERROR(@"The name of the measurement is nil. Discarding the measurement.");
+        return;
+    }
+
+    @synchronized(_measurements) {
+        _measurements[name] = measurement;
+    }
 }
 
 - (void)finish
diff --git a/Tests/SentryTests/Transaction/SentryTracer+Test.h b/Tests/SentryTests/Transaction/SentryTracer+Test.h
index 80b4902939b..ac810b22ad8 100644
--- a/Tests/SentryTests/Transaction/SentryTracer+Test.h
+++ b/Tests/SentryTests/Transaction/SentryTracer+Test.h
@@ -10,4 +10,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 @end
 
+void testing_setMeasurementWithNilName(SentryTracer *tracer, NSNumber *value);
+
+void testing_setMeasurementWithNilNameAndUnit(
+    SentryTracer *tracer, NSNumber *value, SentryMeasurementUnit *unit);
+
 NS_ASSUME_NONNULL_END
diff --git a/Tests/SentryTests/Transaction/SentryTracer+Test.m b/Tests/SentryTests/Transaction/SentryTracer+Test.m
new file mode 100644
index 00000000000..47c76404b9e
--- /dev/null
+++ b/Tests/SentryTests/Transaction/SentryTracer+Test.m
@@ -0,0 +1,22 @@
+#import "SentryTracer+Test.h"
+#import <Foundation/Foundation.h>
+
+void
+testing_setMeasurementWithNilName(SentryTracer *tracer, NSNumber *value)
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+    [tracer setMeasurement:nil value:value];
+#pragma clang diagnostic pop
+}
+
+void
+testing_setMeasurementWithNilNameAndUnit(
+    SentryTracer *tracer, NSNumber *value, SentryMeasurementUnit *unit)
+{
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+    [tracer setMeasurement:nil value:value unit:unit];
+#pragma clang diagnostic pop
+}
diff --git a/Tests/SentryTests/Transaction/SentryTracerTests.swift b/Tests/SentryTests/Transaction/SentryTracerTests.swift
index 538f24c50c6..64b94d05f55 100644
--- a/Tests/SentryTests/Transaction/SentryTracerTests.swift
+++ b/Tests/SentryTests/Transaction/SentryTracerTests.swift
@@ -988,6 +988,64 @@ class SentryTracerTests: XCTestCase {
         XCTAssertEqual(unit.unit, try XCTUnwrap(measurement["unit"] as? String))
     }
 
+    func testMeasurement_NameIsNil_MeasurementsGetsDiscarded() throws {
+        // Arrange
+        let sut = fixture.getSut()
+
+        // Act
+        testing_setMeasurementWithNilName(sut, 0.0)
+        testing_setMeasurementWithNilNameAndUnit(sut, 0.0, MeasurementUnitFraction.percent)
+
+        // Assert
+        sut.finish()
+
+        XCTAssertEqual(1, fixture.hub.capturedEventsWithScopes.count)
+        let serializedTransaction = fixture.hub.capturedEventsWithScopes.first?.event.serialize()
+
+        XCTAssertNil(serializedTransaction?["measurements"])
+    }
+
+    func testMeasurements_WriteFromDifferentThreads_SetsAllMeasurements() throws {
+        // Arrange
+        let iterations = 100
+        let unit = MeasurementUnitFraction.percent
+
+        let sut = fixture.getSut()
+        let childSpan = sut.startChild(operation: "operation")
+
+        let dispatchQueue = DispatchQueue(label: "testQueue", attributes: .concurrent)
+        let expectation = XCTestExpectation(description: "Set measurements")
+        expectation.expectedFulfillmentCount = iterations
+
+        // Act
+        for i in 0..<iterations {
+            dispatchQueue.async {
+                sut.setMeasurement(name: "transaction \(i)", value: 12.0, unit: unit)
+                childSpan.setMeasurement(name: "span \(i)", value: 10.0, unit: unit)
+                expectation.fulfill()
+            }
+        }
+
+        wait(for: [expectation], timeout: 5.0)
+
+        // Assert
+        childSpan.finish()
+        sut.finish()
+        XCTAssertEqual(1, fixture.hub.capturedEventsWithScopes.count)
+        let serializedTransaction = fixture.hub.capturedEventsWithScopes.first?.event.serialize()
+
+        let measurements = try XCTUnwrap(serializedTransaction?["measurements"] as? [String: [String: Any]])
+        XCTAssertEqual(measurements.count, iterations * 2)
+
+        for i in 0..<iterations {
+            let transactionMeasurement = try XCTUnwrap(measurements["transaction \(i)"])
+            XCTAssertEqual(try XCTUnwrap(transactionMeasurement["value"] as? NSNumber), 12.0)
+
+            let spanMeasurement = try XCTUnwrap(measurements["span \(i)"])
+            XCTAssertEqual(try XCTUnwrap(spanMeasurement["value"] as? NSNumber), 10.0)
+        }
+    }
+
     func testFinish_WithUnfinishedChildren() {
         let sut = fixture.getSut(waitForChildren: false)
         let child1 = sut.startChild(operation: fixture.transactionOperation)


Reviews:
user: login: philprime
body: LGTM, left some comments
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-08T09:27:49Z
user: login: philipphofmann
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T09:44:35Z
user: login: philipphofmann
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T11:52:47Z
user: login: philipphofmann
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T11:55:15Z
user: login: philprime
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T13:20:42Z
user: login: philipphofmann
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T07:45:26Z

Review comments:
diff_hunk: @@ -423,13 +423,27 @@ - (nullable SentryTraceContext *)traceContext
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value
 {
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value];
-    _measurements[name] = measurement;
+
+    [self setMeasurement:name measurement:measurement];
 }
 
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value unit:(SentryMeasurementUnit *)unit
 {
+
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value
                                                                                    unit:unit];
+    [self setMeasurement:name measurement:measurement];
+}
+
+- (void)setMeasurement:(NSString *)name measurement:(SentryMeasurementValue *)measurement
+{
+    // Although name is nonnull we saw edge cases where it was nil and then leading to crashes. If
+    // the name is nil we can discard the measurement
+    if (name == nil) {
path: Sources/Sentry/SentryTracer.m
user: login: philprime
body: `l`: Does this also include `NULL`, `[NSNull null]`? Does it make sense to change the `setMeasurement` signature to use `_Nonnull` for the parameters?
created_at: 2025-04-08T09:26:58Z
author_association: MEMBER
diff_hunk: @@ -10,4 +10,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 @end
 
+void testing_setMeasurementWithNilName(SentryTracer *tracer, NSNumber *value);
path: Tests/SentryTests/Transaction/SentryTracer+Test.h
user: login: philprime
body: `l`: Should we mark this explicitly as `_Nullable`?
created_at: 2025-04-08T09:27:22Z
author_association: MEMBER
diff_hunk: @@ -423,13 +423,27 @@ - (nullable SentryTraceContext *)traceContext
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value
 {
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value];
-    _measurements[name] = measurement;
+
+    [self setMeasurement:name measurement:measurement];
 }
 
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value unit:(SentryMeasurementUnit *)unit
 {
+
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value
                                                                                    unit:unit];
+    [self setMeasurement:name measurement:measurement];
+}
+
+- (void)setMeasurement:(NSString *)name measurement:(SentryMeasurementValue *)measurement
+{
+    // Although name is nonnull we saw edge cases where it was nil and then leading to crashes. If
+    // the name is nil we can discard the measurement
+    if (name == nil) {
path: Sources/Sentry/SentryTracer.m
user: login: philipphofmann
body: We already use _Nonnull, but somehow we still sometimes get `nil` here. It could be related to Kotlin Multiplatform.
created_at: 2025-04-08T09:44:35Z
author_association: MEMBER
diff_hunk: @@ -10,4 +10,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 @end
 
+void testing_setMeasurementWithNilName(SentryTracer *tracer, NSNumber *value);
path: Tests/SentryTests/Transaction/SentryTracer+Test.h
user: login: philipphofmann
body: The tracer and value must not be nil. The implementation passes `nil` to the setMeasurement. So not it doesn't make sense.
created_at: 2025-04-08T11:52:47Z
author_association: MEMBER
diff_hunk: @@ -423,13 +423,27 @@ - (nullable SentryTraceContext *)traceContext
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value
 {
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value];
-    _measurements[name] = measurement;
+
+    [self setMeasurement:name measurement:measurement];
 }
 
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value unit:(SentryMeasurementUnit *)unit
 {
+
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value
                                                                                    unit:unit];
+    [self setMeasurement:name measurement:measurement];
+}
+
+- (void)setMeasurement:(NSString *)name measurement:(SentryMeasurementValue *)measurement
+{
+    // Although name is nonnull we saw edge cases where it was nil and then leading to crashes. If
+    // the name is nil we can discard the measurement
+    if (name == nil) {
path: Sources/Sentry/SentryTracer.m
user: login: philipphofmann
body: Why do you think we should also include `NULL` and `NSNull null` here? We're not dealing with dictionaries here.
created_at: 2025-04-08T11:55:15Z
author_association: MEMBER
diff_hunk: @@ -423,13 +423,27 @@ - (nullable SentryTraceContext *)traceContext
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value
 {
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value];
-    _measurements[name] = measurement;
+
+    [self setMeasurement:name measurement:measurement];
 }
 
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value unit:(SentryMeasurementUnit *)unit
 {
+
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value
                                                                                    unit:unit];
+    [self setMeasurement:name measurement:measurement];
+}
+
+- (void)setMeasurement:(NSString *)name measurement:(SentryMeasurementValue *)measurement
+{
+    // Although name is nonnull we saw edge cases where it was nil and then leading to crashes. If
+    // the name is nil we can discard the measurement
+    if (name == nil) {
path: Sources/Sentry/SentryTracer.m
user: login: philprime
body: No direct reason, just double-checking after implementing #4760. If you say it is fine, I agree with you.
created_at: 2025-04-08T13:20:41Z
author_association: MEMBER
diff_hunk: @@ -423,13 +423,27 @@ - (nullable SentryTraceContext *)traceContext
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value
 {
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value];
-    _measurements[name] = measurement;
+
+    [self setMeasurement:name measurement:measurement];
 }
 
 - (void)setMeasurement:(NSString *)name value:(NSNumber *)value unit:(SentryMeasurementUnit *)unit
 {
+
     SentryMeasurementValue *measurement = [[SentryMeasurementValue alloc] initWithValue:value
                                                                                    unit:unit];
+    [self setMeasurement:name measurement:measurement];
+}
+
+- (void)setMeasurement:(NSString *)name measurement:(SentryMeasurementValue *)measurement
+{
+    // Although name is nonnull we saw edge cases where it was nil and then leading to crashes. If
+    // the name is nil we can discard the measurement
+    if (name == nil) {
path: Sources/Sentry/SentryTracer.m
user: login: philipphofmann
body: I think it's fine.
created_at: 2025-04-10T07:45:26Z
author_association: MEMBER

PR comments:
user: login: codecov[bot]
created_at: 2025-04-08T09:26:39Z
body: ## [Codecov](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 92.729%. Comparing base [(`9c3c8d5`)](https://app.codecov.io/gh/getsentry/sentry-cocoa/commit/9c3c8d5cf1955fabae1d5c3dd3a6810dc69169ca?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) to head [(`797eb72`)](https://app.codecov.io/gh/getsentry/sentry-cocoa/commit/797eb72125a0785d48fad2555376ff2d867f6383?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).
> Report is 2 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064/graphs/tree.svg?width=650&height=150&src=pr&token=PTZKtOJlrs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)

```diff
@@              Coverage Diff              @@
##              main     #5064       +/-   ##
=============================================
- Coverage   92.731%   92.729%   -0.002%     
=============================================
  Files          674       675        +1     
  Lines        83552     83629       +77     
  Branches     30451     30480       +29     
=============================================
+ Hits         77479     77549       +70     
- Misses        5976      5980        +4     
- Partials        97       100        +3     
```

| [Files with missing lines](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) | Coverage Δ | |
|---|---|---|
| [Sources/Sentry/SentryTracer.m](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?src=pr&el=tree&filepath=Sources%2FSentry%2FSentryTracer.m&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry#diff-U291cmNlcy9TZW50cnkvU2VudHJ5VHJhY2VyLm0=) | `97.631% <100.000%> (+0.036%)` | :arrow_up: |
| [Tests/SentryTests/Transaction/SentryTracer+Test.m](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?src=pr&el=tree&filepath=Tests%2FSentryTests%2FTransaction%2FSentryTracer%2BTest.m&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry#diff-VGVzdHMvU2VudHJ5VGVzdHMvVHJhbnNhY3Rpb24vU2VudHJ5VHJhY2VyK1Rlc3QubQ==) | `100.000% <100.000%> (ø)` | |
| [...ts/SentryTests/Transaction/SentryTracerTests.swift](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?src=pr&el=tree&filepath=Tests%2FSentryTests%2FTransaction%2FSentryTracerTests.swift&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry#diff-VGVzdHMvU2VudHJ5VGVzdHMvVHJhbnNhY3Rpb24vU2VudHJ5VHJhY2VyVGVzdHMuc3dpZnQ=) | `99.418% <100.000%> (+0.024%)` | :arrow_up: |

... and [11 files with indirect coverage changes](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)

------

[Continue to review full report in Codecov by Sentry](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?dropdown=coverage&src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry). Last update [9c3c8d5...797eb72](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5064?dropdown=coverage&src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-08T09:30:46Z
body: ##  Performance metrics :rocket:
<table>
  <tr>
    <th>&nbsp;</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr>
  <tr>
    <th align="left">Startup time</th>
    <td align="right">1223.76 ms</td>
    <td align="right">1254.88 ms</td>
    <td align="right"><strong>31.12 ms</strong></td>
  </tr>
  <tr>
    <th align="left">Size</th>
    <td align="right">22.30 KiB</td>
    <td align="right">846.07 KiB</td>
    <td align="right"><strong>823.77 KiB</strong></td>
  </tr>
</table>
<details><summary><h3>Baseline results on branch: main</h3></summary>
<h3>Startup times</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">6164c6781644b530f72cc345f535902517303aab</th>
  <td align="right">1219.02 ms</td>
  <td align="right">1231.38 ms</td>
  <td align="right"><strong>12.35 ms</strong></td>
</tr><tr>
  <th align="left">596ccc1396714bd5d6daa893912a008d94ba8c10</th>
  <td align="right">1230.85 ms</td>
  <td align="right">1244.24 ms</td>
  <td align="right"><strong>13.39 ms</strong></td>
</tr><tr>
  <th align="left">253bb7145527585db28fe308f7eeeef63cd1266a</th>
  <td align="right">1221.62 ms</td>
  <td align="right">1250.82 ms</td>
  <td align="right"><strong>29.20 ms</strong></td>
</tr><tr>
  <th align="left">c59914b8a097f1bb71151cff9854ddd872103f92</th>
  <td align="right">1342.08 ms</td>
  <td align="right">1375.73 ms</td>
  <td align="right"><strong>33.65 ms</strong></td>
</tr><tr>
  <th align="left">ebfe678c1e43cd6773a44627555093de022f5dcf</th>
  <td align="right">1234.63 ms</td>
  <td align="right">1254.52 ms</td>
  <td align="right"><strong>19.89 ms</strong></td>
</tr><tr>
  <th align="left">9ce54cc68e9c50efb28daa179a606fb5efc59a8d</th>
  <td align="right">1230.31 ms</td>
  <td align="right">1237.20 ms</td>
  <td align="right"><strong>6.90 ms</strong></td>
</tr><tr>
  <th align="left">0a12181c582c75899c1209660f87ec3bb2a70717</th>
  <td align="right">1231.37 ms</td>
  <td align="right">1248.13 ms</td>
  <td align="right"><strong>16.75 ms</strong></td>
</tr><tr>
  <th align="left">7bbb7c3a08a5cf332c7c289296813ee5c0dd58cc</th>
  <td align="right">1232.40 ms</td>
  <td align="right">1249.78 ms</td>
  <td align="right"><strong>17.38 ms</strong></td>
</tr><tr>
  <th align="left">3cba0e88ef7bf5987091e4162dd409ba6e31634f</th>
  <td align="right">1243.04 ms</td>
  <td align="right">1257.46 ms</td>
  <td align="right"><strong>14.42 ms</strong></td>
</tr><tr>
  <th align="left">c0ea6a1a047f4851e656ad7f3df6c8b6fc106858</th>
  <td align="right">1236.42 ms</td>
  <td align="right">1250.94 ms</td>
  <td align="right"><strong>14.52 ms</strong></td>
</tr></table>
<h3>App size</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">6164c6781644b530f72cc345f535902517303aab</th>
  <td align="right">21.58 KiB</td>
  <td align="right">681.72 KiB</td>
  <td align="right"><strong>660.14 KiB</strong></td>
</tr><tr>
  <th align="left">596ccc1396714bd5d6daa893912a008d94ba8c10</th>
  <td align="right">22.84 KiB</td>
  <td align="right">401.44 KiB</td>
  <td align="right"><strong>378.60 KiB</strong></td>
</tr><tr>
  <th align="left">253bb7145527585db28fe308f7eeeef63cd1266a</th>
  <td align="right">20.76 KiB</td>
  <td align="right">393.37 KiB</td>
  <td align="right"><strong>372.60 KiB</strong></td>
</tr><tr>
  <th align="left">c59914b8a097f1bb71151cff9854ddd872103f92</th>
  <td align="right">21.58 KiB</td>
  <td align="right">671.90 KiB</td>
  <td align="right"><strong>650.32 KiB</strong></td>
</tr><tr>
  <th align="left">ebfe678c1e43cd6773a44627555093de022f5dcf</th>
  <td align="right">22.31 KiB</td>
  <td align="right">775.27 KiB</td>
  <td align="right"><strong>752.95 KiB</strong></td>
</tr><tr>
  <th align="left">9ce54cc68e9c50efb28daa179a606fb5efc59a8d</th>
  <td align="right">21.58 KiB</td>
  <td align="right">573.71 KiB</td>
  <td align="right"><strong>552.13 KiB</strong></td>
</tr><tr>
  <th align="left">0a12181c582c75899c1209660f87ec3bb2a70717</th>
  <td align="right">21.58 KiB</td>
  <td align="right">419.20 KiB</td>
  <td align="right"><strong>397.61 KiB</strong></td>
</tr><tr>
  <th align="left">7bbb7c3a08a5cf332c7c289296813ee5c0dd58cc</th>
  <td align="right">21.58 KiB</td>
  <td align="right">418.78 KiB</td>
  <td align="right"><strong>397.20 KiB</strong></td>
</tr><tr>
  <th align="left">3cba0e88ef7bf5987091e4162dd409ba6e31634f</th>
  <td align="right">22.84 KiB</td>
  <td align="right">403.19 KiB</td>
  <td align="right"><strong>380.34 KiB</strong></td>
</tr><tr>
  <th align="left">c0ea6a1a047f4851e656ad7f3df6c8b6fc106858</th>
  <td align="right">21.58 KiB</td>
  <td align="right">671.94 KiB</td>
  <td align="right"><strong>650.35 KiB</strong></td>
</tr></table>
</details>
<details><summary><h3>Previous results on branch: fix/set-measurement-crash</h3></summary>
<h3>Startup times</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">9bc0dc18c72861ab16c27cc468ec0af63520ce30</th>
  <td align="right">1221.45 ms</td>
  <td align="right">1238.69 ms</td>
  <td align="right"><strong>17.24 ms</strong></td>
</tr><tr>
  <th align="left">097f0f67d7c0dec420ab8beffd123a4753e75e4f</th>
  <td align="right">1211.33 ms</td>
  <td align="right">1238.49 ms</td>
  <td align="right"><strong>27.16 ms</strong></td>
</tr></table>
<h3>App size</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">9bc0dc18c72861ab16c27cc468ec0af63520ce30</th>
  <td align="right">22.30 KiB</td>
  <td align="right">844.67 KiB</td>
  <td align="right"><strong>822.37 KiB</strong></td>
</tr><tr>
  <th align="left">097f0f67d7c0dec420ab8beffd123a4753e75e4f</th>
  <td align="right">22.30 KiB</td>
  <td align="right">846.07 KiB</td>
  <td align="right"><strong>823.77 KiB</strong></td>
</tr></table>
</details>

author_association: CONTRIBUTOR
user: login: philipphofmann
created_at: 2025-04-10T07:52:02Z
body: Sorry about the commit messup, I accidentially merged https://github.com/getsentry/sentry-cocoa/pull/5067 into this one before merging this PR. 
author_association: MEMBER