From 050aaa40f8e690149c1f4c19999b17c54a66d4e8 Mon Sep 17 00:00:00 2001 From: Julian Rosse Date: Thu, 6 Apr 2017 19:39:13 -0400 Subject: [PATCH] Fix #4489: Regex octal escape sequence bug --- lib/coffee-script/lexer.js | 14 +++++++------- src/lexer.coffee | 18 +++++++++++++++--- test/error_messages.coffee | 7 +++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index c87dc96349..ef2737b4d8 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.12.4 (function() { - var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, + var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, HERE_JSTOKEN, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVERSES, JSTOKEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, REGEX_INVALID_ESCAPE, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_INVALID_ESCAPE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, isForFrom, isUnassignable, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, slice = [].slice; @@ -868,18 +868,16 @@ }; Lexer.prototype.validateEscapes = function(str, options) { - var before, hex, invalidEscape, match, message, octal, ref2, unicode; + var before, hex, invalidEscape, invalid_escape_regex, match, message, octal, ref2, unicode; if (options == null) { options = {}; } - match = INVALID_ESCAPE.exec(str); + invalid_escape_regex = options.isRegex ? REGEX_INVALID_ESCAPE : STRING_INVALID_ESCAPE; + match = invalid_escape_regex.exec(str); if (!match) { return; } match[0], before = match[1], octal = match[2], hex = match[3], unicode = match[4]; - if (options.isRegex && octal && octal.charAt(0) !== '0') { - return; - } message = octal ? "octal escape sequences are not allowed" : "invalid escape sequence"; invalidEscape = "\\" + (octal || hex || unicode); return this.error(message + " " + invalidEscape, { @@ -1067,7 +1065,9 @@ LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/; - INVALID_ESCAPE = /((?:^|[^\\])(?:\\\\)*)\\(?:(0[0-7]|[1-7])|(x(?![\da-fA-F]{2}).{0,2})|(u(?![\da-fA-F]{4}).{0,4}))/; + STRING_INVALID_ESCAPE = /((?:^|[^\\])(?:\\\\)*)\\(?:(0[0-7]|[1-7])|(x(?![\da-fA-F]{2}).{0,2})|(u(?![\da-fA-F]{4}).{0,4}))/; + + REGEX_INVALID_ESCAPE = /((?:^|[^\\])(?:\\\\)*)\\(?:(0[0-7])|(x(?![\da-fA-F]{2}).{0,2})|(u(?![\da-fA-F]{4}).{0,4}))/; LEADING_BLANK_LINE = /^[^\n\S]*\n/; diff --git a/src/lexer.coffee b/src/lexer.coffee index df10eaa98b..7848c70661 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -763,10 +763,14 @@ exports.Lexer = class Lexer # Validates escapes in strings and regexes. validateEscapes: (str, options = {}) -> - match = INVALID_ESCAPE.exec str + invalid_escape_regex = + if options.isRegex + REGEX_INVALID_ESCAPE + else + STRING_INVALID_ESCAPE + match = invalid_escape_regex.exec str return unless match [[], before, octal, hex, unicode] = match - return if options.isRegex and octal and octal.charAt(0) isnt '0' message = if octal "octal escape sequences are not allowed" @@ -978,7 +982,7 @@ HERECOMMENT_ILLEGAL = /\*\// LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?![.\d]) | :: ) /// -INVALID_ESCAPE = /// +STRING_INVALID_ESCAPE = /// ( (?:^|[^\\]) (?:\\\\)* ) # make sure the escape isn’t escaped \\ ( ?: (0[0-7]|[1-7]) # octal escape @@ -986,6 +990,14 @@ INVALID_ESCAPE = /// | (u(?![\da-fA-F]{4}).{0,4}) # unicode escape ) /// +REGEX_INVALID_ESCAPE = /// + ( (?:^|[^\\]) (?:\\\\)* ) # make sure the escape isn’t escaped + \\ ( + ?: (0[0-7]) # octal escape + | (x(?![\da-fA-F]{2}).{0,2}) # hex escape + | (u(?![\da-fA-F]{4}).{0,4}) # unicode escape + ) +/// LEADING_BLANK_LINE = /^[^\n\S]*\n/ TRAILING_BLANK_LINE = /\n[^\n\S]*$/ diff --git a/test/error_messages.coffee b/test/error_messages.coffee index e3a07e98c7..3e33db5e57 100644 --- a/test/error_messages.coffee +++ b/test/error_messages.coffee @@ -456,6 +456,13 @@ test "octal escapes", -> /a\\0\\tb\\\\\\07c/ \ \ \ \ ^\^^ ''' + assertErrorFormat ''' + /a\\1\\tb\\\\\\07c/ + ''', ''' + [stdin]:1:10: error: octal escape sequences are not allowed \\07 + /a\\1\\tb\\\\\\07c/ + \ \ \ \ ^\^^ + ''' assertErrorFormat ''' ///a #{b} \\01///