Title: [202846] trunk
Revision
202846
Author
[email protected]
Date
2016-07-05 22:04:05 -0700 (Tue, 05 Jul 2016)

Log Message

RELEASE_ASSERT(!thisObject) in ObjCCallbackFunctionImpl::call when calling JSExport ObjC Constructor without operator new
https://bugs.webkit.org/show_bug.cgi?id=159446

Patch by Joseph Pecoraro <[email protected]> on 2016-07-05
Reviewed by Mark Lam.

Source/_javascript_Core:

Treat ObjC JSExport init constructors like ES6 Class Constructors
and throw a TypeError when called without 'new'.

* API/ObjCCallbackFunction.mm:
(JSC::ObjCCallbackFunctionImpl::type):
(JSC::objCCallbackFunctionCallAsFunction):
When calling an init method as a function instead of construction
throw a TypeError.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
Improve error message.

* API/tests/testapi.mm:
(testObjectiveCAPIMain):
Test we get an exception when calling an ObjC constructor without 'new'.

LayoutTests:

* js/class-syntax-call-expected.txt:
* js/class-syntax-default-constructor-expected.txt:
* js/script-tests/class-syntax-call.js:
* js/script-tests/class-syntax-default-constructor.js:
Improve error message when calling a class constructor without 'new'.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (202845 => 202846)


--- trunk/LayoutTests/ChangeLog	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/LayoutTests/ChangeLog	2016-07-06 05:04:05 UTC (rev 202846)
@@ -1,3 +1,16 @@
+2016-07-05  Joseph Pecoraro  <[email protected]>
+
+        RELEASE_ASSERT(!thisObject) in ObjCCallbackFunctionImpl::call when calling JSExport ObjC Constructor without operator new
+        https://bugs.webkit.org/show_bug.cgi?id=159446
+
+        Reviewed by Mark Lam.
+
+        * js/class-syntax-call-expected.txt:
+        * js/class-syntax-default-constructor-expected.txt:
+        * js/script-tests/class-syntax-call.js:
+        * js/script-tests/class-syntax-default-constructor.js:
+        Improve error message when calling a class constructor without 'new'.
+
 2016-07-05  David Kilzer  <[email protected]>
 
         Throw exceptions for invalid number of channels for ConvolverNode

Modified: trunk/LayoutTests/js/class-syntax-call-expected.txt (202845 => 202846)


--- trunk/LayoutTests/js/class-syntax-call-expected.txt	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/LayoutTests/js/class-syntax-call-expected.txt	2016-07-06 05:04:05 UTC (rev 202846)
@@ -4,13 +4,13 @@
 
 
 PASS new A
-PASS A():::"TypeError: Cannot call a class constructor"
+PASS A():::"TypeError: Cannot call a class constructor without |new|"
 PASS new B
-PASS B():::"TypeError: Cannot call a class constructor"
+PASS B():::"TypeError: Cannot call a class constructor without |new|"
 PASS new (class { constructor() {} })()
-PASS (class { constructor() {} })():::"TypeError: Cannot call a class constructor"
+PASS (class { constructor() {} })():::"TypeError: Cannot call a class constructor without |new|"
 PASS new (class extends null { constructor() { super() } })():::"TypeError: function is not a constructor (evaluating 'super()')"
-PASS (class extends null { constructor() { super() } })():::"TypeError: Cannot call a class constructor"
+PASS (class extends null { constructor() { super() } })():::"TypeError: Cannot call a class constructor without |new|"
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/js/class-syntax-default-constructor-expected.txt (202845 => 202846)


--- trunk/LayoutTests/js/class-syntax-default-constructor-expected.txt	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/LayoutTests/js/class-syntax-default-constructor-expected.txt	2016-07-06 05:04:05 UTC (rev 202846)
@@ -4,11 +4,11 @@
 
 
 PASS new A instanceof A
-PASS A():::TypeError: Cannot call a class constructor
+PASS A():::TypeError: Cannot call a class constructor without |new|
 PASS A.prototype.constructor instanceof Function
 PASS A.prototype.constructor.name:::"A"
 PASS new B instanceof A; new B instanceof A
-PASS B():::TypeError: Cannot call a class constructor
+PASS B():::TypeError: Cannot call a class constructor without |new|
 PASS B.prototype.constructor.name:::"B"
 PASS A !== B
 PASS A.prototype.constructor !== B.prototype.constructor

Modified: trunk/LayoutTests/js/script-tests/class-syntax-call.js (202845 => 202846)


--- trunk/LayoutTests/js/script-tests/class-syntax-call.js	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/LayoutTests/js/script-tests/class-syntax-call.js	2016-07-06 05:04:05 UTC (rev 202846)
@@ -32,12 +32,12 @@
 }
 
 shouldNotThrow('new A');
-shouldThrow('A()', '"TypeError: Cannot call a class constructor"');
+shouldThrow('A()', '"TypeError: Cannot call a class constructor without |new|"');
 shouldNotThrow('new B');
-shouldThrow('B()', '"TypeError: Cannot call a class constructor"');
+shouldThrow('B()', '"TypeError: Cannot call a class constructor without |new|"');
 shouldNotThrow('new (class { constructor() {} })()');
-shouldThrow('(class { constructor() {} })()', '"TypeError: Cannot call a class constructor"');
+shouldThrow('(class { constructor() {} })()', '"TypeError: Cannot call a class constructor without |new|"');
 shouldThrow('new (class extends null { constructor() { super() } })()', '"TypeError: function is not a constructor (evaluating \'super()\')"');
-shouldThrow('(class extends null { constructor() { super() } })()', '"TypeError: Cannot call a class constructor"');
+shouldThrow('(class extends null { constructor() { super() } })()', '"TypeError: Cannot call a class constructor without |new|"');
 
 var successfullyParsed = true;

Modified: trunk/LayoutTests/js/script-tests/class-syntax-default-constructor.js (202845 => 202846)


--- trunk/LayoutTests/js/script-tests/class-syntax-default-constructor.js	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/LayoutTests/js/script-tests/class-syntax-default-constructor.js	2016-07-06 05:04:05 UTC (rev 202846)
@@ -43,11 +43,11 @@
 class B extends A { };
 
 shouldBeTrue('new A instanceof A');
-shouldThrow('A()', '"TypeError: Cannot call a class constructor"');
+shouldThrow('A()', '"TypeError: Cannot call a class constructor without |new|"');
 shouldBeTrue('A.prototype.constructor instanceof Function');
 shouldBe('A.prototype.constructor.name', '"A"');
 shouldBeTrue('new B instanceof A; new B instanceof A');
-shouldThrow('B()', '"TypeError: Cannot call a class constructor"');
+shouldThrow('B()', '"TypeError: Cannot call a class constructor without |new|"');
 shouldBe('B.prototype.constructor.name', '"B"');
 shouldBeTrue('A !== B');
 shouldBeTrue('A.prototype.constructor !== B.prototype.constructor');

Modified: trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm (202845 => 202846)


--- trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/Source/_javascript_Core/API/ObjCCallbackFunction.mm	2016-07-06 05:04:05 UTC (rev 202846)
@@ -428,6 +428,8 @@
         }
     }
 
+    CallbackType type() const { return m_type; }
+
     bool isConstructible()
     {
         return !!wrappedBlock() || m_type == CallbackInitMethod;
@@ -455,6 +457,12 @@
     ObjCCallbackFunctionImpl* impl = callback->impl();
     JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(callback->globalObject()->globalExec())];
 
+    if (impl->type() == CallbackInitMethod) {
+        JSGlobalContextRef contextRef = [context JSGlobalContextRef];
+        *exception = toRef(JSC::createTypeError(toJS(contextRef), ASCIILiteral("Cannot call a class constructor without |new|")));
+        return JSValueMakeUndefined(contextRef);
+    }
+
     CallbackData callbackData;
     JSValueRef result;
     @autoreleasepool {

Modified: trunk/Source/_javascript_Core/API/tests/testapi.mm (202845 => 202846)


--- trunk/Source/_javascript_Core/API/tests/testapi.mm	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/Source/_javascript_Core/API/tests/testapi.mm	2016-07-06 05:04:05 UTC (rev 202846)
@@ -1334,6 +1334,7 @@
             } \
         })()"];
         checkResult(@"shouldn't be able to construct ClassC", ![canConstructClassC toBool]);
+
         JSValue *canConstructClassCPrime = [context evaluateScript:@"(function() { \
             try { \
                 (new ClassCPrime(1)); \
@@ -1347,6 +1348,19 @@
 
     @autoreleasepool {
         JSContext *context = [[JSContext alloc] init];
+        context[@"ClassA"] = [ClassA class];
+        context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
+            NSLog(@"%@", [exception toString]);
+            context.exception = exception;
+        };
+
+        checkResult(@"ObjC Constructor without 'new' pre", !context.exception);
+        [context evaluateScript:@"ClassA(42)"];
+        checkResult(@"ObjC Constructor without 'new' post", context.exception);
+    }
+
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
         context[@"ClassD"] = [ClassD class];
         context[@"ClassE"] = [ClassE class];
        

Modified: trunk/Source/_javascript_Core/ChangeLog (202845 => 202846)


--- trunk/Source/_javascript_Core/ChangeLog	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-07-06 05:04:05 UTC (rev 202846)
@@ -1,3 +1,27 @@
+2016-07-05  Joseph Pecoraro  <[email protected]>
+
+        RELEASE_ASSERT(!thisObject) in ObjCCallbackFunctionImpl::call when calling JSExport ObjC Constructor without operator new
+        https://bugs.webkit.org/show_bug.cgi?id=159446
+
+        Reviewed by Mark Lam.
+
+        Treat ObjC JSExport init constructors like ES6 Class Constructors
+        and throw a TypeError when called without 'new'.
+
+        * API/ObjCCallbackFunction.mm:
+        (JSC::ObjCCallbackFunctionImpl::type):
+        (JSC::objCCallbackFunctionCallAsFunction):
+        When calling an init method as a function instead of construction
+        throw a TypeError.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        Improve error message.
+
+        * API/tests/testapi.mm:
+        (testObjectiveCAPIMain):
+        Test we get an exception when calling an ObjC constructor without 'new'.
+
 2016-07-05  Mark Lam  <[email protected]>
 
         Remove some unneeded #include "CachedCall.h".

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (202845 => 202846)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2016-07-06 04:11:44 UTC (rev 202845)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2016-07-06 05:04:05 UTC (rev 202846)
@@ -564,7 +564,7 @@
                 else
                     emitCreateThis(&m_thisRegister);
             } else if (constructorKind() != ConstructorKind::None)
-                emitThrowTypeError("Cannot call a class constructor");
+                emitThrowTypeError("Cannot call a class constructor without |new|");
             else {
                 bool shouldEmitToThis = false;
                 if (functionNode->usesThis() || codeBlock->usesEval() || m_scopeNode->doAnyInnerArrowFunctionsUseThis() || m_scopeNode->doAnyInnerArrowFunctionsUseEval())
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to