Skip to content

Commit

Permalink
Proxing NSException stack trace to NSError object
Browse files Browse the repository at this point in the history
Summary:
When we catch an Objective-C exception and convert it to NSError we need to somehow represent the call stack from NSException instance in NSError instance. For now, we just attach the stack trace to `message` field.

The next step would be to figure out how to pass the Objective-C stack trace to error reporting infra to help it to display the stack trace nicely in the web interface.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: sammy-SC

Differential Revision: D23557600

fbshipit-source-id: a080c2e186e719e42dcfc01bb12f5811e3c5b2e6
  • Loading branch information
shergin authored and facebook-github-bot committed Sep 8, 2020
1 parent aaeffdb commit 1b994f9
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 2 deletions.
5 changes: 5 additions & 0 deletions React/Base/RCTAssert.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ RCT_EXTERN NSString *const RCTJSStackTraceKey;
*/
RCT_EXTERN NSString *const RCTJSRawStackTraceKey;

/**
* Objective-C stack trace string provided as part of an NSError's userInfo
*/
RCT_EXTERN NSString *const RCTObjCStackTraceKey;

/**
* Name of fatal exceptions generated by RCTFatal
*/
Expand Down
1 change: 1 addition & 0 deletions React/Base/RCTAssert.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
NSString *const RCTErrorDomain = @"RCTErrorDomain";
NSString *const RCTJSStackTraceKey = @"RCTJSStackTraceKey";
NSString *const RCTJSRawStackTraceKey = @"RCTJSRawStackTraceKey";
NSString *const RCTObjCStackTraceKey = @"RCTObjCStackTraceKey";
NSString *const RCTFatalExceptionName = @"RCTFatalException";
NSString *const RCTUntruncatedMessageKey = @"RCTUntruncatedMessageKey";

Expand Down
3 changes: 3 additions & 0 deletions React/Base/RCTUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ RCT_EXTERN BOOL RCTForceTouchAvailable(void);
// Create an NSError in the RCTErrorDomain
RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message);

// Creates an NSError from given an NSException
RCT_EXTERN NSError *RCTErrorWithNSException(NSException *exception);

// Convert nil values to NSNull, and vice-versa
#define RCTNullIfNil(value) ((value) ?: (id)kCFNull)
#define RCTNilIfNull(value) \
Expand Down
10 changes: 10 additions & 0 deletions React/Base/RCTUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,16 @@ BOOL RCTForceTouchAvailable(void)
return [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
}

NSError *RCTErrorWithNSException(NSException *exception)
{
NSString *message = [NSString stringWithFormat:@"NSException: %@; trace: %@.",
exception,
[[exception callStackSymbols] componentsJoinedByString:@";"]];
NSDictionary<NSString *, id> *errorInfo =
@{NSLocalizedDescriptionKey : message, RCTObjCStackTraceKey : [exception callStackSymbols]};
return [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
}

double RCTZeroIfNaN(double value)
{
return isnan(value) || isinf(value) ? 0 : value;
Expand Down
3 changes: 1 addition & 2 deletions React/CxxModule/RCTCxxUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@
func();
return nil;
} @catch (NSException *exception) {
NSString *message = [NSString stringWithFormat:@"Exception '%@' was thrown from JS thread", exception];
return RCTErrorWithMessage(message);
return RCTErrorWithNSException(exception);
} @catch (id exception) {
// This will catch any other ObjC exception, but no C++ exceptions
return RCTErrorWithMessage(@"non-std ObjC Exception");
Expand Down

0 comments on commit 1b994f9

Please sign in to comment.