From ba5015104dac25c4af56d661fcb6d54e4f30915f Mon Sep 17 00:00:00 2001 From: Zack Sheppard Date: Thu, 6 Dec 2018 20:19:06 -0800 Subject: [PATCH] Extend reason message for `RCTFatalException` (#22532) Summary: Fixes #22530 As described in the issue, the previous behavior for the `RCTFatal` macro was to truncate the `reason` on the resulting `NSException` to 75 characters. This would ensure the reason would fit on a single line, but resulted in issues debugging errors that occurred in the wild, as many crash logging tools (like Sentry) discard the `name` value of the exception and use the `reason` as their primary identifier. At 75 characters, useful information like the location of the error would usually be truncated. - [x] This extends the truncation threshold to 175 characters, which should be short enough to prevent full-screen-takeover length errors, but long enough to provide useful context to the error. - [x] This adds a `userInfo` value to the resulting `NSException`. It copies over the `userInfo` from the `NSError` passed to the macro, and adds an "untruncated message" value that contains the untruncated version of the `NSException`'s reason. [iOS] [Changed] - RCTFatalExceptions now include more information in their reason and a userInfo. Pull Request resolved: https://github.com/facebook/react-native/pull/22532 Differential Revision: D13373469 Pulled By: cpojer fbshipit-source-id: ac140d14ce76e1664869437c2c178bdd65ab6e0e --- React/Base/RCTAssert.m | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/React/Base/RCTAssert.m b/React/Base/RCTAssert.m index 61cefe2ad5fca2..13db0a598fd871 100644 --- a/React/Base/RCTAssert.m +++ b/React/Base/RCTAssert.m @@ -12,6 +12,7 @@ NSString *const RCTJSStackTraceKey = @"RCTJSStackTraceKey"; NSString *const RCTJSRawStackTraceKey = @"RCTJSRawStackTraceKey"; NSString *const RCTFatalExceptionName = @"RCTFatalException"; +NSString *const RCTUntruncatedMessageKey = @"RCTUntruncatedMessageKey"; static NSString *const RCTAssertFunctionStack = @"RCTAssertFunctionStack"; @@ -128,8 +129,20 @@ void RCTFatal(NSError *error) @try { #endif NSString *name = [NSString stringWithFormat:@"%@: %@", RCTFatalExceptionName, error.localizedDescription]; - NSString *message = RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], 75); - @throw [[NSException alloc] initWithName:name reason:message userInfo:nil]; + + // Truncate the localized description to 175 characters to avoid wild screen overflows + NSString *message = RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], 175); + + // Attach an untruncated copy of the description to the userInfo, in case it is needed + NSMutableDictionary *userInfo = [error.userInfo mutableCopy]; + [userInfo setObject:RCTFormatError(error.localizedDescription, error.userInfo[RCTJSStackTraceKey], -1) + forKey:RCTUntruncatedMessageKey]; + + // Expected resulting exception information: + // name: RCTFatalException: + // reason: + // userInfo: + @throw [[NSException alloc] initWithName:name reason:message userInfo:userInfo]; #if DEBUG } @catch (NSException *e) {} #endif