Skip to content

Commit

Permalink
fix(ios): make KrollPromise no-op under covers when KrollFinalizer is…
Browse files Browse the repository at this point in the history
… running to avoid crash

* when finalizing don't even try to generate error object from context
  • Loading branch information
sgtcoolguy committed Jan 26, 2021
1 parent 9afe176 commit b3aaaa3
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 17 deletions.
1 change: 1 addition & 0 deletions iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ bool KrollDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef prope
+ (id)toID:(KrollContext *)context value:(JSValueRef)ref;
+ (JSValueRef)toValue:(KrollContext *)context value:(id)obj;
+ (id)nonNull:(id)value;
+ (BOOL)isFinalizing;

/**
Checks if a property with the given name exists on our target.
Expand Down
9 changes: 8 additions & 1 deletion iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ JSValueRef ConvertIdTiValue(KrollContext *context, id obj)
//
// callback for handling finalization (in JS land)
//
static BOOL finalizing = NO;
void KrollFinalizer(JSObjectRef ref)
{
id o = (id)JSObjectGetPrivate(ref);
Expand All @@ -112,9 +113,10 @@ void KrollFinalizer(JSObjectRef ref)
}
}
}

finalizing = YES;
[o release];
o = nil;
finalizing = NO;
}

bool KrollDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef *exception)
Expand Down Expand Up @@ -399,6 +401,11 @@ + (JSClassRef)jsClassRef
return KrollObjectClassRef;
}

+ (BOOL)isFinalizing
{
return finalizing;
}

- (id)initWithTarget:(id)target_ context:(KrollContext *)context_
{
if (self = [self init]) {
Expand Down
3 changes: 3 additions & 0 deletions iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollPromise.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
@private
JSValue *resolveFunc;
JSValue *rejectFunc;
BOOL _fulfilled;
BOOL _flushMe;
}

@property (readonly, nonatomic) JSValue *JSValue;

- (void)resolve:(NSArray *)arguments;
- (void)reject:(NSArray *)arguments;
- (void)rejectWithErrorMessage:(NSString *)message;
- (void)flush;

- (KrollPromise *)initInContext:(JSContext *)context;

Expand Down
74 changes: 58 additions & 16 deletions iphone/TitaniumKit/TitaniumKit/Sources/Kroll/KrollPromise.m
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
#import "KrollPromise.h"
#import "KrollObject.h"
#import "TiExceptionHandler.h"

@implementation KrollPromise

- (KrollPromise *)initInContext:(JSContext *)context
{
if (self = [super init]) {
if ([KrollObject isFinalizing]) {
// We cannot create a Promise in this context! If an object is being finalized the function
// we call to generate a Promise will crash complaining about the Promise constructor not being an object!
return self;
}
if (@available(iOS 13, *)) {
// Use iOS 13 APIs.
JSObjectRef resolve;
JSObjectRef reject;
JSValueRef exception = NULL;

JSObjectRef promiseRef = JSObjectMakeDeferredPromise(context.JSGlobalContextRef, &resolve, &reject, &exception);
if (exception) {
// FIXME: Randomly getting "null is not an object" and I don't know what is null here. The context? The Promise prototype?
// report exception
JSValue *error = [JSValue valueWithJSValueRef:exception inContext:context];
NSLog(@"%@", error[@"message"]);
[context setException:error];
_JSValue = [[JSValue valueWithUndefinedInContext:context] retain];
resolveFunc = [[JSValue valueWithUndefinedInContext:context] retain];
Expand All @@ -41,7 +44,6 @@ - (KrollPromise *)initInContext:(JSContext *)context
if (exception != nil) {
[TiExceptionHandler.defaultExceptionHandler reportScriptError:exception inJSContext:context];
}
// FIXME: Do we need to use a ManagedJSValue here rather than retain it? We do expose it to the JS Engine!
_JSValue = [[createPromise callWithArguments:@[ executor ]] retain];
resolveFunc = [executor[@"resolve"] retain];
rejectFunc = [executor[@"reject"] retain];
Expand All @@ -67,35 +69,75 @@ + (KrollPromise *)rejected:(NSArray *)arguments inContext:(JSContext *)context
+ (KrollPromise *)rejectedWithErrorMessage:(NSString *)message inContext:(JSContext *)context
{
KrollPromise *promise = [[[KrollPromise alloc] initInContext:context] autorelease];
JSValue *error = [JSValue valueWithNewErrorFromMessage:message inContext:context];
[promise reject:@[ error ]];
[promise rejectWithErrorMessage:message];
return promise;
}

- (void)resolve:(NSArray *)arguments
{
[resolveFunc callWithArguments:arguments];
if (resolveFunc) {
[resolveFunc callWithArguments:arguments];
}
_fulfilled = YES;
if (_flushMe) {
[self flush];
_flushMe = NO;
}
}

- (void)reject:(NSArray *)arguments
{
[rejectFunc callWithArguments:arguments];
if (rejectFunc) {
[rejectFunc callWithArguments:arguments];
}
_fulfilled = YES;
if (_flushMe) {
[self flush];
_flushMe = NO;
}
}

// We need to handle "settling" fulfillments/rejections so we don't leave unhandled rejections around
- (void)flush
{
if (_JSValue == nil) {
// assume no-op Promise generated during finalization
return;
}
if (_fulfilled) {
JSValue *noop = [JSValue
valueWithObject:^() {
}
inContext:rejectFunc.context];
[_JSValue invokeMethod:@"then" withArguments:@[ noop, noop ]];
} else {
// not yet fulfilled/rejected, so mark it to get flushed after it is
_flushMe = YES;
}
}

- (void)rejectWithErrorMessage:(NSString *)message
{
JSValue *error = [JSValue valueWithNewErrorFromMessage:message inContext:rejectFunc.context];
[self reject:@[ error ]];
if (rejectFunc) {
JSValue *error = [JSValue valueWithNewErrorFromMessage:message inContext:rejectFunc.context];
[self reject:@[ error ]];
}
}

- (void)dealloc
{
[_JSValue release];
_JSValue = nil;
[resolveFunc release];
resolveFunc = nil;
[rejectFunc release];
rejectFunc = nil;
if (_JSValue) {
[_JSValue release];
_JSValue = nil;
}
if (resolveFunc) {
[resolveFunc release];
resolveFunc = nil;
}
if (rejectFunc) {
[rejectFunc release];
rejectFunc = nil;
}
[super dealloc];
}

Expand Down

0 comments on commit b3aaaa3

Please sign in to comment.