]> granicus.if.org Git - php/commitdiff
Fix bug #62010 (json_decode produces invalid byte-sequences)
authorJakub Zelenka <bukka@php.net>
Sun, 28 Jun 2015 16:16:12 +0000 (17:16 +0100)
committerJakub Zelenka <bukka@php.net>
Sun, 28 Jun 2015 16:16:12 +0000 (17:16 +0100)
NEWS
ext/json/json.c
ext/json/json_scanner.c
ext/json/json_scanner.re
ext/json/tests/bug62010.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 248c285a6731e2c92da13c4bc141753f386a3a4d..4f5de4e88f2c0be6b637a826f68d5edecad68231 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,10 @@ PHP                                                                        NEWS
 - COM:
   . Fixed bug #69939 (Casting object to bool returns false). (Kalle)
 
+- JSON
+  . Fixed bug #62010 (json_decode produces invalid byte-sequences).
+       (Jakub Zelenka)
+
 - OCI8:
   . Corrected oci8 hash destructors to prevent segfaults, and a few other fixes.
     (Cameron Porter)
index 8088a89b4ee2a352daa868d9a126889b2df6f047..79b9278513ec7b91055c94e629d11747910a5c20 100644 (file)
@@ -122,6 +122,7 @@ static PHP_MINIT_FUNCTION(json)
        REGISTER_LONG_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("JSON_ERROR_INVALID_PROPERTY_NAME", PHP_JSON_ERROR_INVALID_PROPERTY_NAME, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("JSON_ERROR_UTF16", PHP_JSON_ERROR_UTF16, CONST_CS | CONST_PERSISTENT);
 
        REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY",          PHP_JSON_OBJECT_AS_ARRAY,               CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING",         PHP_JSON_BIGINT_AS_STRING,              CONST_CS | CONST_PERSISTENT);
@@ -303,6 +304,8 @@ static PHP_FUNCTION(json_last_error_msg)
                        RETURN_STRING("Type is not supported");
                case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
                        RETURN_STRING("The decoded property name is invalid");
+               case PHP_JSON_ERROR_UTF16:
+                       RETURN_STRING("Single unpaired UTF-16 surrogate in unicode escape");
                default:
                        RETURN_STRING("Unknown error");
        }
index a9d220cba2f0de8b30ff84e6ae2c2f914eefb74a..7b192c43f13bf9e6a56035bdac79189e977a6a15 100644 (file)
@@ -593,7 +593,7 @@ yy81:
                                goto yy71;
                        }
                } else {
-                       goto yy101;
+                       goto yy103;
                }
 yy82:
                yych = *++YYCURSOR;
@@ -649,28 +649,28 @@ yy94:
                if (yych <= 'D') {
                        if (yych <= '9') {
                                if (yych <= '/') goto yy81;
-                               if (yych >= '1') goto yy97;
+                               if (yych >= '1') goto yy96;
                        } else {
                                if (yych <= '@') goto yy81;
-                               if (yych <= 'C') goto yy97;
-                               goto yy96;
+                               if (yych <= 'C') goto yy96;
+                               goto yy97;
                        }
                } else {
                        if (yych <= 'c') {
-                               if (yych <= 'F') goto yy97;
+                               if (yych <= 'F') goto yy96;
                                if (yych <= '`') goto yy81;
-                               goto yy97;
+                               goto yy96;
                        } else {
-                               if (yych <= 'd') goto yy96;
-                               if (yych <= 'f') goto yy97;
+                               if (yych <= 'd') goto yy97;
+                               if (yych <= 'f') goto yy96;
                                goto yy81;
                        }
                }
                yych = *++YYCURSOR;
                if (yych <= '9') {
                        if (yych <= '/') goto yy81;
-                       if (yych <= '0') goto yy112;
-                       if (yych <= '7') goto yy113;
+                       if (yych <= '0') goto yy116;
+                       if (yych <= '7') goto yy117;
                        goto yy98;
                } else {
                        if (yych <= 'F') {
@@ -683,174 +683,205 @@ yy94:
                        }
                }
 yy96:
+               yych = *++YYCURSOR;
+               if (yych <= '@') {
+                       if (yych <= '/') goto yy81;
+                       if (yych <= '9') goto yy98;
+                       goto yy81;
+               } else {
+                       if (yych <= 'F') goto yy98;
+                       if (yych <= '`') goto yy81;
+                       if (yych <= 'f') goto yy98;
+                       goto yy81;
+               }
+yy97:
                yych = *++YYCURSOR;
                if (yych <= 'B') {
                        if (yych <= '7') {
                                if (yych <= '/') goto yy81;
-                               goto yy98;
                        } else {
-                               if (yych <= '9') goto yy102;
+                               if (yych <= '9') goto yy99;
                                if (yych <= '@') goto yy81;
-                               goto yy102;
+                               goto yy99;
                        }
                } else {
                        if (yych <= '`') {
-                               if (yych <= 'F') goto yy98;
+                               if (yych <= 'F') goto yy100;
                                goto yy81;
                        } else {
-                               if (yych <= 'b') goto yy102;
-                               if (yych <= 'f') goto yy98;
+                               if (yych <= 'b') goto yy99;
+                               if (yych <= 'f') goto yy100;
                                goto yy81;
                        }
                }
-yy97:
+yy98:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
-                       if (yych >= ':') goto yy81;
+                       if (yych <= '9') goto yy113;
+                       goto yy81;
                } else {
-                       if (yych <= 'F') goto yy98;
+                       if (yych <= 'F') goto yy113;
                        if (yych <= '`') goto yy81;
-                       if (yych >= 'g') goto yy81;
+                       if (yych <= 'f') goto yy113;
+                       goto yy81;
                }
-yy98:
+yy99:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
-                       if (yych >= ':') goto yy81;
+                       if (yych <= '9') goto yy104;
+                       goto yy81;
                } else {
-                       if (yych <= 'F') goto yy99;
+                       if (yych <= 'F') goto yy104;
                        if (yych <= '`') goto yy81;
-                       if (yych >= 'g') goto yy81;
+                       if (yych <= 'f') goto yy104;
+                       goto yy81;
                }
-yy99:
+yy100:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy100;
+                       if (yych <= 'F') goto yy101;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
-yy100:
-               ++YYCURSOR;
 yy101:
-               {
-               s->str_esc += 3;
-               PHP_JSON_CONDITION_GOTO(STR_P1);
-       }
-yy102:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy103;
+                       if (yych <= 'F') goto yy102;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
+yy102:
+               ++YYCURSOR;
 yy103:
+               {
+               s->errcode = PHP_JSON_ERROR_UTF16;
+               return PHP_JSON_T_ERROR;
+       }
+yy104:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy104;
+                       if (yych <= 'F') goto yy105;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
-yy104:
+yy105:
                yyaccept = 2;
                yych = *(YYMARKER = ++YYCURSOR);
-               if (yych != '\\') goto yy101;
+               if (yych != '\\') goto yy103;
                yych = *++YYCURSOR;
                if (yych != 'u') goto yy81;
                yych = *++YYCURSOR;
-               if (yych == 'D') goto yy107;
+               if (yych == 'D') goto yy108;
                if (yych != 'd') goto yy81;
-yy107:
+yy108:
                yych = *++YYCURSOR;
                if (yych <= 'B') goto yy81;
-               if (yych <= 'F') goto yy108;
+               if (yych <= 'F') goto yy109;
                if (yych <= 'b') goto yy81;
                if (yych >= 'g') goto yy81;
-yy108:
+yy109:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy109;
+                       if (yych <= 'F') goto yy110;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
-yy109:
+yy110:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy110;
+                       if (yych <= 'F') goto yy111;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
-yy110:
+yy111:
                ++YYCURSOR;
                {
                s->str_esc += 8;
                PHP_JSON_CONDITION_GOTO(STR_P1);
        }
-yy112:
+yy113:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
-                       if (yych <= '7') goto yy117;
-                       if (yych <= '9') goto yy114;
-                       goto yy81;
+                       if (yych >= ':') goto yy81;
                } else {
                        if (yych <= 'F') goto yy114;
                        if (yych <= '`') goto yy81;
-                       if (yych <= 'f') goto yy114;
+                       if (yych >= 'g') goto yy81;
+               }
+yy114:
+               ++YYCURSOR;
+               {
+               s->str_esc += 3;
+               PHP_JSON_CONDITION_GOTO(STR_P1);
+       }
+yy116:
+               yych = *++YYCURSOR;
+               if (yych <= '@') {
+                       if (yych <= '/') goto yy81;
+                       if (yych <= '7') goto yy121;
+                       if (yych <= '9') goto yy118;
+                       goto yy81;
+               } else {
+                       if (yych <= 'F') goto yy118;
+                       if (yych <= '`') goto yy81;
+                       if (yych <= 'f') goto yy118;
                        goto yy81;
                }
-yy113:
+yy117:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy114;
+                       if (yych <= 'F') goto yy118;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
-yy114:
+yy118:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy115;
+                       if (yych <= 'F') goto yy119;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
-yy115:
+yy119:
                ++YYCURSOR;
                {
                s->str_esc += 4;
                PHP_JSON_CONDITION_GOTO(STR_P1);
        }
-yy117:
+yy121:
                yych = *++YYCURSOR;
                if (yych <= '@') {
                        if (yych <= '/') goto yy81;
                        if (yych >= ':') goto yy81;
                } else {
-                       if (yych <= 'F') goto yy118;
+                       if (yych <= 'F') goto yy122;
                        if (yych <= '`') goto yy81;
                        if (yych >= 'g') goto yy81;
                }
-yy118:
+yy122:
                ++YYCURSOR;
                {
                s->str_esc += 5;
@@ -859,22 +890,22 @@ yy118:
 /* *********************************** */
 yyc_STR_P2:
                yych = *YYCURSOR;
-               if (yych == '"') goto yy124;
-               if (yych == '\\') goto yy126;
+               if (yych == '"') goto yy128;
+               if (yych == '\\') goto yy130;
                ++YYCURSOR;
                { PHP_JSON_CONDITION_GOTO(STR_P2); }
-yy124:
+yy128:
                ++YYCURSOR;
                YYSETCONDITION(yycJS);
                {
                PHP_JSON_SCANNER_COPY_ESC();
                return PHP_JSON_T_STRING;
        }
-yy126:
+yy130:
                yyaccept = 0;
                yych = *(YYMARKER = ++YYCURSOR);
-               if (yych == 'u') goto yy128;
-yy127:
+               if (yych == 'u') goto yy132;
+yy131:
                {
                char esc;
                PHP_JSON_SCANNER_COPY_ESC();
@@ -908,105 +939,104 @@ yy127:
                s->str_start = s->cursor;
                PHP_JSON_CONDITION_GOTO(STR_P2);
        }
-yy128:
+yy132:
                yych = *++YYCURSOR;
                if (yych <= 'D') {
                        if (yych <= '9') {
-                               if (yych <= '/') goto yy129;
-                               if (yych <= '0') goto yy130;
-                               goto yy132;
+                               if (yych <= '/') goto yy133;
+                               if (yych <= '0') goto yy134;
+                               goto yy135;
                        } else {
-                               if (yych <= '@') goto yy129;
-                               if (yych <= 'C') goto yy132;
-                               goto yy131;
+                               if (yych <= '@') goto yy133;
+                               if (yych <= 'C') goto yy135;
+                               goto yy136;
                        }
                } else {
                        if (yych <= 'c') {
-                               if (yych <= 'F') goto yy132;
-                               if (yych >= 'a') goto yy132;
+                               if (yych <= 'F') goto yy135;
+                               if (yych >= 'a') goto yy135;
                        } else {
-                               if (yych <= 'd') goto yy131;
-                               if (yych <= 'f') goto yy132;
+                               if (yych <= 'd') goto yy136;
+                               if (yych <= 'f') goto yy135;
                        }
                }
-yy129:
+yy133:
                YYCURSOR = YYMARKER;
-               if (yyaccept == 0) {
-                       goto yy127;
-               } else {
-                       goto yy136;
-               }
-yy130:
+               goto yy131;
+yy134:
                yych = *++YYCURSOR;
                if (yych <= '9') {
-                       if (yych <= '/') goto yy129;
-                       if (yych <= '0') goto yy147;
-                       if (yych <= '7') goto yy148;
-                       goto yy133;
+                       if (yych <= '/') goto yy133;
+                       if (yych <= '0') goto yy151;
+                       if (yych <= '7') goto yy152;
+                       goto yy138;
                } else {
                        if (yych <= 'F') {
-                               if (yych <= '@') goto yy129;
-                               goto yy133;
+                               if (yych <= '@') goto yy133;
+                               goto yy138;
                        } else {
-                               if (yych <= '`') goto yy129;
-                               if (yych <= 'f') goto yy133;
-                               goto yy129;
+                               if (yych <= '`') goto yy133;
+                               if (yych <= 'f') goto yy138;
+                               goto yy133;
                        }
                }
-yy131:
+yy135:
                yych = *++YYCURSOR;
-               if (yych <= 'B') {
-                       if (yych <= '7') {
-                               if (yych <= '/') goto yy129;
-                               goto yy133;
-                       } else {
-                               if (yych <= '9') goto yy137;
-                               if (yych <= '@') goto yy129;
-                               goto yy137;
-                       }
+               if (yych <= '@') {
+                       if (yych <= '/') goto yy133;
+                       if (yych <= '9') goto yy138;
+                       goto yy133;
                } else {
-                       if (yych <= '`') {
-                               if (yych <= 'F') goto yy133;
-                               goto yy129;
-                       } else {
-                               if (yych <= 'b') goto yy137;
-                               if (yych <= 'f') goto yy133;
-                               goto yy129;
-                       }
+                       if (yych <= 'F') goto yy138;
+                       if (yych <= '`') goto yy133;
+                       if (yych <= 'f') goto yy138;
+                       goto yy133;
                }
-yy132:
+yy136:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych <= '7') goto yy138;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy133;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'B') goto yy137;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'c') goto yy133;
                }
-yy133:
+yy137:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych <= '9') goto yy142;
+                       goto yy133;
                } else {
-                       if (yych <= 'F') goto yy134;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy142;
+                       if (yych <= '`') goto yy133;
+                       if (yych <= 'f') goto yy142;
+                       goto yy133;
                }
-yy134:
+yy138:
+               yych = *++YYCURSOR;
+               if (yych <= '@') {
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
+               } else {
+                       if (yych <= 'F') goto yy139;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
+               }
+yy139:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy135;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy140;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
                }
-yy135:
+yy140:
                ++YYCURSOR;
-yy136:
                {
                int utf16 = php_json_ucs2_to_int(s, 4);
                PHP_JSON_SCANNER_COPY_UTF();
@@ -1016,62 +1046,51 @@ yy136:
                s->str_start = s->cursor;
                PHP_JSON_CONDITION_GOTO(STR_P2);
        }
-yy137:
+yy142:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy138;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy143;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
                }
-yy138:
+yy143:
                yych = *++YYCURSOR;
-               if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
-               } else {
-                       if (yych <= 'F') goto yy139;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
-               }
-yy139:
-               yyaccept = 1;
-               yych = *(YYMARKER = ++YYCURSOR);
-               if (yych != '\\') goto yy136;
+               if (yych != '\\') goto yy133;
                yych = *++YYCURSOR;
-               if (yych != 'u') goto yy129;
+               if (yych != 'u') goto yy133;
                yych = *++YYCURSOR;
-               if (yych == 'D') goto yy142;
-               if (yych != 'd') goto yy129;
-yy142:
+               if (yych == 'D') goto yy146;
+               if (yych != 'd') goto yy133;
+yy146:
                yych = *++YYCURSOR;
-               if (yych <= 'B') goto yy129;
-               if (yych <= 'F') goto yy143;
-               if (yych <= 'b') goto yy129;
-               if (yych >= 'g') goto yy129;
-yy143:
+               if (yych <= 'B') goto yy133;
+               if (yych <= 'F') goto yy147;
+               if (yych <= 'b') goto yy133;
+               if (yych >= 'g') goto yy133;
+yy147:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy144;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy148;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
                }
-yy144:
+yy148:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy145;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy149;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
                }
-yy145:
+yy149:
                ++YYCURSOR;
                {
                int utf32, utf16_hi, utf16_lo;
@@ -1086,40 +1105,40 @@ yy145:
                s->str_start = s->cursor;
                PHP_JSON_CONDITION_GOTO(STR_P2);
        }
-yy147:
+yy151:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych <= '7') goto yy152;
-                       if (yych <= '9') goto yy149;
-                       goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych <= '7') goto yy156;
+                       if (yych <= '9') goto yy153;
+                       goto yy133;
                } else {
-                       if (yych <= 'F') goto yy149;
-                       if (yych <= '`') goto yy129;
-                       if (yych <= 'f') goto yy149;
-                       goto yy129;
+                       if (yych <= 'F') goto yy153;
+                       if (yych <= '`') goto yy133;
+                       if (yych <= 'f') goto yy153;
+                       goto yy133;
                }
-yy148:
+yy152:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy149;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy153;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
                }
-yy149:
+yy153:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy150;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy154;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
                }
-yy150:
+yy154:
                ++YYCURSOR;
                {
                int utf16 = php_json_ucs2_to_int(s, 3);
@@ -1129,17 +1148,17 @@ yy150:
                s->str_start = s->cursor;
                PHP_JSON_CONDITION_GOTO(STR_P2);
        }
-yy152:
+yy156:
                yych = *++YYCURSOR;
                if (yych <= '@') {
-                       if (yych <= '/') goto yy129;
-                       if (yych >= ':') goto yy129;
+                       if (yych <= '/') goto yy133;
+                       if (yych >= ':') goto yy133;
                } else {
-                       if (yych <= 'F') goto yy153;
-                       if (yych <= '`') goto yy129;
-                       if (yych >= 'g') goto yy129;
+                       if (yych <= 'F') goto yy157;
+                       if (yych <= '`') goto yy133;
+                       if (yych >= 'g') goto yy133;
                }
-yy153:
+yy157:
                ++YYCURSOR;
                {
                int utf16 = php_json_ucs2_to_int(s, 2);
index e4a4c813dda82c8409f8c6172e99be38d1c355a6..82cf69b45771bc913f955dfa982d91035e2aaf9b 100644 (file)
@@ -213,13 +213,17 @@ std:
                s->str_esc += 4;
                PHP_JSON_CONDITION_GOTO(STR_P1);
        }
+       <STR_P1>UTF16_3          {
+               s->str_esc += 3;
+               PHP_JSON_CONDITION_GOTO(STR_P1);
+       }
        <STR_P1>UTF16_4          {
                s->str_esc += 8;
                PHP_JSON_CONDITION_GOTO(STR_P1);
        }
        <STR_P1>UCS2             {
-               s->str_esc += 3;
-               PHP_JSON_CONDITION_GOTO(STR_P1);
+               s->errcode = PHP_JSON_ERROR_UTF16;
+               return PHP_JSON_T_ERROR;
        }
        <STR_P1>ESC              {
                s->str_esc++;
@@ -272,6 +276,15 @@ std:
                s->str_start = s->cursor;
                PHP_JSON_CONDITION_GOTO(STR_P2);
        }
+       <STR_P2>UTF16_3             {
+               int utf16 = php_json_ucs2_to_int(s, 4);
+               PHP_JSON_SCANNER_COPY_UTF();
+               *(s->pstr++) = (char) (0xe0 | (utf16 >> 12));
+               *(s->pstr++) = (char) (0x80 | ((utf16 >> 6) & 0x3f));
+               *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f));
+               s->str_start = s->cursor;
+               PHP_JSON_CONDITION_GOTO(STR_P2);
+       }
        <STR_P2>UTF16_4             {
                int utf32, utf16_hi, utf16_lo;
                utf16_hi = php_json_ucs2_to_int(s, 4);
@@ -285,15 +298,6 @@ std:
                s->str_start = s->cursor;
                PHP_JSON_CONDITION_GOTO(STR_P2);
        }
-       <STR_P2>UCS2             {
-               int utf16 = php_json_ucs2_to_int(s, 4);
-               PHP_JSON_SCANNER_COPY_UTF();
-               *(s->pstr++) = (char) (0xe0 | (utf16 >> 12));
-               *(s->pstr++) = (char) (0x80 | ((utf16 >> 6) & 0x3f));
-               *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f));
-               s->str_start = s->cursor;
-               PHP_JSON_CONDITION_GOTO(STR_P2);
-       }
        <STR_P2>ESCPREF          {
                char esc;
                PHP_JSON_SCANNER_COPY_ESC();
diff --git a/ext/json/tests/bug62010.phpt b/ext/json/tests/bug62010.phpt
new file mode 100644 (file)
index 0000000..ddac896
--- /dev/null
@@ -0,0 +1,15 @@
+--TEST--
+Bug #62010 (json_decode produces invalid byte-sequences)
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(json_decode('"\ud834"'));
+var_dump(json_last_error() === JSON_ERROR_UTF16);
+var_dump(json_last_error_msg());
+?>
+--EXPECTF--
+NULL
+bool(true)
+string(50) "Single unpaired UTF-16 surrogate in unicode escape"