From 3e0668000ef1baac5dff3570cf2a36c61ee91d8e Mon Sep 17 00:00:00 2001 From: Jan Vennemann Date: Thu, 9 Apr 2020 03:24:50 +0200 Subject: [PATCH] fix(ios): manually evaluate all error properties (9_0_X) (#11577) * fix(ios): manually evaluate all error properties * fix(ios): pass correct context argument * fix(ios): look up non-enumerable error properties Co-authored-by: Vijay Vikram Singh Co-authored-by: ssekhri --- .../TitaniumKit/Sources/API/KrollBridge.m | 6 +-- .../TitaniumKit/Sources/API/ObjcProxy.m | 3 +- .../TitaniumKit/Sources/API/TiBindingEvent.m | 3 +- .../Sources/API/TiBindingTiValue.m | 40 +++++++++-------- .../Sources/API/TiExceptionHandler.h | 9 ++++ .../Sources/API/TiExceptionHandler.m | 12 ++++++ .../TitaniumKit/Sources/API/TiUtils.h | 2 + .../TitaniumKit/Sources/API/TiUtils.m | 43 +++++++++++++++++++ .../TitaniumKit/Sources/Kroll/KrollCallback.m | 3 +- .../TitaniumKit/Sources/Kroll/KrollContext.m | 6 +-- .../TitaniumKit/Sources/Kroll/KrollObject.m | 6 +-- .../Sources/Kroll/KrollTimerManager.m | 3 +- .../TitaniumKit/Sources/Kroll/KrollWrapper.m | 3 +- 13 files changed, 98 insertions(+), 41 deletions(-) diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/KrollBridge.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/KrollBridge.m index 97c2de386f0..db438b56db4 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/KrollBridge.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/KrollBridge.m @@ -315,9 +315,8 @@ - (void)evalFileOnThread:(NSString *)path context:(KrollContext *)context_ } } if (exception != NULL) { - id excm = [KrollObject toID:context value:exception]; evaluationError = YES; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:context]; } JSStringRelease(jsCode); @@ -696,8 +695,7 @@ - (KrollWrapper *)loadCommonJSModule:(NSString *)code withSourceURL:(NSURL *)sou [eval release]; if (exception != NULL) { - id excm = [KrollObject toID:context value:exception]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:context]; return nil; } /* diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/ObjcProxy.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/ObjcProxy.m index 95429fbec02..a8d6ad03440 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/ObjcProxy.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/ObjcProxy.m @@ -283,8 +283,7 @@ - (void)_fireEventToListener:(NSString *)type withObject:(id)obj listener:(JSVal // handle an uncaught exception JSValue *exception = listener.context.exception; if (exception != nil) { - NSDictionary *exceptionDict = [self JSValueToNative:exception]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:exceptionDict]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inJSContext:listener.context]; } } } diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingEvent.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingEvent.m index 0b14d0601cc..1833983ad29 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingEvent.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingEvent.m @@ -263,8 +263,7 @@ void TiBindingEventProcess(TiBindingRunLoop runloop, void *payload) JSValueRef exception = NULL; JSObjectCallAsFunction(context, (JSObjectRef)currentCallback, (JSObjectRef)eventTargetRef, 1, (JSValueRef *)&eventObjectRef, &exception); if (exception != NULL) { - id excm = TiBindingTiValueToNSObject(context, exception); - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:runloop]; } // Note cancel bubble diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingTiValue.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingTiValue.m index 124bf7d8469..50f59849528 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingTiValue.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiBindingTiValue.m @@ -32,9 +32,7 @@ { JSObjectRef obj = JSValueToObject(jsContext, objRef, NULL); JSPropertyNameArrayRef props = JSObjectCopyPropertyNames(jsContext, obj); - NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; - size_t count = JSPropertyNameArrayGetCount(props); for (size_t i = 0; i < count; i++) { JSStringRef jsString = JSPropertyNameArrayGetNameAtIndex(props, i); @@ -46,23 +44,30 @@ } [jsonkey release]; } + JSPropertyNameArrayRelease(props); - // if this looks like a JS Error object, get the message - if ([dict objectForKey:@"line"] != nil && [dict objectForKey:@"column"] != nil) { - JSStringRef messageKeyRef = JSStringCreateWithUTF8CString("message"); - JSStringRef stackKeyRef = JSStringCreateWithUTF8CString("stack"); - JSValueRef messageRef = JSObjectGetProperty(jsContext, obj, messageKeyRef, NULL); - JSValueRef stackRef = JSObjectGetProperty(jsContext, obj, stackKeyRef, NULL); - - id message = TiBindingTiValueToNSObject(jsContext, messageRef); - if (message && ![message isEqual:[NSNull null]]) { + // if this looks like a JS Error object, get related non-enumerable properties + JSContext *context = [JSContext contextWithJSGlobalContextRef:JSContextGetGlobalContext(jsContext)]; + JSValue *value = [JSValue valueWithJSValueRef:objRef inContext:context]; + if ([value hasProperty:@"line"] && [value hasProperty:@"column"]) { + if ([dict objectForKey:@"message"] == nil && [value hasProperty:@"message"]) { + NSString *message = [value[@"message"] toString]; [dict setObject:message forKey:@"message"]; } - JSStringRelease(messageKeyRef); - - id stack = TiBindingTiValueToNSObject(jsContext, stackRef); - if (stack && ![stack isEqual:[NSNull null]]) { - + if ([dict objectForKey:@"line"] == nil && [value hasProperty:@"line"]) { + NSNumber *line = [value[@"line"] toNumber]; + [dict setObject:line forKey:@"line"]; + } + if ([dict objectForKey:@"column"] == nil && [value hasProperty:@"column"]) { + NSNumber *column = [value[@"column"] toNumber]; + [dict setObject:column forKey:@"column"]; + } + if ([dict objectForKey:@"sourceURL"] == nil && [value hasProperty:@"sourceURL"]) { + NSString *sourceURL = [value[@"sourceURL"] toString]; + [dict setObject:sourceURL forKey:@"sourceURL"]; + } + if ([dict objectForKey:@"stack"] == nil && [value hasProperty:@"stack"]) { + NSString *stack = [value[@"stack"] toString]; // lets re-format the stack similar to node.js stack = [stack stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"file://%@", [[NSBundle mainBundle] bundlePath]] withString:@"("]; stack = [stack stringByReplacingOccurrencesOfString:@"\n" withString:@")\n at "]; @@ -72,11 +77,8 @@ [dict setObject:stack forKey:@"stack"]; } - JSStringRelease(stackKeyRef); } - JSPropertyNameArrayRelease(props); - return [dict autorelease]; } diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.h b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.h index 325ad3ef142..8039df4c633 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.h +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.h @@ -6,6 +6,11 @@ */ #import +#import + +@class KrollContext; +@class JSValue; +@class JSContext; #pragma mark - TiScriptError @@ -107,4 +112,8 @@ - (void)reportScriptError:(TiScriptError *)error; +- (void)reportScriptError:(JSValueRef)errorRef inKrollContext:(KrollContext *)krollContext; + +- (void)reportScriptError:(JSValue *)error inJSContext:(JSContext *)context; + @end diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.m index 85f435d01e7..3c9f92ff441 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiExceptionHandler.m @@ -7,9 +7,11 @@ #import "TiExceptionHandler.h" #import "APSAnalytics.h" +#import "KrollContext.h" #import "TiApp.h" #import "TiBase.h" +#include #include #include @@ -80,6 +82,16 @@ - (void)reportScriptError:(TiScriptError *)scriptError [currentDelegate handleScriptError:scriptError]; } +- (void)reportScriptError:(JSValueRef)errorRef inKrollContext:(KrollContext *)krollContext +{ + [self reportScriptError:[TiUtils scriptErrorFromValueRef:errorRef inContext:krollContext.context]]; +} + +- (void)reportScriptError:(JSValue *)error inJSContext:(JSContext *)context +{ + [self reportScriptError:[TiUtils scriptErrorFromValueRef:error.JSValueRef inContext:context.JSGlobalContextRef]]; +} + - (void)showScriptError:(TiScriptError *)error { NSArray *exceptionStackTrace = [error valueForKey:@"nativeStack"]; diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.h b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.h index 5b024f6eec1..031bc790241 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.h +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.h @@ -523,6 +523,8 @@ typedef enum { + (TiScriptError *)scriptErrorValue:(id)value; ++ (TiScriptError *)scriptErrorFromValueRef:(JSValueRef)valueRef inContext:(JSGlobalContextRef)contextRef; + + (NSTextAlignment)textAlignmentValue:(id)alignment; + (NSString *)jsonStringify:(id)value; diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.m index c268835b33b..d976759a9fe 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUtils.m @@ -1272,6 +1272,49 @@ + (WebFont *)fontValue:(id)value return [self fontValue:value def:[WebFont defaultFont]]; } ++ (TiScriptError *)scriptErrorFromValueRef:(JSValueRef)valueRef inContext:(JSGlobalContextRef)contextRef +{ + JSContext *context = [JSContext contextWithJSGlobalContextRef:contextRef]; + JSValue *error = [JSValue valueWithJSValueRef:valueRef inContext:context]; + NSMutableDictionary *errorDict = [NSMutableDictionary new]; + + if ([error hasProperty:@"constructor"]) { + [errorDict setObject:[error[@"constructor"][@"name"] toString] forKey:@"type"]; + } + + // error message + if ([error hasProperty:@"message"]) { + [errorDict setObject:[error[@"message"] toString] forKey:@"message"]; + } + if ([error hasProperty:@"nativeReason"]) { + [errorDict setObject:[error[@"nativeReason"] toString] forKey:@"nativeReason"]; + } + + // error location + if ([error hasProperty:@"sourceURL"]) { + [errorDict setObject:[error[@"sourceURL"] toString] forKey:@"sourceURL"]; + } + if ([error hasProperty:@"line"]) { + [errorDict setObject:[error[@"line"] toNumber] forKey:@"line"]; + } + if ([error hasProperty:@"column"]) { + [errorDict setObject:[error[@"column"] toNumber] forKey:@"column"]; + } + + // stack trace + if ([error hasProperty:@"backtrace"]) { + [errorDict setObject:[error[@"backtrace"] toString] forKey:@"backtrace"]; + } + if ([error hasProperty:@"stack"]) { + [errorDict setObject:[error[@"stack"] toString] forKey:@"stack"]; + } + if ([error hasProperty:@"nativeStack"]) { + [errorDict setObject:[error[@"nativeStack"] toString] forKey:@"nativeStack"]; + } + + return [[[TiScriptError alloc] initWithDictionary:errorDict] autorelease]; +} + + (TiScriptError *)scriptErrorValue:(id)value; { if ((value == nil) || (value == [NSNull null])) { diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollCallback.m b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollCallback.m index fc91ef89e81..2f6e45a95f2 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollCallback.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollCallback.m @@ -143,8 +143,7 @@ - (id)call:(NSArray *)args thisObject:(id)thisObject_ JSValueRef exception = NULL; JSValueRef retVal = JSObjectCallAsFunction(jsContext, function, tp, [args count], _args, &exception); if (exception != NULL) { - id excm = [KrollObject toID:context value:exception]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:context]; } if (top != NULL) { JSValueUnprotect(jsContext, tp); diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollContext.m b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollContext.m index f7090608629..4dfc61c0c27 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollContext.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollContext.m @@ -535,8 +535,7 @@ - (void)invoke:(KrollContext *)context [self jsInvokeInContext:context exception:&exception]; if (exception != NULL) { - id excm = [KrollObject toID:context value:exception]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:context]; pthread_mutex_unlock(&KrollEntryLock); } pthread_mutex_unlock(&KrollEntryLock); @@ -549,8 +548,7 @@ - (id)invokeWithResult:(KrollContext *)context JSValueRef result = [self jsInvokeInContext:context exception:&exception]; if (exception != NULL) { - id excm = [KrollObject toID:context value:exception]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:context]; pthread_mutex_unlock(&KrollEntryLock); } pthread_mutex_unlock(&KrollEntryLock); diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollObject.m b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollObject.m index 3234607439d..bf8dfaa2b9b 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollObject.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollObject.m @@ -1043,8 +1043,7 @@ - (void)invokeCallbackForKey:(NSString *)key withObject:(NSDictionary *)eventDat JSValueRef jsEventData = ConvertIdTiValue(context, eventData); JSValueRef result = JSObjectCallAsFunction(jsContext, jsCallback, [_thisObject jsobject], 1, &jsEventData, &exception); if (exception != NULL) { - id excm = [KrollObject toID:context value:exception]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:context]; } if (block != nil) { @@ -1279,8 +1278,7 @@ - (void)triggerEvent:(NSString *)eventName withObject:(NSDictionary *)eventData JSValueRef exception = NULL; JSObjectCallAsFunction(jsContext, (JSObjectRef)currentCallback, [thisObject jsobject], 1, &jsEventData, &exception); if (exception != NULL) { - id excm = [KrollObject toID:context value:exception]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:excm]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inKrollContext:context]; } } } diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollTimerManager.m b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollTimerManager.m index 3c4b7a02d7b..20aac830a6b 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollTimerManager.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollTimerManager.m @@ -50,8 +50,7 @@ - (void)timerFired:(NSTimer *_Nonnull)timer JSContext *context = self.callback.context; JSValue *exception = context.exception; if (exception != nil) { - NSDictionary *exceptionDict = TiBindingTiValueToNSObject(context.JSGlobalContextRef, exception.JSValueRef); - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:exceptionDict]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inJSContext:context]; } } diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollWrapper.m b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollWrapper.m index 3810fa85f18..04a17a6b3f1 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollWrapper.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollWrapper.m @@ -100,8 +100,7 @@ - (JSValueRef)executeWithArguments:(NSArray *)arguments JSValueRef functionResult = JSObjectCallAsFunction(context, value, NULL, 1, callArgs, &callException); if (callException != NULL) { - id exceptionPayload = [KrollObject toID:self.bridge.krollContext value:callException]; - [[TiExceptionHandler defaultExceptionHandler] reportScriptError:[TiUtils scriptErrorValue:exceptionPayload]]; + [TiExceptionHandler.defaultExceptionHandler reportScriptError:callException inKrollContext:self.bridge.krollContext]; } return functionResult;