From: sgjesse@chromium.org Date: Mon, 16 May 2011 08:27:52 +0000 (+0000) Subject: Limit the number of local variables in a function X-Git-Tag: upstream/4.7.83~19411 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=230a56abda91307155b32179ed52825962174352;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/messages.js b/src/messages.js index 14cedec9d..798335022 100644 --- a/src/messages.js +++ b/src/messages.js @@ -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"], diff --git a/src/parser.cc b/src/parser.cc index 683854138..d5353c70b 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1309,7 +1309,7 @@ VariableProxy* Parser::Declare(Handle 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::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 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) { diff --git a/src/parser.h b/src/parser.h index d420d0302..01cf61112 100644 --- a/src/parser.h +++ b/src/parser.h @@ -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); diff --git a/src/scopes.cc b/src/scopes.cc index 7eadab015..61024426e 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -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 name) { } -Variable* Scope::DeclareLocal(Handle name, Variable::Mode mode) { +Variable* Scope::DeclareLocal(Handle 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); } diff --git a/src/scopes.h b/src/scopes.h index 44688ae06..faa6fd97e 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -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 name, Variable::Mode mode); + virtual Variable* DeclareLocal(Handle 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); + // 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 index 000000000..ad9ec4368 --- /dev/null +++ b/test/mjsunit/limit-locals.js @@ -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)");