Title: [196745] trunk/Source
Revision
196745
Author
[email protected]
Date
2016-02-17 22:28:26 -0800 (Wed, 17 Feb 2016)

Log Message

Callers of JSString::value() should check for exceptions thereafter.
https://bugs.webkit.org/show_bug.cgi?id=154346

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

JSString::value() can throw an exception if the JS string is a rope and value() 
needs to resolve the rope but encounters an OutOfMemory error.  If value() is not
able to resolve the rope, it will return a null string (in addition to throwing
the exception).  If a caller does not check for exceptions after calling
JSString::value(), they may eventually use the returned null string and crash the
VM.

The fix is to add all the necessary exception checks, and do the appropriate
handling if needed.

* jsc.cpp:
(functionRun):
(functionLoad):
(functionReadFile):
(functionCheckSyntax):
(functionLoadWebAssembly):
(functionLoadModule):
(functionCheckModuleSyntax):
* runtime/DateConstructor.cpp:
(JSC::dateParse):
(JSC::dateNow):
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncEval):
* tools/JSDollarVMPrototype.cpp:
(JSC::functionPrint):

Source/WebCore:

No new tests.  The crash that results from this issue is dependent on a race
condition where an OutOfMemory error occurs precisely at the point where the
JSString::value() function is called on a rope JSString.

* bindings/js/JSHTMLAllCollectionCustom.cpp:
(WebCore::callHTMLAllCollection):
* bindings/js/JSStorageCustom.cpp:
(WebCore::JSStorage::putDelegate):
- Added a comment at the site of the exception check to clarify the meaning of
  the return value.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (196744 => 196745)


--- trunk/Source/_javascript_Core/ChangeLog	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-02-18 06:28:26 UTC (rev 196745)
@@ -1,3 +1,36 @@
+2016-02-17  Mark Lam  <[email protected]>
+
+        Callers of JSString::value() should check for exceptions thereafter.
+        https://bugs.webkit.org/show_bug.cgi?id=154346
+
+        Reviewed by Geoffrey Garen.
+
+        JSString::value() can throw an exception if the JS string is a rope and value() 
+        needs to resolve the rope but encounters an OutOfMemory error.  If value() is not
+        able to resolve the rope, it will return a null string (in addition to throwing
+        the exception).  If a caller does not check for exceptions after calling
+        JSString::value(), they may eventually use the returned null string and crash the
+        VM.
+
+        The fix is to add all the necessary exception checks, and do the appropriate
+        handling if needed.
+
+        * jsc.cpp:
+        (functionRun):
+        (functionLoad):
+        (functionReadFile):
+        (functionCheckSyntax):
+        (functionLoadWebAssembly):
+        (functionLoadModule):
+        (functionCheckModuleSyntax):
+        * runtime/DateConstructor.cpp:
+        (JSC::dateParse):
+        (JSC::dateNow):
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncEval):
+        * tools/JSDollarVMPrototype.cpp:
+        (JSC::functionPrint):
+
 2016-02-17  Benjamin Poulain  <[email protected]>
 
         [JSC] ARM64: Support the immediate format used for bit operations in Air

Modified: trunk/Source/_javascript_Core/jsc.cpp (196744 => 196745)


--- trunk/Source/_javascript_Core/jsc.cpp	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/_javascript_Core/jsc.cpp	2016-02-18 06:28:26 UTC (rev 196745)
@@ -1243,6 +1243,8 @@
 EncodedJSValue JSC_HOST_CALL functionRun(ExecState* exec)
 {
     String fileName = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     Vector<char> script;
     if (!fetchScriptFromLocalFileSystem(fileName, script))
         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
@@ -1272,6 +1274,8 @@
 EncodedJSValue JSC_HOST_CALL functionLoad(ExecState* exec)
 {
     String fileName = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     Vector<char> script;
     if (!fetchScriptFromLocalFileSystem(fileName, script))
         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
@@ -1288,6 +1292,8 @@
 EncodedJSValue JSC_HOST_CALL functionReadFile(ExecState* exec)
 {
     String fileName = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     Vector<char> script;
     if (!fillBufferWithContentsOfFile(fileName, script))
         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
@@ -1298,6 +1304,8 @@
 EncodedJSValue JSC_HOST_CALL functionCheckSyntax(ExecState* exec)
 {
     String fileName = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     Vector<char> script;
     if (!fetchScriptFromLocalFileSystem(fileName, script))
         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
@@ -1565,6 +1573,8 @@
 EncodedJSValue JSC_HOST_CALL functionLoadWebAssembly(ExecState* exec)
 {
     String fileName = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     Vector<char> buffer;
     if (!fillBufferWithContentsOfFile(fileName, buffer))
         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
@@ -1584,6 +1594,8 @@
 EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
 {
     String fileName = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     Vector<char> script;
     if (!fetchScriptFromLocalFileSystem(fileName, script))
         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
@@ -1608,6 +1620,8 @@
 EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState* exec)
 {
     String source = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
 
     StopWatch stopWatch;
     stopWatch.start();

Modified: trunk/Source/_javascript_Core/runtime/DateConstructor.cpp (196744 => 196745)


--- trunk/Source/_javascript_Core/runtime/DateConstructor.cpp	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/_javascript_Core/runtime/DateConstructor.cpp	2016-02-18 06:28:26 UTC (rev 196745)
@@ -205,7 +205,10 @@
 
 EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec)
 {
-    return JSValue::encode(jsNumber(parseDate(exec->vm(), exec->argument(0).toString(exec)->value(exec))));
+    String dateStr = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+    return JSValue::encode(jsNumber(parseDate(exec->vm(), dateStr)));
 }
 
 EncodedJSValue JSC_HOST_CALL dateNow(ExecState* exec)

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (196744 => 196745)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2016-02-18 06:28:26 UTC (rev 196745)
@@ -574,6 +574,8 @@
     }
 
     String s = x.toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
 
     if (s.is8Bit()) {
         LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON);

Modified: trunk/Source/_javascript_Core/tools/JSDollarVMPrototype.cpp (196744 => 196745)


--- trunk/Source/_javascript_Core/tools/JSDollarVMPrototype.cpp	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/_javascript_Core/tools/JSDollarVMPrototype.cpp	2016-02-18 06:28:26 UTC (rev 196745)
@@ -303,7 +303,10 @@
     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
         if (i)
             dataLog(" ");
-        dataLog(exec->uncheckedArgument(i).toString(exec)->value(exec));
+        String argStr = exec->uncheckedArgument(i).toString(exec)->value(exec);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+        dataLog(argStr);
     }
     return JSValue::encode(jsUndefined());
 }

Modified: trunk/Source/WebCore/ChangeLog (196744 => 196745)


--- trunk/Source/WebCore/ChangeLog	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/WebCore/ChangeLog	2016-02-18 06:28:26 UTC (rev 196745)
@@ -1,3 +1,21 @@
+2016-02-17  Mark Lam  <[email protected]>
+
+        Callers of JSString::value() should check for exceptions thereafter.
+        https://bugs.webkit.org/show_bug.cgi?id=154346
+
+        Reviewed by Geoffrey Garen.
+
+        No new tests.  The crash that results from this issue is dependent on a race
+        condition where an OutOfMemory error occurs precisely at the point where the
+        JSString::value() function is called on a rope JSString.
+
+        * bindings/js/JSHTMLAllCollectionCustom.cpp:
+        (WebCore::callHTMLAllCollection):
+        * bindings/js/JSStorageCustom.cpp:
+        (WebCore::JSStorage::putDelegate):
+        - Added a comment at the site of the exception check to clarify the meaning of
+          the return value.
+
 2016-02-17  David Kilzer  <[email protected]>
 
         [Cocoa] Always check the return value of dlopen() and dlsym() in Release builds

Modified: trunk/Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp (196744 => 196745)


--- trunk/Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp	2016-02-18 06:28:26 UTC (rev 196745)
@@ -65,6 +65,8 @@
     if (exec->argumentCount() == 1) {
         // Support for document.all(<index>) etc.
         String string = exec->argument(0).toString(exec)->value(exec);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
         if (Optional<uint32_t> index = parseIndex(*string.impl()))
             return JSValue::encode(toJS(exec, jsCollection->globalObject(), collection.item(index.value())));
 
@@ -74,6 +76,8 @@
 
     // The second arg, if set, is the index of the item we want
     String string = exec->argument(0).toString(exec)->value(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     if (Optional<uint32_t> index = parseIndex(*exec->argument(1).toWTFString(exec).impl())) {
         if (auto* item = collection.namedItemWithIndex(string, index.value()))
             return JSValue::encode(toJS(exec, jsCollection->globalObject(), item));

Modified: trunk/Source/WebCore/bindings/js/JSStorageCustom.cpp (196744 => 196745)


--- trunk/Source/WebCore/bindings/js/JSStorageCustom.cpp	2016-02-18 06:13:15 UTC (rev 196744)
+++ trunk/Source/WebCore/bindings/js/JSStorageCustom.cpp	2016-02-18 06:28:26 UTC (rev 196745)
@@ -114,8 +114,13 @@
         return false;
 
     String stringValue = value.toString(exec)->value(exec);
-    if (exec->hadException())
+    if (exec->hadException()) {
+        // The return value indicates whether putDelegate() should handle the put operation (which
+        // if true, tells the caller not to execute the generic put). It does not indicate whether
+        // putDelegate() did successfully complete the operation or not (which it didn't in this
+        // case due to the exception).
         return true;
+    }
 
     ExceptionCode ec = 0;
     wrapped().setItem(propertyNameToString(propertyName), stringValue, ec);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to