Limit the number of local variables in a function
authorsgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 16 May 2011 08:27:52 +0000 (08:27 +0000)
committersgjesse@chromium.org <sgjesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 16 May 2011 08:27:52 +0000 (08:27 +0000)
Review URL: http://codereview.chromium.org//7003030

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7892 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/messages.js
src/parser.cc
src/parser.h
src/scopes.cc
src/scopes.h
test/mjsunit/limit-locals.js [new file with mode: 0644]

index 14cedec9d8735d066b09a8636f7f10faa0c31316..7983350225cc103b8f18c2ce4a48f6c4e1e310f3 100644 (file)
@@ -214,7 +214,8 @@ function FormatMessage(message) {
       invalid_preparser_data:       ["Invalid preparser data for function ", "%0"],
       strict_mode_with:             ["Strict mode code may not include a with statement"],
       strict_catch_variable:        ["Catch variable may not be eval or arguments in strict mode"],
-      too_many_parameters:          ["Too many parameters in function definition"],
+      too_many_parameters:          ["Too many parameters in function definition (only 32766 allowed)"],
+      too_many_variables:           ["Too many variables declared (only 32767 allowed)"],
       strict_param_name:            ["Parameter name eval or arguments is not allowed in strict mode"],
       strict_param_dupe:            ["Strict mode function may not have duplicate parameter names"],
       strict_var_name:              ["Variable name may not be eval or arguments in strict mode"],
index 683854138161b49a7879b7c750b9239520fe80c9..d5353c70b255b84ddbb41741b677f148a70a32d8 100644 (file)
@@ -1309,7 +1309,7 @@ VariableProxy* Parser::Declare(Handle<String> name,
     var = top_scope_->LocalLookup(name);
     if (var == NULL) {
       // Declare the name.
-      var = top_scope_->DeclareLocal(name, mode);
+      var = top_scope_->DeclareLocal(name, mode, Scope::VAR_OR_CONST);
     } else {
       // The name was declared before; check for conflicting
       // re-declarations. If the previous declaration was a const or the
@@ -1581,6 +1581,12 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
                        is_const /* always bound for CONST! */,
                        CHECK_OK);
     nvars++;
+    if (top_scope_->num_var_or_const() > kMaxNumFunctionLocals) {
+      ReportMessageAt(scanner().location(), "too_many_variables",
+                      Vector<const char*>::empty());
+      *ok = false;
+      return NULL;
+    }
 
     // Parse initialization expression if present and/or needed. A
     // declaration of the form:
@@ -3564,7 +3570,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
         reserved_loc = scanner().location();
       }
 
-      Variable* parameter = top_scope_->DeclareLocal(param_name, Variable::VAR);
+      Variable* parameter = top_scope_->DeclareLocal(param_name,
+                                                     Variable::VAR,
+                                                     Scope::PARAMETER);
       top_scope_->AddParameter(parameter);
       num_parameters++;
       if (num_parameters > kMaxNumFunctionParameters) {
index d420d030259d203611dd3b73f7c9f96506c70e30..01cf61112ead0da42b02f662166b9cfc3432dbc4 100644 (file)
@@ -449,6 +449,7 @@ class Parser {
   // construct a hashable id, so if more than 2^17 are allowed, this
   // should be checked.
   static const int kMaxNumFunctionParameters = 32766;
+  static const int kMaxNumFunctionLocals = 32767;
   FunctionLiteral* ParseLazy(CompilationInfo* info,
                              UC16CharacterStream* source,
                              ZoneScope* zone_scope);
index 7eadab0152c8ab8bf165f233d2c806d58646179e..61024426e3ca9b76545e25b3b5ef373733f2697a 100644 (file)
@@ -203,6 +203,7 @@ void Scope::SetDefaults(Type type,
   inner_scope_calls_eval_ = false;
   outer_scope_is_eval_scope_ = false;
   force_eager_compilation_ = false;
+  num_var_or_const_ = 0;
   num_stack_slots_ = 0;
   num_heap_slots_ = 0;
   scope_info_ = scope_info;
@@ -365,12 +366,17 @@ Variable* Scope::DeclareFunctionVar(Handle<String> name) {
 }
 
 
-Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
+Variable* Scope::DeclareLocal(Handle<String> name,
+                              Variable::Mode mode,
+                              LocalType type) {
   // DYNAMIC variables are introduces during variable allocation,
   // INTERNAL variables are allocated explicitly, and TEMPORARY
   // variables are allocated via NewTemporary().
   ASSERT(!resolved());
   ASSERT(mode == Variable::VAR || mode == Variable::CONST);
+  if (type == VAR_OR_CONST) {
+    num_var_or_const_++;
+  }
   return variables_.Declare(this, name, mode, true, Variable::NORMAL);
 }
 
index 44688ae0682d85a575676de62a1e486477c4cd05..faa6fd97efd95dc5ad859a7363d32c59acd8a180 100644 (file)
@@ -95,6 +95,11 @@ class Scope: public ZoneObject {
     GLOBAL_SCOPE    // the top-level scope for a program or a top-level eval
   };
 
+  enum LocalType {
+    PARAMETER,
+    VAR_OR_CONST
+  };
+
   Scope(Scope* outer_scope, Type type);
 
   virtual ~Scope() { }
@@ -134,7 +139,9 @@ class Scope: public ZoneObject {
 
   // Declare a local variable in this scope. If the variable has been
   // declared before, the previously declared variable is returned.
-  virtual Variable* DeclareLocal(Handle<String> name, Variable::Mode mode);
+  virtual Variable* DeclareLocal(Handle<String> name,
+                                 Variable::Mode mode,
+                                 LocalType type);
 
   // Declare an implicit global variable in this scope which must be a
   // global scope.  The variable was introduced (possibly from an inner
@@ -288,6 +295,9 @@ class Scope: public ZoneObject {
   // cases the context parameter is an empty handle.
   void AllocateVariables(Handle<Context> context);
 
+  // Current number of var or const locals.
+  int num_var_or_const() { return num_var_or_const_; }
+
   // Result of variable allocation.
   int num_stack_slots() const { return num_stack_slots_; }
   int num_heap_slots() const { return num_heap_slots_; }
@@ -380,6 +390,9 @@ class Scope: public ZoneObject {
   bool outer_scope_is_eval_scope_;
   bool force_eager_compilation_;
 
+  // Computed as variables are declared.
+  int num_var_or_const_;
+
   // Computed via AllocateVariables; function scopes only.
   int num_stack_slots_;
   int num_heap_slots_;
diff --git a/test/mjsunit/limit-locals.js b/test/mjsunit/limit-locals.js
new file mode 100644 (file)
index 0000000..ad9ec43
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that there is a limit of 32767 locals.
+
+function function_with_n_locals(n) {
+  test_prefix = "prefix ";
+  test_suffix = " suffix";
+  var src = "test_prefix + (function () {"
+  for (var i = 1; i <= n; i++) {
+    src += "var x" + i + ";";
+  }
+  src += "return " + n + ";})() + test_suffix";
+  return eval(src);
+}
+
+assertEquals("prefix 0 suffix", function_with_n_locals(0));
+assertEquals("prefix 16000 suffix", function_with_n_locals(16000));
+assertEquals("prefix 32767 suffix", function_with_n_locals(32767));
+
+assertThrows("function_with_n_locals(32768)");
+assertThrows("function_with_n_locals(100000)");