Title: [260343] trunk/Source/_javascript_Core
Revision
260343
Author
[email protected]
Date
2020-04-19 14:18:07 -0700 (Sun, 19 Apr 2020)

Log Message

Fix missing exception checks and handling in JSC APIs.
https://bugs.webkit.org/show_bug.cgi?id=210715
<rdar://problem/61599658>

Reviewed by Saam Barati.

* API/APICallbackFunction.h:
(JSC::APICallbackFunction::call):
- We should return early if an exception was thrown.  We should not be using the
  result in any way since we cannot rely on it having any sane value.
(JSC::APICallbackFunction::construct):
- For consistency, also return an undefined here when an exception was thrown.

* API/JSCallbackObjectFunctions.h:
(JSC::JSCallbackObject<Parent>::construct):
(JSC::JSCallbackObject<Parent>::call):
- Return an undefined if an exception was thrown.  Don't return the potentially
  garbage result value.  Who knows what the client code will do with it.  Returning
  an undefined here makes the code more robust.

* API/JSObjectRef.cpp:
(JSObjectGetProperty):
(JSObjectHasPropertyForKey):
(JSObjectGetPropertyForKey):
(JSObjectDeletePropertyForKey):
(JSObjectGetPropertyAtIndex):
(JSObjectDeleteProperty):
- Explicitly return a nullptr if an exception was thrown.  The toRef() on the
  result that follows the exception check may or may not return a nullptr
  (also see toRef(JSC::VM& vm, JSC::JSValue v) for !CPU(ADDRESS64)).

* API/JSValueRef.cpp:
(JSValueIsEqual):
(JSValueIsInstanceOfConstructor):
- For consistency, make these return false if an exception is thrown.

* API/ObjCCallbackFunction.mm:
(JSC::objCCallbackFunctionCallAsFunction):
(JSC::objCCallbackFunctionCallAsConstructor):
(JSC::ObjCCallbackFunctionImpl::call):
- Add some assertions and return early if an exception was thrown.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/API/APICallbackFunction.h (260342 => 260343)


--- trunk/Source/_javascript_Core/API/APICallbackFunction.h	2020-04-19 18:34:07 UTC (rev 260342)
+++ trunk/Source/_javascript_Core/API/APICallbackFunction.h	2020-04-19 21:18:07 UTC (rev 260343)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -62,8 +62,10 @@
         JSLock::DropAllLocks dropAllLocks(globalObject);
         result = jsCast<T*>(toJS(functionRef))->functionCallback()(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception);
     }
-    if (exception)
+    if (exception) {
         throwException(globalObject, scope, toJS(globalObject, exception));
+        return JSValue::encode(jsUndefined());
+    }
 
     // result must be a valid JSValue.
     if (!result)
@@ -97,7 +99,7 @@
         }
         if (exception) {
             throwException(globalObject, scope, toJS(globalObject, exception));
-            return JSValue::encode(toJS(globalObject, exception));
+            return JSValue::encode(jsUndefined());
         }
         // result must be a valid JSValue.
         if (!result)

Modified: trunk/Source/_javascript_Core/API/JSCallbackObjectFunctions.h (260342 => 260343)


--- trunk/Source/_javascript_Core/API/JSCallbackObjectFunctions.h	2020-04-19 18:34:07 UTC (rev 260342)
+++ trunk/Source/_javascript_Core/API/JSCallbackObjectFunctions.h	2020-04-19 21:18:07 UTC (rev 260343)
@@ -465,8 +465,10 @@
                 JSLock::DropAllLocks dropAllLocks(globalObject);
                 result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception));
             }
-            if (exception)
+            if (exception) {
                 throwException(globalObject, scope, toJS(globalObject, exception));
+                return JSValue::encode(jsUndefined());
+            }
             return JSValue::encode(result);
         }
     }
@@ -538,8 +540,10 @@
                 JSLock::DropAllLocks dropAllLocks(globalObject);
                 result = toJS(globalObject, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception));
             }
-            if (exception)
+            if (exception) {
                 throwException(globalObject, scope, toJS(globalObject, exception));
+                return JSValue::encode(jsUndefined());
+            }
             return JSValue::encode(result);
         }
     }

Modified: trunk/Source/_javascript_Core/API/JSObjectRef.cpp (260342 => 260343)


--- trunk/Source/_javascript_Core/API/JSObjectRef.cpp	2020-04-19 18:34:07 UTC (rev 260342)
+++ trunk/Source/_javascript_Core/API/JSObjectRef.cpp	2020-04-19 21:18:07 UTC (rev 260343)
@@ -348,7 +348,7 @@
 {
     if (!ctx || !object) {
         ASSERT_NOT_REACHED();
-        return 0;
+        return nullptr;
     }
     JSGlobalObject* globalObject = toJS(ctx);
     VM& vm = globalObject->vm();
@@ -358,7 +358,8 @@
     JSObject* jsObject = toJS(object);
 
     JSValue jsValue = jsObject->get(globalObject, propertyName->identifier(&vm));
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return nullptr;
     return toRef(globalObject, jsValue);
 }
 
@@ -407,7 +408,8 @@
         return false;
 
     bool result = jsObject->hasProperty(globalObject, ident);
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return false;
     return result;
 }
 
@@ -428,7 +430,8 @@
         return nullptr;
 
     JSValue jsValue = jsObject->get(globalObject, ident);
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return nullptr;
     return toRef(globalObject, jsValue);
 }
 
@@ -480,7 +483,8 @@
         return false;
 
     bool result = JSCell::deleteProperty(jsObject, globalObject, ident);
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return false;
     return result;
 }
 
@@ -488,7 +492,7 @@
 {
     if (!ctx) {
         ASSERT_NOT_REACHED();
-        return 0;
+        return nullptr;
     }
     JSGlobalObject* globalObject = toJS(ctx);
     VM& vm = globalObject->vm();
@@ -498,7 +502,8 @@
     JSObject* jsObject = toJS(object);
 
     JSValue jsValue = jsObject->get(globalObject, propertyIndex);
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return nullptr;
     return toRef(globalObject, jsValue);
 }
 
@@ -535,7 +540,8 @@
     JSObject* jsObject = toJS(object);
 
     bool result = JSCell::deleteProperty(jsObject, globalObject, propertyName->identifier(&vm));
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return false;
     return result;
 }
 

Modified: trunk/Source/_javascript_Core/API/JSValueRef.cpp (260342 => 260343)


--- trunk/Source/_javascript_Core/API/JSValueRef.cpp	2020-04-19 18:34:07 UTC (rev 260342)
+++ trunk/Source/_javascript_Core/API/JSValueRef.cpp	2020-04-19 21:18:07 UTC (rev 260343)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -235,7 +235,8 @@
     JSValue jsB = toJS(globalObject, b);
 
     bool result = JSValue::equal(globalObject, jsA, jsB); // false if an exception is thrown
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return false;
     
     return result;
 }
@@ -272,7 +273,8 @@
     if (!jsConstructor->structure(vm)->typeInfo().implementsHasInstance())
         return false;
     bool result = jsConstructor->hasInstance(globalObject, jsValue); // false if an exception is thrown
-    handleExceptionIfNeeded(scope, ctx, exception);
+    if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow)
+        return false;
     return result;
 }
 

Modified: trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm (260342 => 260343)


--- trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm	2020-04-19 18:34:07 UTC (rev 260342)
+++ trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm	2020-04-19 21:18:07 UTC (rev 260343)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -67,7 +67,10 @@
 class CallbackArgumentInteger : public CallbackArgument {
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         T value = (T)JSC::toInt32(JSValueToNumber([context JSGlobalContextRef], argument, exception));
+        if (*exception)
+            return;
         [invocation setArgument:&value atIndex:argumentNumber];
     }
 };
@@ -76,7 +79,10 @@
 class CallbackArgumentDouble : public CallbackArgument {
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         T value = (T)JSValueToNumber([context JSGlobalContextRef], argument, exception);
+        if (*exception)
+            return;
         [invocation setArgument:&value atIndex:argumentNumber];
     }
 };
@@ -107,6 +113,7 @@
 private:
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         JSGlobalContextRef contextRef = [context JSGlobalContextRef];
 
         id object = tryUnwrapObjcObject(contextRef, argument);
@@ -130,7 +137,10 @@
 class CallbackArgumentNSNumber : public CallbackArgument {
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         id value = valueToNumber([context JSGlobalContextRef], argument, exception);
+        if (*exception)
+            return;
         [invocation setArgument:&value atIndex:argumentNumber];
     }
 };
@@ -138,7 +148,10 @@
 class CallbackArgumentNSString : public CallbackArgument {
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         id value = valueToString([context JSGlobalContextRef], argument, exception);
+        if (*exception)
+            return;
         [invocation setArgument:&value atIndex:argumentNumber];
     }
 };
@@ -146,7 +159,10 @@
 class CallbackArgumentNSDate : public CallbackArgument {
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         id value = valueToDate([context JSGlobalContextRef], argument, exception);
+        if (*exception)
+            return;
         [invocation setArgument:&value atIndex:argumentNumber];
     }
 };
@@ -154,7 +170,10 @@
 class CallbackArgumentNSArray : public CallbackArgument {
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         id value = valueToArray([context JSGlobalContextRef], argument, exception);
+        if (*exception)
+            return;
         [invocation setArgument:&value atIndex:argumentNumber];
     }
 };
@@ -162,7 +181,10 @@
 class CallbackArgumentNSDictionary : public CallbackArgument {
     void set(NSInvocation *invocation, NSInteger argumentNumber, JSContext *context, JSValueRef argument, JSValueRef* exception) override
     {
+        ASSERT(exception && !*exception);
         id value = valueToDictionary([context JSGlobalContextRef], argument, exception);
+        if (*exception)
+            return;
         [invocation setArgument:&value atIndex:argumentNumber];
     }
 };
@@ -447,6 +469,8 @@
 
 static JSValueRef objCCallbackFunctionCallAsFunction(JSContextRef callerContext, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
+    ASSERT(exception && !*exception);
+
     // Retake the API lock - we need this for a few reasons:
     // (1) We don't want to support the C-API's confusing drops-locks-once policy - should only drop locks if we can do so recursively.
     // (2) We're calling some JSC internals that require us to be on the 'inside' - e.g. createTypeError.
@@ -460,6 +484,8 @@
     if (impl->type() == CallbackInitMethod) {
         JSGlobalContextRef contextRef = [context JSGlobalContextRef];
         *exception = toRef(JSC::createTypeError(toJS(contextRef), "Cannot call a class constructor without |new|"_s));
+        if (*exception)
+            return nullptr;
         return JSValueMakeUndefined(contextRef);
     }
 
@@ -472,11 +498,14 @@
             *exception = valueInternalValue(context.exception);
         [context endCallbackWithData:&callbackData];
     }
+    if (*exception)
+        return nullptr;
     return result;
 }
 
 static JSObjectRef objCCallbackFunctionCallAsConstructor(JSContextRef callerContext, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
+    ASSERT(exception && !*exception);
     JSC::JSLockHolder locker(toJS(callerContext));
 
     ObjCCallbackFunction* callback = static_cast<ObjCCallbackFunction*>(toJS(constructor));
@@ -492,15 +521,15 @@
             *exception = valueInternalValue(context.exception);
         [context endCallbackWithData:&callbackData];
     }
-
-    JSGlobalContextRef contextRef = [context JSGlobalContextRef];
     if (*exception)
         return nullptr;
 
+    JSGlobalContextRef contextRef = [context JSGlobalContextRef];
     if (!JSValueIsObject(contextRef, result)) {
         *exception = toRef(JSC::createTypeError(toJS(contextRef), "Objective-C blocks called as constructors must return an object."_s));
         return nullptr;
     }
+    ASSERT(!*exception);
     return const_cast<JSObjectRef>(result);
 }
 
@@ -540,6 +569,7 @@
 
 JSValueRef ObjCCallbackFunctionImpl::call(JSContext *context, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
+    ASSERT(exception && !*exception);
     JSGlobalContextRef contextRef = [context JSGlobalContextRef];
 
     id target;
@@ -550,6 +580,8 @@
         target = [m_instanceClass alloc];
         if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
             *exception = toRef(JSC::createTypeError(toJS(contextRef), "self type check failed for Objective-C instance method"_s));
+            if (*exception)
+                return nullptr;
             return JSValueMakeUndefined(contextRef);
         }
         [m_invocation setTarget:target];
@@ -560,6 +592,8 @@
         target = tryUnwrapObjcObject(contextRef, thisObject);
         if (!target || ![target isKindOfClass:m_instanceClass.get()]) {
             *exception = toRef(JSC::createTypeError(toJS(contextRef), "self type check failed for Objective-C instance method"_s));
+            if (*exception)
+                return nullptr;
             return JSValueMakeUndefined(contextRef);
         }
         [m_invocation setTarget:target];
@@ -578,7 +612,7 @@
         JSValueRef value = argumentNumber < argumentCount ? arguments[argumentNumber] : JSValueMakeUndefined(contextRef);
         argument->set(m_invocation.get(), argumentNumber + firstArgument, context, value, exception);
         if (*exception)
-            return JSValueMakeUndefined(contextRef);
+            return nullptr;
         ++argumentNumber;
     }
 
@@ -585,6 +619,8 @@
     [m_invocation invoke];
 
     JSValueRef result = m_result->get(m_invocation.get(), context, exception);
+    if (*exception)
+        return nullptr;
 
     // Balance our call to -alloc with a call to -autorelease. We have to do this after calling -init
     // because init family methods are allowed to release the allocated object and return something 

Modified: trunk/Source/_javascript_Core/ChangeLog (260342 => 260343)


--- trunk/Source/_javascript_Core/ChangeLog	2020-04-19 18:34:07 UTC (rev 260342)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-04-19 21:18:07 UTC (rev 260343)
@@ -1,3 +1,47 @@
+2020-04-19  Mark Lam  <[email protected]>
+
+        Fix missing exception checks and handling in JSC APIs.
+        https://bugs.webkit.org/show_bug.cgi?id=210715
+        <rdar://problem/61599658>
+
+        Reviewed by Saam Barati.
+
+        * API/APICallbackFunction.h:
+        (JSC::APICallbackFunction::call):
+        - We should return early if an exception was thrown.  We should not be using the
+          result in any way since we cannot rely on it having any sane value.
+        (JSC::APICallbackFunction::construct):
+        - For consistency, also return an undefined here when an exception was thrown.
+
+        * API/JSCallbackObjectFunctions.h:
+        (JSC::JSCallbackObject<Parent>::construct):
+        (JSC::JSCallbackObject<Parent>::call):
+        - Return an undefined if an exception was thrown.  Don't return the potentially
+          garbage result value.  Who knows what the client code will do with it.  Returning
+          an undefined here makes the code more robust.
+
+        * API/JSObjectRef.cpp:
+        (JSObjectGetProperty):
+        (JSObjectHasPropertyForKey):
+        (JSObjectGetPropertyForKey):
+        (JSObjectDeletePropertyForKey):
+        (JSObjectGetPropertyAtIndex):
+        (JSObjectDeleteProperty):
+        - Explicitly return a nullptr if an exception was thrown.  The toRef() on the
+          result that follows the exception check may or may not return a nullptr
+          (also see toRef(JSC::VM& vm, JSC::JSValue v) for !CPU(ADDRESS64)).
+
+        * API/JSValueRef.cpp:
+        (JSValueIsEqual):
+        (JSValueIsInstanceOfConstructor):
+        - For consistency, make these return false if an exception is thrown.
+
+        * API/ObjCCallbackFunction.mm:
+        (JSC::objCCallbackFunctionCallAsFunction):
+        (JSC::objCCallbackFunctionCallAsConstructor):
+        (JSC::ObjCCallbackFunctionImpl::call):
+        - Add some assertions and return early if an exception was thrown.
+
 2020-04-18  Keith Miller  <[email protected]>
 
         Fix CLoop build for iterator opcodes
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to