Changeset 41905 in webkit for trunk/JavaScriptCore/API


Ignore:
Timestamp:
Mar 22, 2009, 11:01:46 PM (16 years ago)
Author:
[email protected]
Message:

Fix exception handling in API

Reviewed by Cameron Zwarich.

We can't just use the ExecState exception slot for returning exceptions
from class introspection functions provided through the API as many JSC
functions will explicitly clear the ExecState exception when returning.

Location:
trunk/JavaScriptCore/API
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/API/JSCallbackObjectFunctions.h

    r40046 r41905  
    127127                propertyNameRef = OpaqueJSString::create(propertyName.ustring());
    128128            JSLock::DropAllLocks dropAllLocks(exec);
    129             if (JSValueRef value = getProperty(ctx, thisRef, propertyNameRef.get(), toRef(exec->exceptionSlot()))) {
     129            JSValueRef exception = 0;
     130            JSValueRef value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception);
     131            exec->setException(toJS(exception));
     132            if (value) {
    130133                slot.setValue(toJS(value));
     134                return true;
     135            }
     136            if (exception) {
     137                slot.setValue(jsUndefined());
    131138                return true;
    132139            }
     
    170177                propertyNameRef = OpaqueJSString::create(propertyName.ustring());
    171178            JSLock::DropAllLocks dropAllLocks(exec);
    172             if (setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, toRef(exec->exceptionSlot())))
     179            JSValueRef exception = 0;
     180            bool result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception);
     181            exec->setException(toJS(exception));
     182            if (result || exception)
    173183                return;
    174184        }
     
    182192                        propertyNameRef = OpaqueJSString::create(propertyName.ustring());
    183193                    JSLock::DropAllLocks dropAllLocks(exec);
    184                     if (setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, toRef(exec->exceptionSlot())))
     194                    JSValueRef exception = 0;
     195                    bool result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception);
     196                    exec->setException(toJS(exception));
     197                    if (result || exception)
    185198                        return;
    186199                } else
     
    214227                propertyNameRef = OpaqueJSString::create(propertyName.ustring());
    215228            JSLock::DropAllLocks dropAllLocks(exec);
    216             if (deleteProperty(ctx, thisRef, propertyNameRef.get(), toRef(exec->exceptionSlot())))
     229            JSValueRef exception = 0;
     230            bool result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception);
     231            exec->setException(toJS(exception));
     232            if (result || exception)
    217233                return true;
    218234        }
     
    269285                arguments[i] = toRef(args.at(exec, i));
    270286            JSLock::DropAllLocks dropAllLocks(exec);
    271             return toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), toRef(exec->exceptionSlot())));
     287            JSValueRef exception = 0;
     288            JSObject* result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception));
     289            exec->setException(toJS(exception));
     290            return result;
    272291        }
    273292    }
     
    286305        if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) {
    287306            JSLock::DropAllLocks dropAllLocks(exec);
    288             return hasInstance(execRef, thisRef, toRef(value), toRef(exec->exceptionSlot()));
     307            JSValueRef exception = 0;
     308            bool result = hasInstance(execRef, thisRef, toRef(value), &exception);
     309            exec->setException(toJS(exception));
     310            return result;
    289311        }
    290312    }
     
    318340                arguments[i] = toRef(args.at(exec, i));
    319341            JSLock::DropAllLocks dropAllLocks(exec);
    320             return toJS(callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), toRef(exec->exceptionSlot())));
     342            JSValueRef exception = 0;
     343            JSValuePtr result = toJS(callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception));
     344            exec->setException(toJS(exception));
     345            return result;
    321346        }
    322347    }
     
    378403        if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
    379404            JSLock::DropAllLocks dropAllLocks(exec);
    380             if (JSValueRef value = convertToType(ctx, thisRef, kJSTypeNumber, toRef(exec->exceptionSlot()))) {
     405           
     406            JSValueRef exception = 0;
     407            JSValueRef value = convertToType(ctx, thisRef, kJSTypeNumber, &exception);
     408            exec->setException(toJS(exception));
     409            if (value) {
    381410                double dValue;
    382411                return toJS(value).getNumber(dValue) ? dValue : NaN;
     
    396425        if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
    397426            JSValueRef value;
     427            JSValueRef exception = 0;
    398428            {
    399429                JSLock::DropAllLocks dropAllLocks(exec);
    400                 value = convertToType(ctx, thisRef, kJSTypeString, toRef(exec->exceptionSlot()));
     430                value = convertToType(ctx, thisRef, kJSTypeString, &exception);
     431                exec->setException(toJS(exception));
    401432            }
    402433            if (value)
    403434                return toJS(value).getString();
     435            if (exception)
     436                return "";
    404437        }
    405438           
     
    444477                        propertyNameRef = OpaqueJSString::create(propertyName.ustring());
    445478                    JSLock::DropAllLocks dropAllLocks(exec);
    446                     if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), toRef(exec->exceptionSlot())))
     479                    JSValueRef exception = 0;
     480                    JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception);
     481                    exec->setException(toJS(exception));
     482                    if (value)
    447483                        return toJS(value);
     484                    if (exception)
     485                        return jsUndefined();
    448486                }
    449487                   
     
    489527                propertyNameRef = OpaqueJSString::create(propertyName.ustring());
    490528            JSLock::DropAllLocks dropAllLocks(exec);
    491             if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), toRef(exec->exceptionSlot())))
     529
     530            JSValueRef exception = 0;
     531            JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception);
     532            exec->setException(toJS(exception));
     533            if (value)
    492534                return toJS(value);
     535            if (exception)
     536                return jsUndefined();
    493537        }
    494538           
  • trunk/JavaScriptCore/API/tests/testapi.c

    r41895 r41905  
    129129    if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")
    130130        || JSStringIsEqualToUTF8CString(propertyName, "cantFind")
     131        || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")
    131132        || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")
    132133        || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")
     
    154155        return JSValueMakeUndefined(context);
    155156    }
    156    
     157
     158    if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) {
     159        return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
     160    }
     161
    157162    if (JSStringIsEqualToUTF8CString(propertyName, "0")) {
    158163        *exception = JSValueMakeNumber(context, 1);
     
    173178        return true; // pretend we set the property in order to swallow it
    174179   
     180    if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) {
     181        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
     182    }
     183   
    175184    return false;
    176185}
     
    185194   
    186195    if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) {
    187         *exception = JSValueMakeNumber(context, 2);
     196        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
    188197        return false;
    189198    }
     
    215224    UNUSED_PARAM(exception);
    216225
     226    if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnCall")) {
     227        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
     228        return JSValueMakeUndefined(context);
     229    }
     230
    217231    if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
    218232        return JSValueMakeNumber(context, 1);
     
    226240    UNUSED_PARAM(object);
    227241
     242    if (argumentCount > 0 && JSValueIsString(context, arguments[0]) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, arguments[0], 0), "throwOnConstruct")) {
     243        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception);
     244        return object;
     245    }
     246
    228247    if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0)))
    229248        return JSValueToObject(context, JSValueMakeNumber(context, 1), exception);
     
    236255    UNUSED_PARAM(context);
    237256    UNUSED_PARAM(constructor);
     257
     258    if (JSValueIsString(context, possibleValue) && JSStringIsEqualToUTF8CString(JSValueToStringCopy(context, possibleValue, 0), "throwOnHasInstance")) {
     259        JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), constructor, JSStringCreateWithUTF8CString("test script"), 1, exception);
     260        return false;
     261    }
    238262
    239263    JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
     
    310334    return jsClass;
    311335}
     336
     337static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
     338{
     339    UNUSED_PARAM(context);
     340    UNUSED_PARAM(constructor);
     341   
     342    JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance");
     343    JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception);
     344    JSStringRelease(hasInstanceName);
     345   
     346    JSObjectRef function = JSValueToObject(context, hasInstance, exception);
     347    JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception);
     348    return result && JSValueToBoolean(context, result);
     349}
     350
     351static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
     352{
     353    UNUSED_PARAM(object);
     354    UNUSED_PARAM(exception);
     355    JSStringRef funcName;
     356    switch (type) {
     357    case kJSTypeNumber:
     358        funcName = JSStringCreateWithUTF8CString("toNumber");
     359        break;
     360    case kJSTypeString:
     361        funcName = JSStringCreateWithUTF8CString("toStringExplicit");
     362        break;
     363    default:
     364        return NULL;
     365        break;
     366    }
     367   
     368    JSValueRef func = JSObjectGetProperty(context, object, funcName, exception);
     369    JSStringRelease(funcName);   
     370    JSObjectRef function = JSValueToObject(context, func, exception);
     371    if (!function)
     372        return NULL;
     373    JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception);
     374    if (!value)
     375        return (JSValueRef)JSStringCreateWithUTF8CString("convertToType failed");
     376    return value;
     377}
     378
     379JSClassDefinition EvilExceptionObject_definition = {
     380    0,
     381    kJSClassAttributeNone,
     382
     383    "EvilExceptionObject",
     384    NULL,
     385
     386    NULL,
     387    NULL,
     388
     389    NULL,
     390    NULL,
     391    NULL,
     392    NULL,
     393    NULL,
     394    NULL,
     395    NULL,
     396    NULL,
     397    NULL,
     398    EvilExceptionObject_hasInstance,
     399    EvilExceptionObject_convertToType,
     400};
     401
     402static JSClassRef EvilExceptionObject_class(JSContextRef context)
     403{
     404    UNUSED_PARAM(context);
     405   
     406    static JSClassRef jsClass;
     407    if (!jsClass)
     408        jsClass = JSClassCreate(&EvilExceptionObject_definition);
     409   
     410    return jsClass;
     411}
     412
    312413
    313414static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
     
    669770    JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
    670771    JSStringRelease(myObjectIString);
     772   
     773    JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL);
     774    JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject");
     775    JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL);
     776    JSStringRelease(EvilExceptionObjectIString);
    671777   
    672778    JSValueRef exception;
  • trunk/JavaScriptCore/API/tests/testapi.js

    r41896 r41905  
    8181delete MyObject.cantDelete;
    8282shouldBe("MyObject.cantDelete", 1);
    83 shouldBe("delete MyObject.throwOnDelete", 2); // deleteProperty -- should throw 2
     83shouldBe("delete MyObject.throwOnDelete", "an exception");
    8484MyObject.cantSet = 1;
    8585shouldBe("MyObject.cantSet", undefined);
     86shouldBe("MyObject.throwOnGet", "an exception");
     87shouldBe("MyObject.throwOnSet = 5", "an exception");
     88shouldBe("MyObject('throwOnCall')", "an exception");
     89shouldBe("new MyObject('throwOnConstruct')", "an exception");
     90shouldBe("'throwOnHasInstance' instanceof MyObject", "an exception");
    8691
    8792var foundMyPropertyName = false;
     
    146151shouldBe("derived.protoDup = 0", 2);
    147152
     153shouldBe("undefined instanceof MyObject", false);
     154EvilExceptionObject.hasInstance = function f() { return f(); };
     155EvilExceptionObject.__proto__ = undefined;
     156shouldThrow("undefined instanceof EvilExceptionObject");
     157EvilExceptionObject.hasInstance = function () { return true; };
     158shouldBe("undefined instanceof EvilExceptionObject", true);
     159
     160EvilExceptionObject.toNumber = function f() { return f(); }
     161shouldThrow("EvilExceptionObject*5");
     162EvilExceptionObject.toStringExplicit = function f() { return f(); }
     163shouldThrow("String(EvilExceptionObject)");
     164
     165
    148166if (failed)
    149167    throw "Some tests failed";
Note: See TracChangeset for help on using the changeset viewer.