Browse Source

Make JsonParser escape character parsing more strict (#1161)

Genteure 3 years ago
parent
commit
b07562e6de
2 changed files with 36 additions and 66 deletions
  1. 2 1
      Jint.Tests/Runtime/JsonTests.cs
  2. 34 65
      Jint/Native/Json/JsonParser.cs

+ 2 - 1
Jint.Tests/Runtime/JsonTests.cs

@@ -45,7 +45,7 @@ namespace Jint.Tests.Runtime
         [InlineData("{true}", "Unexpected token 'true' in JSON at position 1")]
         [InlineData("{null}", "Unexpected token 'null' in JSON at position 1")]
         [InlineData("{:}", "Unexpected token ':' in JSON at position 1")]
-        [InlineData("\"\\xah\"", "Expected hexadecimal digit in JSON at position 4")]
+        [InlineData("\"\\uah\"", "Expected hexadecimal digit in JSON at position 4")]
         [InlineData("0123", "Unexpected token '1' in JSON at position 1")]  // leading 0 (octal number) not allowed
         [InlineData("1e+A", "Unexpected token 'A' in JSON at position 3")]
         [InlineData("truE", "Unexpected token 'tru' in JSON at position 0")]
@@ -55,6 +55,7 @@ namespace Jint.Tests.Runtime
         [InlineData("alpha", "Unexpected token 'a' in JSON at position 0")]
         [InlineData("[1,\na]", "Unexpected token 'a' in JSON at position 4")] // multiline
         [InlineData("\x06", "Unexpected token '\x06' in JSON at position 0")] // control char
+        [InlineData("{\"\\v\":1}", "Unexpected token 'v' in JSON at position 3")] // invalid escape sequence
         public void ShouldReportHelpfulSyntaxErrorForInvalidJson(string json, string expectedMessage)
         {
             var engine = new Engine();

+ 34 - 65
Jint/Native/Json/JsonParser.cs

@@ -83,12 +83,11 @@ namespace Jint.Native.Json
                 ;
         }
 
-        private char ScanHexEscape(char prefix)
+        private char ScanHexEscape()
         {
             int code = char.MinValue;
 
-            int len = (prefix == 'u') ? 4 : 2;
-            for (int i = 0; i < len; ++i)
+            for (int i = 0; i < 4; ++i)
             {
                 if (_index < _length && IsHexDigit(_source.CharCodeAt(_index)))
                 {
@@ -100,7 +99,7 @@ namespace Jint.Native.Json
                     ThrowError(_index, Messages.ExpectedHexadecimalDigit);
                 }
             }
-            return (char)code;
+            return (char) code;
         }
 
         private void SkipWhiteSpace()
@@ -320,68 +319,38 @@ namespace Jint.Native.Json
                 {
                     ch = _source.CharCodeAt(_index++);
 
-                    if (ch > 0 || !IsLineTerminator(ch))
+                    switch (ch)
                     {
-                        switch (ch)
-                        {
-                            case 'n':
-                                sb.Append('\n');
-                                break;
-                            case 'r':
-                                sb.Append('\r');
-                                break;
-                            case 't':
-                                sb.Append('\t');
-                                break;
-                            case 'u':
-                            case 'x':
-                                char unescaped = ScanHexEscape(ch);
-                                sb.Append(unescaped);
-                                break;
-                            case 'b':
-                                sb.Append('\b');
-                                break;
-                            case 'f':
-                                sb.Append('\f');
-                                break;
-                            case 'v':
-                                sb.Append('\x0B');
-                                break;
-
-                            default:
-                                if (IsOctalDigit(ch))
-                                {
-                                    int code = "01234567".IndexOf(ch);
-
-                                    if (_index < _length && IsOctalDigit(_source.CharCodeAt(_index)))
-                                    {
-                                        code = code * 8 + "01234567".IndexOf(_source.CharCodeAt(_index++));
-
-                                        // 3 digits are only allowed when string starts
-                                        // with 0, 1, 2, 3
-                                        if ("0123".IndexOf(ch) >= 0 &&
-                                            _index < _length &&
-                                            IsOctalDigit(_source.CharCodeAt(_index)))
-                                        {
-                                            code = code * 8 + "01234567".IndexOf(_source.CharCodeAt(_index++));
-                                        }
-                                    }
-                                    sb.Append(((char)code).ToString());
-                                }
-                                else
-                                {
-                                    sb.Append(ch.ToString());
-                                }
-                                break;
-                        }
-                    }
-                    else
-                    {
-                        ++_lineNumber;
-                        if (ch == '\r' && _source.CharCodeAt(_index) == '\n')
-                        {
-                            ++_index;
-                        }
+                        case '"':
+                            sb.Append('"');
+                            break;
+                        case '\\':
+                            sb.Append('\\');
+                            break;
+                        case '/':
+                            sb.Append('/');
+                            break;
+                        case 'n':
+                            sb.Append('\n');
+                            break;
+                        case 'r':
+                            sb.Append('\r');
+                            break;
+                        case 't':
+                            sb.Append('\t');
+                            break;
+                        case 'u':
+                            sb.Append(ScanHexEscape());
+                            break;
+                        case 'b':
+                            sb.Append('\b');
+                            break;
+                        case 'f':
+                            sb.Append('\f');
+                            break;
+                        default:
+                            ThrowError(_index - 1, Messages.UnexpectedToken, ch);
+                            break;
                     }
                 }
                 else if (IsLineTerminator(ch))