Commit 230a56ab authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Limit the number of local variables in a function

Review URL: http://codereview.chromium.org//7003030

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7892 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c5ff1f21
...@@ -214,7 +214,8 @@ function FormatMessage(message) { ...@@ -214,7 +214,8 @@ function FormatMessage(message) {
invalid_preparser_data: ["Invalid preparser data for function ", "%0"], invalid_preparser_data: ["Invalid preparser data for function ", "%0"],
strict_mode_with: ["Strict mode code may not include a with statement"], 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"], 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_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_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"], strict_var_name: ["Variable name may not be eval or arguments in strict mode"],
......
...@@ -1309,7 +1309,7 @@ VariableProxy* Parser::Declare(Handle<String> name, ...@@ -1309,7 +1309,7 @@ VariableProxy* Parser::Declare(Handle<String> name,
var = top_scope_->LocalLookup(name); var = top_scope_->LocalLookup(name);
if (var == NULL) { if (var == NULL) {
// Declare the name. // Declare the name.
var = top_scope_->DeclareLocal(name, mode); var = top_scope_->DeclareLocal(name, mode, Scope::VAR_OR_CONST);
} else { } else {
// The name was declared before; check for conflicting // The name was declared before; check for conflicting
// re-declarations. If the previous declaration was a const or the // re-declarations. If the previous declaration was a const or the
...@@ -1581,6 +1581,12 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, ...@@ -1581,6 +1581,12 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
is_const /* always bound for CONST! */, is_const /* always bound for CONST! */,
CHECK_OK); CHECK_OK);
nvars++; 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 // Parse initialization expression if present and/or needed. A
// declaration of the form: // declaration of the form:
...@@ -3564,7 +3570,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, ...@@ -3564,7 +3570,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
reserved_loc = scanner().location(); 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); top_scope_->AddParameter(parameter);
num_parameters++; num_parameters++;
if (num_parameters > kMaxNumFunctionParameters) { if (num_parameters > kMaxNumFunctionParameters) {
......
...@@ -449,6 +449,7 @@ class Parser { ...@@ -449,6 +449,7 @@ class Parser {
// construct a hashable id, so if more than 2^17 are allowed, this // construct a hashable id, so if more than 2^17 are allowed, this
// should be checked. // should be checked.
static const int kMaxNumFunctionParameters = 32766; static const int kMaxNumFunctionParameters = 32766;
static const int kMaxNumFunctionLocals = 32767;
FunctionLiteral* ParseLazy(CompilationInfo* info, FunctionLiteral* ParseLazy(CompilationInfo* info,
UC16CharacterStream* source, UC16CharacterStream* source,
ZoneScope* zone_scope); ZoneScope* zone_scope);
......
...@@ -203,6 +203,7 @@ void Scope::SetDefaults(Type type, ...@@ -203,6 +203,7 @@ void Scope::SetDefaults(Type type,
inner_scope_calls_eval_ = false; inner_scope_calls_eval_ = false;
outer_scope_is_eval_scope_ = false; outer_scope_is_eval_scope_ = false;
force_eager_compilation_ = false; force_eager_compilation_ = false;
num_var_or_const_ = 0;
num_stack_slots_ = 0; num_stack_slots_ = 0;
num_heap_slots_ = 0; num_heap_slots_ = 0;
scope_info_ = scope_info; scope_info_ = scope_info;
...@@ -365,12 +366,17 @@ Variable* Scope::DeclareFunctionVar(Handle<String> name) { ...@@ -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, // DYNAMIC variables are introduces during variable allocation,
// INTERNAL variables are allocated explicitly, and TEMPORARY // INTERNAL variables are allocated explicitly, and TEMPORARY
// variables are allocated via NewTemporary(). // variables are allocated via NewTemporary().
ASSERT(!resolved()); ASSERT(!resolved());
ASSERT(mode == Variable::VAR || mode == Variable::CONST); 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); return variables_.Declare(this, name, mode, true, Variable::NORMAL);
} }
......
...@@ -95,6 +95,11 @@ class Scope: public ZoneObject { ...@@ -95,6 +95,11 @@ class Scope: public ZoneObject {
GLOBAL_SCOPE // the top-level scope for a program or a top-level eval 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); Scope(Scope* outer_scope, Type type);
virtual ~Scope() { } virtual ~Scope() { }
...@@ -134,7 +139,9 @@ class Scope: public ZoneObject { ...@@ -134,7 +139,9 @@ class Scope: public ZoneObject {
// Declare a local variable in this scope. If the variable has been // Declare a local variable in this scope. If the variable has been
// declared before, the previously declared variable is returned. // 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 // Declare an implicit global variable in this scope which must be a
// global scope. The variable was introduced (possibly from an inner // global scope. The variable was introduced (possibly from an inner
...@@ -288,6 +295,9 @@ class Scope: public ZoneObject { ...@@ -288,6 +295,9 @@ class Scope: public ZoneObject {
// cases the context parameter is an empty handle. // cases the context parameter is an empty handle.
void AllocateVariables(Handle<Context> context); 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. // Result of variable allocation.
int num_stack_slots() const { return num_stack_slots_; } int num_stack_slots() const { return num_stack_slots_; }
int num_heap_slots() const { return num_heap_slots_; } int num_heap_slots() const { return num_heap_slots_; }
...@@ -380,6 +390,9 @@ class Scope: public ZoneObject { ...@@ -380,6 +390,9 @@ class Scope: public ZoneObject {
bool outer_scope_is_eval_scope_; bool outer_scope_is_eval_scope_;
bool force_eager_compilation_; bool force_eager_compilation_;
// Computed as variables are declared.
int num_var_or_const_;
// Computed via AllocateVariables; function scopes only. // Computed via AllocateVariables; function scopes only.
int num_stack_slots_; int num_stack_slots_;
int num_heap_slots_; int num_heap_slots_;
......
// 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)");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment