Revision: 7892
Author: [email protected]
Date: Mon May 16 01:27:52 2011
Log: Limit the number of local variables in a function
Review URL: http://codereview.chromium.org//7003030
http://code.google.com/p/v8/source/detail?r=7892
Added:
/branches/bleeding_edge/test/mjsunit/limit-locals.js
Modified:
/branches/bleeding_edge/src/messages.js
/branches/bleeding_edge/src/parser.cc
/branches/bleeding_edge/src/parser.h
/branches/bleeding_edge/src/scopes.cc
/branches/bleeding_edge/src/scopes.h
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/limit-locals.js Mon May 16
01:27:52 2011
@@ -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)");
=======================================
--- /branches/bleeding_edge/src/messages.js Wed May 4 22:21:30 2011
+++ /branches/bleeding_edge/src/messages.js Mon May 16 01:27:52 2011
@@ -214,7 +214,8 @@
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"],
=======================================
--- /branches/bleeding_edge/src/parser.cc Wed May 11 04:56:15 2011
+++ /branches/bleeding_edge/src/parser.cc Mon May 16 01:27:52 2011
@@ -1309,7 +1309,7 @@
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 @@
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 @@
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) {
=======================================
--- /branches/bleeding_edge/src/parser.h Wed May 11 04:56:15 2011
+++ /branches/bleeding_edge/src/parser.h Mon May 16 01:27:52 2011
@@ -449,6 +449,7 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/scopes.cc Wed May 11 04:26:11 2011
+++ /branches/bleeding_edge/src/scopes.cc Mon May 16 01:27:52 2011
@@ -203,6 +203,7 @@
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::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);
}
=======================================
--- /branches/bleeding_edge/src/scopes.h Wed May 11 04:26:11 2011
+++ /branches/bleeding_edge/src/scopes.h Mon May 16 01:27:52 2011
@@ -95,6 +95,11 @@
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 @@
// 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
@@ -287,6 +294,9 @@
// parameter is the context in which eval was called. In all other
// 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_; }
@@ -380,6 +390,9 @@
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_;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev