summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--ext/json/json.c3
-rw-r--r--ext/json/json_scanner.c415
-rw-r--r--ext/json/json_scanner.re26
-rw-r--r--ext/json/tests/bug62010.phpt15
5 files changed, 254 insertions, 209 deletions
diff --git a/NEWS b/NEWS
index 248c285a67..4f5de4e88f 100644
--- 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)
diff --git a/ext/json/json.c b/ext/json/json.c
index 8088a89b4e..79b9278513 100644
--- a/ext/json/json.c
+++ b/ext/json/json.c
@@ -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");
}
diff --git a/ext/json/json_scanner.c b/ext/json/json_scanner.c
index a9d220cba2..7b192c43f1 100644
--- a/ext/json/json_scanner.c
+++ b/ext/json/json_scanner.c
@@ -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') {
@@ -684,173 +684,204 @@ 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);
diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re
index e4a4c813dd..82cf69b457 100644
--- a/ext/json/json_scanner.re
+++ b/ext/json/json_scanner.re
@@ -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
index 0000000000..ddac8963c3
--- /dev/null
+++ b/ext/json/tests/bug62010.phpt
@@ -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"