Skip to content

Commit d43d51b

Browse files
authored
fix: Breadcrumb issues in Apple native bridge (#2327)
1 parent c274997 commit d43d51b

File tree

4 files changed

+182
-138
lines changed

4 files changed

+182
-138
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Fixes
1010

11+
- Fixed crashes when adding breadcrumbs on iOS/macOS. This was caused by invalid date parsing and corrupted string data in the native bridge responsible for scope sync ([#2327](https://github.com/getsentry/sentry-unity/pull/2327))
12+
- Fixed input handling in samples to work with old and new input system ([#2319](https://github.com/getsentry/sentry-unity/pull/2319))
1113
- The SDK now captures exceptions on WebGL through the logging integration instead of the incompatible log handler, providing better stack trace support . ([#2322](https://github.com/getsentry/sentry-unity/pull/2322))
1214
- Fixed input handling in samples to work with old and new input system. ([#2319](https://github.com/getsentry/sentry-unity/pull/2319))
1315

package-dev/Plugins/iOS/SentryNativeBridge.m

Lines changed: 71 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,39 @@
66

77
NS_ASSUME_NONNULL_BEGIN
88

9+
static NSDateFormatter *_Nullable sentry_cachedISO8601Formatter(void) {
10+
static NSDateFormatter *formatter = nil;
11+
static dispatch_once_t onceToken;
12+
dispatch_once(&onceToken, ^{
13+
formatter = [[NSDateFormatter alloc] init];
14+
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
15+
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
16+
formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
17+
});
18+
return formatter;
19+
}
20+
21+
static inline NSString *_NSStringOrNil(const char *value)
22+
{
23+
return value ? [NSString stringWithUTF8String:value] : nil;
24+
}
25+
26+
static inline NSNumber *_NSNumberOrNil(int32_t value)
27+
{
28+
return value == 0 ? nil : @(value);
29+
}
30+
31+
static inline NSNumber *_NSBoolOrNil(int8_t value)
32+
{
33+
if (value == 0) {
34+
return @NO;
35+
}
36+
if (value == 1) {
37+
return @YES;
38+
}
39+
return nil;
40+
}
41+
942
// macOS only
1043
// On iOS, the SDK is linked statically so we don't need to dlopen() it.
1144
int SentryNativeBridgeLoadLibrary() { return 1; }
@@ -64,24 +97,26 @@ void SentryNativeBridgeAddBreadcrumb(
6497
return;
6598
}
6699

100+
NSString *timestampString = _NSStringOrNil(timestamp);
101+
NSString *messageString = _NSStringOrNil(message);
102+
NSString *typeString = _NSStringOrNil(type);
103+
NSString *categoryString = _NSStringOrNil(category) ?: @"default"; // Category cannot be nil
104+
67105
[SentrySDK configureScope:^(SentryScope *scope) {
68106
SentryBreadcrumb *breadcrumb = [[SentryBreadcrumb alloc]
69107
initWithLevel:level
70-
category:(category ? [NSString stringWithUTF8String:category] : nil)];
108+
category:categoryString];
71109

72-
if (timestamp != NULL) {
73-
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
74-
[dateFormatter setDateFormat:NSCalendarIdentifierISO8601];
75-
breadcrumb.timestamp =
76-
[dateFormatter dateFromString:[NSString stringWithUTF8String:timestamp]];
110+
if (timestampString != nil && timestampString.length > 0) {
111+
breadcrumb.timestamp = [sentry_cachedISO8601Formatter() dateFromString:timestampString];
77112
}
78113

79-
if (message != NULL) {
80-
breadcrumb.message = [NSString stringWithUTF8String:message];
114+
if (messageString != nil) {
115+
breadcrumb.message = messageString;
81116
}
82117

83-
if (type != NULL) {
84-
breadcrumb.type = [NSString stringWithUTF8String:type];
118+
if (typeString != nil) {
119+
breadcrumb.type = typeString;
85120
}
86121

87122
[scope addBreadcrumb:breadcrumb];
@@ -94,13 +129,11 @@ void SentryNativeBridgeSetExtra(const char *key, const char *value)
94129
return;
95130
}
96131

132+
NSString *keyString = [NSString stringWithUTF8String:key];
133+
NSString *valueString = _NSStringOrNil(value);
134+
97135
[SentrySDK configureScope:^(SentryScope *scope) {
98-
if (value != NULL) {
99-
[scope setExtraValue:[NSString stringWithUTF8String:value]
100-
forKey:[NSString stringWithUTF8String:key]];
101-
} else {
102-
[scope removeExtraForKey:[NSString stringWithUTF8String:key]];
103-
}
136+
[scope setExtraValue:valueString forKey:keyString];
104137
}];
105138
}
106139

@@ -110,13 +143,11 @@ void SentryNativeBridgeSetTag(const char *key, const char *value)
110143
return;
111144
}
112145

146+
NSString *keyString = [NSString stringWithUTF8String:key];
147+
NSString *valueString = _NSStringOrNil(value);
148+
113149
[SentrySDK configureScope:^(SentryScope *scope) {
114-
if (value != NULL) {
115-
[scope setTagValue:[NSString stringWithUTF8String:value]
116-
forKey:[NSString stringWithUTF8String:key]];
117-
} else {
118-
[scope removeTagForKey:[NSString stringWithUTF8String:key]];
119-
}
150+
[scope setTagValue:valueString forKey:keyString];
120151
}];
121152
}
122153

@@ -126,35 +157,28 @@ void SentryNativeBridgeUnsetTag(const char *key)
126157
return;
127158
}
128159

129-
[SentrySDK configureScope:^(
130-
SentryScope *scope) { [scope removeTagForKey:[NSString stringWithUTF8String:key]]; }];
160+
NSString *keyString = [NSString stringWithUTF8String:key];
161+
162+
[SentrySDK configureScope:^(SentryScope *scope) {
163+
[scope removeTagForKey:keyString];
164+
}];
131165
}
132166

133167
void SentryNativeBridgeSetUser(
134168
const char *email, const char *userId, const char *ipAddress, const char *username)
135169
{
136-
if (email == NULL && userId == NULL && ipAddress == NULL && username == NULL) {
137-
return;
138-
}
139-
170+
NSString *emailString = _NSStringOrNil(email);
171+
NSString *userIdString = _NSStringOrNil(userId);
172+
NSString *ipAddressString = _NSStringOrNil(ipAddress);
173+
NSString *usernameString = _NSStringOrNil(username);
174+
140175
[SentrySDK configureScope:^(SentryScope *scope) {
141176
SentryUser *user = [[SentryUser alloc] init];
142177

143-
if (email != NULL) {
144-
user.email = [NSString stringWithUTF8String:email];
145-
}
146-
147-
if (userId != NULL) {
148-
user.userId = [NSString stringWithUTF8String:userId];
149-
}
150-
151-
if (ipAddress != NULL) {
152-
user.ipAddress = [NSString stringWithUTF8String:ipAddress];
153-
}
154-
155-
if (username != NULL) {
156-
user.username = [NSString stringWithUTF8String:username];
157-
}
178+
user.email = emailString;
179+
user.userId = userIdString;
180+
user.ipAddress = ipAddressString;
181+
user.username = usernameString;
158182

159183
[scope setUser:user];
160184
}];
@@ -184,42 +208,21 @@ void SentryNativeBridgeSetTrace(const char *traceId, const char *spanId)
184208

185209
NSString *traceIdStr = [NSString stringWithUTF8String:traceId];
186210
NSString *spanIdStr = [NSString stringWithUTF8String:spanId];
187-
211+
188212
// This is a workaround to deal with SentryId living inside the Swift header
189213
Class sentryIdClass = NSClassFromString(@"_TtC6Sentry8SentryId");
190214
Class sentrySpanIdClass = NSClassFromString(@"SentrySpanId");
191-
215+
192216
if (sentryIdClass && sentrySpanIdClass) {
193217
id sentryTraceId = [[sentryIdClass alloc] initWithUUIDString:traceIdStr];
194218
id sentrySpanId = [[sentrySpanIdClass alloc] initWithValue:spanIdStr];
195-
219+
196220
if (sentryTraceId && sentrySpanId) {
197221
[PrivateSentrySDKOnly setTrace:sentryTraceId spanId:sentrySpanId];
198222
}
199223
}
200224
}
201225

202-
static inline NSString *_NSStringOrNil(const char *value)
203-
{
204-
return value ? [NSString stringWithUTF8String:value] : nil;
205-
}
206-
207-
static inline NSNumber *_NSNumberOrNil(int32_t value)
208-
{
209-
return value == 0 ? nil : @(value);
210-
}
211-
212-
static inline NSNumber *_NSBoolOrNil(int8_t value)
213-
{
214-
if (value == 0) {
215-
return @NO;
216-
}
217-
if (value == 1) {
218-
return @YES;
219-
}
220-
return nil;
221-
}
222-
223226
void SentryNativeBridgeWriteScope( // clang-format off
224227
// // const char *AppStartTime,
225228
// const char *AppBuildType,
@@ -288,4 +291,4 @@ void SentryNativeBridgeWriteScope( // clang-format off
288291
}];
289292
}
290293

291-
NS_ASSUME_NONNULL_END
294+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)