Revision: 5030
Author: [email protected]
Date: Wed Jul  7 03:28:22 2010
Log: Prevent invalid pre-parsing data passed in through the API from crashing V8.
Review URL: http://codereview.chromium.org/2876046
http://code.google.com/p/v8/source/detail?r=5030

Modified:
 /branches/bleeding_edge/src/messages.js
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/test/cctest/test-api.cc
 /branches/bleeding_edge/test/mjsunit/fuzz-natives.js

=======================================
--- /branches/bleeding_edge/src/messages.js     Fri Jul  2 07:36:34 2010
+++ /branches/bleeding_edge/src/messages.js     Wed Jul  7 03:28:22 2010
@@ -197,7 +197,8 @@
       obj_ctor_property_non_object: "Object.%0 called on non-object",
       array_indexof_not_defined:    "Array.getIndexOf: Argument undefined",
object_not_extensible: "Can't add property %0, object is not extensible",
-      illegal_access:               "illegal access"
+      illegal_access:               "Illegal access",
+ invalid_preparser_data: "Invalid preparser data for function %0"
     };
   }
   var format = kMessages[message.type];
=======================================
--- /branches/bleeding_edge/src/parser.cc       Tue Jun  8 05:04:49 2010
+++ /branches/bleeding_edge/src/parser.cc       Wed Jul  7 03:28:22 2010
@@ -134,6 +134,7 @@

   // Report syntax error
   void ReportUnexpectedToken(Token::Value token);
+  void ReportInvalidPreparseData(Handle<String> name, bool* ok);

   Handle<Script> script_;
   Scanner scanner_;
@@ -3261,6 +3262,15 @@
     ReportMessage("unexpected_token", Vector<const char*>(&name, 1));
   }
 }
+
+
+void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
+  SmartPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
+  const char* element[1] = { *name_string };
+  ReportMessage("invalid_preparser_data",
+                Vector<const char*>(element, 1));
+  *ok = false;
+}


 Expression* Parser::ParsePrimaryExpression(bool* ok) {
@@ -3810,7 +3820,14 @@
     Handle<FixedArray> this_property_assignments;
     if (is_lazily_compiled && pre_data() != NULL) {
       FunctionEntry entry = pre_data()->GetFunctionEnd(start_pos);
+      if (!entry.is_valid()) {
+        ReportInvalidPreparseData(name, CHECK_OK);
+      }
       int end_pos = entry.end_pos();
+      if (end_pos <= start_pos) {
+ // End position greater than end of stream is safe, and hard to check.
+        ReportInvalidPreparseData(name, CHECK_OK);
+      }
       Counters::total_preparse_skipped.Increment(end_pos - start_pos);
       scanner_.SeekForward(end_pos);
       materialized_literal_count = entry.literal_count();
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc     Fri Jul  2 07:36:34 2010
+++ /branches/bleeding_edge/test/cctest/test-api.cc     Wed Jul  7 03:28:22 2010
@@ -8555,6 +8555,43 @@

   delete sd;
 }
+
+
+// Attempts to deserialize bad data.
+TEST(PreCompileInvalidPreparseDataError) {
+  v8::V8::Initialize();
+  v8::HandleScope scope;
+  LocalContext context;
+
+  const char* script = "function foo(){ return 5;}\n"
+      "function bar(){ return 6 + 7;}  foo();";
+  v8::ScriptData* sd =
+      v8::ScriptData::PreCompile(script, i::StrLength(script));
+  CHECK(!sd->HasError());
+  // ScriptDataImpl private implementation details
+  const int kUnsignedSize = sizeof(unsigned);
+  const int kHeaderSize = 4;
+  const int kFunctionEntrySize = 4;
+  const int kFunctionEntryStartOffset = 0;
+  const int kFunctionEntryEndOffset = 1;
+  unsigned* sd_data =
+      reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
+  CHECK_EQ(sd->Length(),
+           (kHeaderSize + 2 * kFunctionEntrySize) * kUnsignedSize);
+
+  // Overwrite function bar's end position with 0.
+ sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
+  Local<String> source = String::New(script);
+  Local<Script> compiled_script = Script::New(source, NULL, sd);
+
+  // Overwrite function bar's start position with 200.  The function entry
+  // will not be found when searching for it by position.
+ sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
+      200;
+  compiled_script = Script::New(source, NULL, sd);
+
+  delete sd;
+}


// Verifies that the Handle<String> and const char* versions of the API produce
=======================================
--- /branches/bleeding_edge/test/mjsunit/fuzz-natives.js Tue May 4 06:07:36 2010 +++ /branches/bleeding_edge/test/mjsunit/fuzz-natives.js Wed Jul 7 03:28:22 2010
@@ -63,7 +63,7 @@
     try {
       func = makeFunction(name, i);
     } catch (e) {
-      if (e != "SyntaxError: illegal access") throw e;
+      if (e != "SyntaxError: Illegal access") throw e;
     }
     if (func === null && i == argc) {
       throw "unexpected exception";

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to