Skip to content

Commit

Permalink
JS: don't convert \0,\x00,\u0000 to literal NULL as it breaks RegExp;…
Browse files Browse the repository at this point in the history
… convert \x00,\u0000 to \0 only if it can't possibly be an octal escape sequence (see #577); fixes #585
  • Loading branch information
tdewolff committed Jun 19, 2023
1 parent 9e03d97 commit bf2187d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 23 deletions.
11 changes: 6 additions & 5 deletions js/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,10 @@ func TestJS(t *testing.T) {
{`"string\t\f\v\bstring"`, "\"string\t\f\v\bstring\""},
{`"string\a\c\'string"`, `"stringac'string"`},
{`"string\∀string"`, `"string∀string"`},
{`"string\0\uFFFFstring"`, "\"string\x00￿string\""},
{`"string\x00\x55\x0A\x0D\x22\x27string"`, "\"string\x00U\\n\\r\\\"'string\""},
{`"string\000\12\015\042\47\411string"`, "\"string\x00\\n\\r\\\"'!1string\""},
{`"string\0\uFFFFstring"`, "\"string\\0\uffffstring\""},
{`"string\x00\x55\x0A\x0D\x22\x27string"`, `"string\x00U\n\r\"'string"`},
{`"string\000\12\015\042\47\411string"`, "\"string\\0\\n\\r\\\"'!1string\""},
{`"\x005"`, `"\x005"`},
{"'string\\n\\rstring'", "`string\n\rstring`"},
{"'string\\\r\nstring\\\nstring\\\rstring\\\u2028string\\\u2029string'", `"stringstringstringstringstringstring"`},
{`"\x7H\u877H"`, `"\x7H\u877H"`},
Expand Down Expand Up @@ -796,8 +797,8 @@ func TestJS(t *testing.T) {
{`var a=5;({});var b=class{c(){3}}`, `var b,a=5;({},b=class{c(){3}})`}, // #494
{`({});a={b(){3}}`, `({},a={b(){3}})`}, // #494
{`export default function Foo(){a}Foo.prototype.bar=b`, `export default function Foo(){a}Foo.prototype.bar=b`}, // #525
{`(e=1,e=2)`, `e=1,e=2`}, // #528
{`"\x00\x31 \0\u0000"`, "\"\x001 \x00\x00\""}, // #577
{`(e=1,e=2)`, `e=1,e=2`}, // #528
{`"\x00\x31 \0\u0000"`, `"\x001 \0\x00"`}, // #577
}

m := minify.New()
Expand Down
47 changes: 29 additions & 18 deletions js/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ func replaceEscapes(b []byte, quote byte, prefix, suffix int) []byte {
for i := prefix; i < len(b)-suffix; i++ {
if c := b[i]; c == '\\' {
c = b[i+1]
if c == quote || c == '\\' || quote != '`' && (c == 'n' || c == 'r') {
if c == quote || c == '\\' || quote != '`' && (c == 'n' || c == 'r') || c == '0' && (i+2 == len(b)-1 || b[i+2] < '0' || '7' < b[i+2]) {
// keep escape sequence
i++
continue
Expand All @@ -999,11 +999,12 @@ func replaceEscapes(b []byte, quote byte, prefix, suffix int) []byte {
n = 2
}
} else if c == 'x' {
if i+3 < len(b)-1 && isHexDigit(b[i+2]) && b[i+2] < '8' && isHexDigit(b[i+3]) {
if i+3 < len(b)-1 && isHexDigit(b[i+2]) && b[i+2] < '8' && isHexDigit(b[i+3]) && (!(b[i+2] == '0' && b[i+3] == '0') || i+3 == len(b) || b[i+3] != '\\' && (b[i+3] < '0' && '7' < b[i+3])) {
// don't convert \x00 to \0 if it may be an octal number
// hexadecimal escapes
_, _ = hex.Decode(b[i+3:i+4:i+4], b[i+2:i+4])
n = 3
if b[i+3] == '\\' || b[i+3] == quote || b[i+3] == '\n' || b[i+3] == '\r' {
if b[i+3] == '\\' || b[i+3] == quote || b[i+3] == '\n' || b[i+3] == '\r' || b[i+3] == 0 {
if b[i+3] == '\n' {
b[i+3] = 'n'
} else if b[i+3] == '\r' {
Expand Down Expand Up @@ -1037,22 +1038,32 @@ func replaceEscapes(b []byte, quote byte, prefix, suffix int) []byte {
continue
}

// decode unicode character to UTF-8 and put at the end of the escape sequence
// then skip the first part of the escape sequence until the decoded character
n = 2 + r - l
if b[i+2] == '{' {
n += 2
}
m := utf8.RuneLen(rune(num))
if m == -1 {
i++
continue
if num == 0 {
// don't convert NULL to literal NULL (gives JS parsing problems)
if r == len(b) || b[r] != '\\' && (b[r] < '0' && '7' < b[r]) {
b[r-2] = '\\'
n = r - l
} else {
// don't convert NULL to \0 (may be an octal number)
b[r-4] = '\\'
b[r-3] = 'x'
n = r - l - 2
}
} else {
// decode unicode character to UTF-8 and put at the end of the escape sequence
// then skip the first part of the escape sequence until the decoded character
n = 2 + r - l
if b[i+2] == '{' {
n += 2
}
m := utf8.RuneLen(rune(num))
if m == -1 {
i++
continue
}
utf8.EncodeRune(b[i+n-m:], rune(num))
n -= m
}
utf8.EncodeRune(b[i+n-m:], rune(num))
n -= m
} else if c == '0' && (i+2 == len(b)-1 || b[i+2] < '0' || '7' < b[i+2]) {
// \0 (NULL)
b[i+1] = '\x00'
} else if '0' <= c && c <= '7' {
// octal escapes (legacy), \0 already handled
num := c - '0'
Expand Down

0 comments on commit bf2187d

Please sign in to comment.