Ignore:
Timestamp:
Mar 19, 2012, 1:12:05 AM (13 years ago)
Author:
[email protected]
Message:

JSCallbackFunction::toStringCallback/valueOfCallback do not handle 0 return value from convertToType
https://bugs.webkit.org/show_bug.cgi?id=81468 <rdar://problem/11034745>

Reviewed by Oliver Hunt.

The API specifies that convertToType may opt not to handle a conversion:

"@result The objects's converted value, or NULL if the object was not converted."

In which case, it would propagate first up the JSClass hierarchy, calling its superclass's
conversion functions, and failing that call the JSObject::defaultValue function.

Unfortunately this behaviour was removed in bug#69677/bug#69858, and instead we now rely on
the toStringCallback/valueOfCallback function introduced in bug#69156. Even after a fix in
bug#73368, these will return the result from the first convertToType they find, regardless
of whether this result is null, and if no convertToType method is found in the api class
hierarchy (possible if toStringCallback/valueOfCallback was accessed off the prototype
chain), they will also return a null pointer. This is unsafe.

It would be easy to make the approach based around toStringCallback/valueOfCallback continue
to walk the api class hierarchy, but making the fallback to defaultValue would be problematic
(since defaultValue calls toStringCallback/valueOfCallback, this would infinitely recurse).
Making the fallback work with toString/valueOf methods attached to api objects is probably
not the right thing to do – instead, we should just implement the defaultValue trap for api
objects.

In addition, this bug highlights that fact that JSCallbackFunction::call will allow a hard
null to be returned from C to JavaScript - this is not okay. Handle with an exception.

  • API/JSCallbackFunction.cpp:

(JSC::JSCallbackFunction::call):

  • Should be null checking the return value.

(JSC):

  • Remove toStringCallback/valueOfCallback.
  • API/JSCallbackFunction.h:

(JSCallbackFunction):

  • Remove toStringCallback/valueOfCallback.
  • API/JSCallbackObject.h:

(JSCallbackObject):

  • Add defaultValue mthods to JSCallbackObject.
  • API/JSCallbackObjectFunctions.h:

(JSC::::defaultValue):

  • Add defaultValue mthods to JSCallbackObject.
  • API/JSClassRef.cpp:

(OpaqueJSClass::prototype):

  • Remove toStringCallback/valueOfCallback.
  • API/tests/testapi.js:
    • Revert this test, now we no longer artificially introduce a toString method onto the api object.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/JSCallbackFunction.cpp

    r103083 r111162  
    3131#include "CodeBlock.h"
    3232#include "ExceptionHelpers.h"
    33 #include "JSCallbackObject.h"
    3433#include "JSFunction.h"
    3534#include "FunctionPrototype.h"
     
    7776        throwError(exec, toJS(exec, exception));
    7877
     78    // result must be a valid JSValue.
     79    if (!result)
     80        return throwVMTypeError(exec);
     81
    7982    return JSValue::encode(toJS(exec, result));
    8083}
     
    8689}
    8790
    88 JSValueRef JSCallbackFunction::toStringCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef* exception)
    89 {
    90     JSObject* object = toJS(thisObject);
    91     if (object->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
    92         for (JSClassRef jsClass = jsCast<JSCallbackObject<JSNonFinalObject>*>(object)->classRef(); jsClass; jsClass = jsClass->parentClass)
    93             if (jsClass->convertToType)
    94                 return jsClass->convertToType(ctx, thisObject, kJSTypeString, exception);
    95     } else if (object->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
    96         for (JSClassRef jsClass = jsCast<JSCallbackObject<JSGlobalObject>*>(object)->classRef(); jsClass; jsClass = jsClass->parentClass)
    97             if (jsClass->convertToType)
    98                 return jsClass->convertToType(ctx, thisObject, kJSTypeString, exception);
    99     }
    100     return 0;
    101 }
    102 
    103 JSValueRef JSCallbackFunction::valueOfCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef* exception)
    104 {
    105     JSObject* object = toJS(thisObject);
    106     if (object->inherits(&JSCallbackObject<JSNonFinalObject>::s_info)) {
    107         for (JSClassRef jsClass = jsCast<JSCallbackObject<JSNonFinalObject>*>(object)->classRef(); jsClass; jsClass = jsClass->parentClass)
    108             if (jsClass->convertToType)
    109                 return jsClass->convertToType(ctx, thisObject, kJSTypeNumber, exception);
    110     } else if (object->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
    111         for (JSClassRef jsClass = jsCast<JSCallbackObject<JSGlobalObject>*>(object)->classRef(); jsClass; jsClass = jsClass->parentClass)
    112             if (jsClass->convertToType)
    113                 return jsClass->convertToType(ctx, thisObject, kJSTypeNumber, exception);
    114     }
    115     return 0;
    116 }
    117 
    118 
    11991} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.