Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### Fixes

- 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))
- Fixed input handling in samples to work with old and new input system ([#2319](https://github.com/getsentry/sentry-unity/pull/2319))

### Dependencies
Expand Down
138 changes: 85 additions & 53 deletions package-dev/Plugins/iOS/SentryNativeBridge.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,39 @@

NS_ASSUME_NONNULL_BEGIN

static NSDateFormatter *_Nullable cachedISO8601Formatter(void) {
static NSDateFormatter *formatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
formatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
});
return formatter;
}

static inline NSString *_NSStringOrNil(const char *value)
{
return value ? [NSString stringWithUTF8String:value] : nil;
}

static inline NSNumber *_NSNumberOrNil(int32_t value)
{
return value == 0 ? nil : @(value);
}

static inline NSNumber *_NSBoolOrNil(int8_t value)
{
if (value == 0) {
return @NO;
}
if (value == 1) {
return @YES;
}
return nil;
}

// macOS only
// On iOS, the SDK is linked statically so we don't need to dlopen() it.
int SentryNativeBridgeLoadLibrary() { return 1; }
Expand Down Expand Up @@ -64,24 +97,26 @@ void SentryNativeBridgeAddBreadcrumb(
return;
}

NSString *timestampString = _NSStringOrNil(timestamp);
NSString *messageString = _NSStringOrNil(message);
NSString *typeString = _NSStringOrNil(type);
NSString *categoryString = _NSStringOrNil(category) ?: @"default"; // Category cannot be nil

[SentrySDK configureScope:^(SentryScope *scope) {
SentryBreadcrumb *breadcrumb = [[SentryBreadcrumb alloc]
initWithLevel:level
category:(category ? [NSString stringWithUTF8String:category] : nil)];
category:categoryString];

if (timestamp != NULL) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:NSCalendarIdentifierISO8601];
breadcrumb.timestamp =
[dateFormatter dateFromString:[NSString stringWithUTF8String:timestamp]];
if (timestampString != nil && timestampString.length > 0) {
breadcrumb.timestamp = [cachedISO8601Formatter() dateFromString:timestampString];
}

if (message != NULL) {
breadcrumb.message = [NSString stringWithUTF8String:message];
if (messageString != nil) {
breadcrumb.message = messageString;
}

if (type != NULL) {
breadcrumb.type = [NSString stringWithUTF8String:type];
if (typeString != nil) {
breadcrumb.type = typeString;
}

[scope addBreadcrumb:breadcrumb];
Expand All @@ -94,12 +129,17 @@ void SentryNativeBridgeSetExtra(const char *key, const char *value)
return;
}

NSString *keyString = [NSString stringWithUTF8String:key];
NSString *valueString = nil;
if (value != NULL) {
valueString = [NSString stringWithUTF8String:value];
}

[SentrySDK configureScope:^(SentryScope *scope) {
if (value != NULL) {
[scope setExtraValue:[NSString stringWithUTF8String:value]
forKey:[NSString stringWithUTF8String:key]];
if (valueString != nil) {
[scope setExtraValue:valueString forKey:keyString];
} else {
[scope removeExtraForKey:[NSString stringWithUTF8String:key]];
[scope removeExtraForKey:keyString];
}
}];
}
Expand All @@ -110,12 +150,17 @@ void SentryNativeBridgeSetTag(const char *key, const char *value)
return;
}

NSString *keyString = [NSString stringWithUTF8String:key];
NSString *valueString = nil;
if (value != NULL) {
valueString = [NSString stringWithUTF8String:value];
}

[SentrySDK configureScope:^(SentryScope *scope) {
if (value != NULL) {
[scope setTagValue:[NSString stringWithUTF8String:value]
forKey:[NSString stringWithUTF8String:key]];
if (valueString != nil) {
[scope setTagValue:valueString forKey:keyString];
} else {
[scope removeTagForKey:[NSString stringWithUTF8String:key]];
[scope removeTagForKey:keyString];
}
}];
}
Expand All @@ -126,8 +171,11 @@ void SentryNativeBridgeUnsetTag(const char *key)
return;
}

[SentrySDK configureScope:^(
SentryScope *scope) { [scope removeTagForKey:[NSString stringWithUTF8String:key]]; }];
NSString *keyString = [NSString stringWithUTF8String:key];

[SentrySDK configureScope:^(SentryScope *scope) {
[scope removeTagForKey:keyString];
}];
}

void SentryNativeBridgeSetUser(
Expand All @@ -137,23 +185,28 @@ void SentryNativeBridgeSetUser(
return;
}

NSString *emailString = (email != NULL) ? [NSString stringWithUTF8String:email] : nil;
NSString *userIdString = (userId != NULL) ? [NSString stringWithUTF8String:userId] : nil;
NSString *ipAddressString = (ipAddress != NULL) ? [NSString stringWithUTF8String:ipAddress] : nil;
NSString *usernameString = (username != NULL) ? [NSString stringWithUTF8String:username] : nil;

[SentrySDK configureScope:^(SentryScope *scope) {
SentryUser *user = [[SentryUser alloc] init];

if (email != NULL) {
user.email = [NSString stringWithUTF8String:email];
if (emailString != nil) {
user.email = emailString;
}

if (userId != NULL) {
user.userId = [NSString stringWithUTF8String:userId];
if (userIdString != nil) {
user.userId = userIdString;
}

if (ipAddress != NULL) {
user.ipAddress = [NSString stringWithUTF8String:ipAddress];
if (ipAddressString != nil) {
user.ipAddress = ipAddressString;
}

if (username != NULL) {
user.username = [NSString stringWithUTF8String:username];
if (usernameString != nil) {
user.username = usernameString;
}

[scope setUser:user];
Expand Down Expand Up @@ -184,42 +237,21 @@ void SentryNativeBridgeSetTrace(const char *traceId, const char *spanId)

NSString *traceIdStr = [NSString stringWithUTF8String:traceId];
NSString *spanIdStr = [NSString stringWithUTF8String:spanId];

// This is a workaround to deal with SentryId living inside the Swift header
Class sentryIdClass = NSClassFromString(@"_TtC6Sentry8SentryId");
Class sentrySpanIdClass = NSClassFromString(@"SentrySpanId");

if (sentryIdClass && sentrySpanIdClass) {
id sentryTraceId = [[sentryIdClass alloc] initWithUUIDString:traceIdStr];
id sentrySpanId = [[sentrySpanIdClass alloc] initWithValue:spanIdStr];

if (sentryTraceId && sentrySpanId) {
[PrivateSentrySDKOnly setTrace:sentryTraceId spanId:sentrySpanId];
}
}
}

static inline NSString *_NSStringOrNil(const char *value)
{
return value ? [NSString stringWithUTF8String:value] : nil;
}

static inline NSNumber *_NSNumberOrNil(int32_t value)
{
return value == 0 ? nil : @(value);
}

static inline NSNumber *_NSBoolOrNil(int8_t value)
{
if (value == 0) {
return @NO;
}
if (value == 1) {
return @YES;
}
return nil;
}

void SentryNativeBridgeWriteScope( // clang-format off
// // const char *AppStartTime,
// const char *AppBuildType,
Expand Down Expand Up @@ -288,4 +320,4 @@ void SentryNativeBridgeWriteScope( // clang-format off
}];
}

NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_END
Loading