Issue #1547 'use strict' eval and arguments use restricted
This commit is contained in:
parent
0b7cfba94a
commit
8b179fb391
|
@ -106,7 +106,7 @@ exports.Lexer = class Lexer
|
|||
@tokens.pop()
|
||||
id = '!' + id
|
||||
|
||||
if id in ['eval', 'arguments'].concat JS_FORBIDDEN
|
||||
if id in JS_FORBIDDEN
|
||||
if forcedIdentifier
|
||||
tag = 'IDENTIFIER'
|
||||
id = new String id
|
||||
|
@ -576,11 +576,14 @@ RESERVED = [
|
|||
'private', 'protected', 'public', 'static', 'yield'
|
||||
]
|
||||
|
||||
STRICT_PROSCRIBED = ['arguments', 'eval']
|
||||
|
||||
# The superset of both JavaScript keywords and reserved words, none of which may
|
||||
# be used as identifiers or properties.
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat RESERVED
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED)
|
||||
|
||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS)
|
||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED)
|
||||
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED
|
||||
|
||||
# Token matching regexes.
|
||||
IDENTIFIER = /// ^
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# the syntax tree into a string of JavaScript code, call `compile()` on the root.
|
||||
|
||||
{Scope} = require './scope'
|
||||
{RESERVED} = require './lexer'
|
||||
{RESERVED, STRICT_PROSCRIBED} = require './lexer'
|
||||
|
||||
# Import the helpers we plan to use.
|
||||
{compact, flatten, extend, merge, del, starts, ends, last} = require './helpers'
|
||||
|
@ -329,7 +329,7 @@ exports.Literal = class Literal extends Base
|
|||
if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'
|
||||
else if @value is 'this'
|
||||
if o.scope.method?.bound then o.scope.method.context else @value
|
||||
else if @value.reserved and "#{@value}" not in ['eval', 'arguments']
|
||||
else if @value.reserved
|
||||
"\"#{@value}\""
|
||||
else
|
||||
@value
|
||||
|
@ -862,6 +862,8 @@ exports.Class = class Class extends Base
|
|||
tail instanceof Access and tail.name.value
|
||||
else
|
||||
@variable.base.value
|
||||
if decl in STRICT_PROSCRIBED
|
||||
throw SyntaxError 'variable name may not be eval or arguments'
|
||||
decl and= IDENTIFIER.test(decl) and decl
|
||||
|
||||
# For all `this`-references and bound functions in the class definition,
|
||||
|
@ -990,6 +992,8 @@ exports.Assign = class Assign extends Base
|
|||
constructor: (@variable, @value, @context, options) ->
|
||||
@param = options and options.param
|
||||
@subpattern = options and options.subpattern
|
||||
if @variable.unwrapAll().value in STRICT_PROSCRIBED
|
||||
throw SyntaxError 'variable name may not be "eval" or "arguments"'
|
||||
|
||||
children: ['variable', 'value']
|
||||
|
||||
|
@ -1055,7 +1059,7 @@ exports.Assign = class Assign extends Base
|
|||
acc = IDENTIFIER.test idx.unwrap().value or 0
|
||||
value = new Value value
|
||||
value.properties.push new (if acc then Access else Index) idx
|
||||
if obj.unwrap().value in ['arguments','eval'].concat RESERVED
|
||||
if obj.unwrap().value in RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}"
|
||||
return new Assign(obj, value, null, param: @param).compile o, LEVEL_TOP
|
||||
vvar = value.compile o, LEVEL_LIST
|
||||
|
@ -1100,7 +1104,7 @@ exports.Assign = class Assign extends Base
|
|||
else
|
||||
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
|
||||
val = new Value new Literal(vvar), [new (if acc then Access else Index) idx]
|
||||
if name? and name in ['arguments','eval'].concat RESERVED
|
||||
if name? and name in RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}"
|
||||
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compile o, LEVEL_LIST
|
||||
assigns.push vvar unless top or @subpattern
|
||||
|
@ -1224,6 +1228,8 @@ exports.Code = class Code extends Base
|
|||
# as well as be a splat, gathering up a group of parameters into an array.
|
||||
exports.Param = class Param extends Base
|
||||
constructor: (@name, @value, @splat) ->
|
||||
if @name.unwrapAll().value in STRICT_PROSCRIBED
|
||||
throw SyntaxError 'parameter name eval or arguments is not allowed'
|
||||
|
||||
children: ['name', 'value']
|
||||
|
||||
|
@ -1575,6 +1581,8 @@ exports.Try = class Try extends Base
|
|||
tryPart = @attempt.compile o, LEVEL_TOP
|
||||
|
||||
catchPart = if @recovery
|
||||
if @error.value in STRICT_PROSCRIBED
|
||||
throw SyntaxError "catch variable may not be eval or arguments"
|
||||
o.scope.add @error.value, 'param' unless o.scope.check @error.value
|
||||
" catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
|
||||
else unless @ensure or @recovery
|
||||
|
|
|
@ -100,32 +100,50 @@ test "`delete` operand restrictions", ->
|
|||
strict '([a]) -> delete a'
|
||||
strict '({a}) -> delete a'
|
||||
|
||||
test "`Future Reserved Word`s as identifiers prohibited", ->
|
||||
futures = 'implements interface let package private protected public static yield'.split ' '
|
||||
for keyword in futures
|
||||
strict "#{keyword} = 1"
|
||||
strict "class #{keyword}"
|
||||
strict "try new Error catch #{keyword}"
|
||||
strict "(#{keyword}) ->"
|
||||
strict "{keyword}++"
|
||||
strict "++{keyword}"
|
||||
strict "{keyword}--"
|
||||
strict "--{keyword}"
|
||||
|
||||
test "`eval` and `arguments` use restricted", ->
|
||||
proscribeds = 'eval arguments'.split ' '
|
||||
for proscribed in proscribeds
|
||||
strict "#{proscribed} = 1"
|
||||
strict "class #{proscribed}"
|
||||
strict "try new Error catch #{proscribed}"
|
||||
strict "(#{proscribed}) ->"
|
||||
strict "{proscribed}++"
|
||||
strict "++{proscribed}"
|
||||
strict "{proscribed}--"
|
||||
strict "--{proscribed}"
|
||||
strictOk "eval 'true'"
|
||||
strictOk "-> arguments[0]"
|
||||
|
||||
test "`Future Reserved Word`s, `eval` and `arguments` restrictions", ->
|
||||
|
||||
access = (keyword, check = strict) ->
|
||||
check "#{keyword}.a = 1"
|
||||
check "#{keyword}[0] = 1"
|
||||
assign = (keyword, check = strict) ->
|
||||
check "#{keyword} = 1"
|
||||
check "#{keyword} += 1"
|
||||
check "#{keyword} -= 1"
|
||||
check "#{keyword} *= 1"
|
||||
check "#{keyword} /= 1"
|
||||
check "#{keyword} ?= 1"
|
||||
check "{keyword}++"
|
||||
check "++{keyword}"
|
||||
check "{keyword}--"
|
||||
check "--{keyword}"
|
||||
invoke = (keyword, check = strict) ->
|
||||
check "#{keyword} yes"
|
||||
check "do #{keyword}"
|
||||
fnDecl = (keyword, check = strict) ->
|
||||
check "class #{keyword}"
|
||||
param = (keyword, check = strict) ->
|
||||
check "(#{keyword}) ->"
|
||||
check "({#{keyword}}) ->"
|
||||
prop = (keyword, check = strict) ->
|
||||
check "a.#{keyword} = 1"
|
||||
tryCatch = (keyword, check = strict) ->
|
||||
check "try new Error catch #{keyword}"
|
||||
|
||||
future = 'implements interface let package private protected public static yield'.split ' '
|
||||
for keyword in future
|
||||
access keyword
|
||||
assign keyword
|
||||
invoke keyword
|
||||
fnDecl keyword
|
||||
param keyword
|
||||
prop keyword, strictOk
|
||||
tryCatch keyword
|
||||
|
||||
for keyword in ['eval', 'arguments']
|
||||
access keyword, strictOk
|
||||
assign keyword
|
||||
invoke keyword, strictOk
|
||||
fnDecl keyword
|
||||
param keyword
|
||||
prop keyword, strictOk
|
||||
tryCatch keyword
|
||||
|
|
Loading…
Reference in New Issue