]> granicus.if.org Git - php/commitdiff
Fix bug #68546 (json_decode cannot access property started with \0)
authorJakub Zelenka <bukka@php.net>
Sun, 21 Jun 2015 14:30:33 +0000 (15:30 +0100)
committerJakub Zelenka <bukka@php.net>
Sun, 21 Jun 2015 14:30:33 +0000 (15:30 +0100)
NEWS
ext/json/json.c
ext/json/json_parser.tab.c
ext/json/json_parser.y
ext/json/php_json.h
ext/json/tests/bug68546.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index e5607192e0edb826dde1fb94aafb7e163f172115..da7583664ad32bc2caabd62f5f34032004ece710 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -199,6 +199,8 @@ PHP                                                                        NEWS
     (JSON extension includes a problematic license statement). (Jakub Zelenka)
   . Fixed bug #68938 (json_decode() decodes empty string without error).
     (jeremy at bat-country dot us)
+  . Fixed bug #68546 (json_decode() Fatal error: Cannot access property
+    started with '\0'). (Jakub Zelenka)
 
 - LDAP
   . Fixed bug #47222 (Implement LDAP_OPT_DIAGNOSTIC_MESSAGE). (Andreas Heigl)
index 1caef6501355e7ed781960324ab357d4298c8602..8088a89b4ee2a352daa868d9a126889b2df6f047 100644 (file)
@@ -121,6 +121,7 @@ static PHP_MINIT_FUNCTION(json)
        REGISTER_LONG_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT);
        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_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);
@@ -300,6 +301,8 @@ static PHP_FUNCTION(json_last_error_msg)
                        RETURN_STRING("Inf and NaN cannot be JSON encoded");
                case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
                        RETURN_STRING("Type is not supported");
+               case PHP_JSON_ERROR_INVALID_PROPERTY_NAME:
+                       RETURN_STRING("The decoded property name is invalid");
                default:
                        RETURN_STRING("Unknown error");
        }
index 45a982bbccc0f85957c605f9cd621530c08236b2..052fc17137a41e69125d158f98de84b4004c82d6 100644 (file)
@@ -204,7 +204,7 @@ int php_json_yyparse (php_json_parser *parser);
 int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
 void php_json_yyerror(php_json_parser *parser, char const *msg);
 void php_json_parser_object_init(php_json_parser *parser, zval *object);
-void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
+int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
 void php_json_parser_array_init(zval *object);
 void php_json_parser_array_append(zval *array, zval *zvalue);
 
@@ -515,9 +515,9 @@ static const yytype_uint8 yytranslate[] =
 static const yytype_uint8 yyrline[] =
 {
        0,    92,    92,    98,   105,   105,   113,   114,   123,   126,
-     130,   135,   140,   147,   152,   159,   159,   167,   168,   177,
-     180,   184,   189,   194,   201,   202,   206,   207,   208,   209,
-     210,   211,   212,   213,   214,   215,   219
+     130,   136,   142,   149,   154,   161,   161,   169,   170,   179,
+     182,   186,   191,   196,   203,   204,   208,   209,   210,   211,
+     212,   213,   214,   215,   216,   217,   221
 };
 #endif
 
@@ -1499,7 +1499,8 @@ yyreduce:
 
     {
                                php_json_parser_object_init(parser, &(yyval.value));
-                               php_json_parser_object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val);
+                               if (php_json_parser_object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE)
+                                       YYERROR;
                        }
 
     break;
@@ -1507,7 +1508,8 @@ yyreduce:
   case 11:
 
     {
-                               php_json_parser_object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val);
+                               if (php_json_parser_object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE)
+                                       YYERROR;
                                ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value));
                        }
 
@@ -1860,7 +1862,7 @@ void php_json_parser_object_init(php_json_parser *parser, zval *object)
        }
 }
 
-void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
+int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
 {
        /* if JSON_OBJECT_AS_ARRAY is set */
        if (Z_TYPE_P(object) == IS_ARRAY) {
@@ -1870,6 +1872,12 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s
                if (key->len == 0) {
                        zend_string_release(key);
                        key = zend_string_init("_empty_", sizeof("_empty_") - 1, 0);
+               } else if (key->val[0] == '\0') {
+                       parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME;
+                       zend_string_release(key);
+                       zval_dtor(zvalue);
+                       zval_dtor(object);
+                       return FAILURE;
                }
                ZVAL_NEW_STR(&zkey, key);
                zend_std_write_property(object, &zkey, zvalue, NULL); 
@@ -1879,6 +1887,8 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s
                }
        }
        zend_string_release(key);
+
+       return SUCCESS;
 }
 
 void php_json_parser_array_init(zval *array)
index 500a0ff11d07cb73a9448b11fb7903837cf0cbf0..1521be69b8e21d0818ca5207f7b5b46716b51f70 100644 (file)
@@ -73,7 +73,7 @@ int json_yydebug = 1;
 int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
 void php_json_yyerror(php_json_parser *parser, char const *msg);
 void php_json_parser_object_init(php_json_parser *parser, zval *object);
-void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
+int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
 void php_json_parser_array_init(zval *object);
 void php_json_parser_array_append(zval *array, zval *zvalue);
 
@@ -130,11 +130,13 @@ member:
                pair
                        {
                                php_json_parser_object_init(parser, &$$);
-                               php_json_parser_object_update(parser, &$$, $1.key, &$1.val);
+                               if (php_json_parser_object_update(parser, &$$, $1.key, &$1.val) == FAILURE)
+                                       YYERROR;
                        }
        |       member ',' pair
                        {
-                               php_json_parser_object_update(parser, &$1, $3.key, &$3.val);
+                               if (php_json_parser_object_update(parser, &$1, $3.key, &$3.val) == FAILURE)
+                                       YYERROR;
                                ZVAL_COPY_VALUE(&$$, &$1);
                        }
        |       member errlex
@@ -248,7 +250,7 @@ void php_json_parser_object_init(php_json_parser *parser, zval *object)
        }
 }
 
-void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
+int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
 {
        /* if JSON_OBJECT_AS_ARRAY is set */
        if (Z_TYPE_P(object) == IS_ARRAY) {
@@ -258,6 +260,12 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s
                if (key->len == 0) {
                        zend_string_release(key);
                        key = zend_string_init("_empty_", sizeof("_empty_") - 1, 0);
+               } else if (key->val[0] == '\0') {
+                       parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME;
+                       zend_string_release(key);
+                       zval_dtor(zvalue);
+                       zval_dtor(object);
+                       return FAILURE;
                }
                ZVAL_NEW_STR(&zkey, key);
                zend_std_write_property(object, &zkey, zvalue, NULL); 
@@ -267,6 +275,8 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s
                }
        }
        zend_string_release(key);
+
+       return SUCCESS;
 }
 
 void php_json_parser_array_init(zval *array)
index 54d94da498d724e6287a4548ca0e2380fda808b7..c47bc0f401247fb7d85c60d436143af04e73a822 100644 (file)
@@ -51,6 +51,7 @@ typedef enum {
        PHP_JSON_ERROR_RECURSION,
        PHP_JSON_ERROR_INF_OR_NAN,
        PHP_JSON_ERROR_UNSUPPORTED_TYPE,
+       PHP_JSON_ERROR_INVALID_PROPERTY_NAME,
        PHP_JSON_ERROR_UTF16
 } php_json_error_code;
 
diff --git a/ext/json/tests/bug68546.phpt b/ext/json/tests/bug68546.phpt
new file mode 100644 (file)
index 0000000..f8c8d13
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Bug #68546 (json_decode() Fatal error: Cannot access property started with '\0')
+--SKIPIF--
+<?php
+
+if (!extension_loaded('json')) die('skip');
+?>
+--FILE--
+<?php
+
+var_dump(json_decode('{"key": {"\u0000": "aa"}}'));
+var_dump(json_last_error() === JSON_ERROR_INVALID_PROPERTY_NAME);
+var_dump(json_decode('[{"key1": 0, "\u0000": 1}]'));
+var_dump(json_last_error() === JSON_ERROR_INVALID_PROPERTY_NAME);
+var_dump(json_last_error_msg());
+
+echo "Done\n";
+?>
+--EXPECTF--
+NULL
+bool(true)
+NULL
+bool(true)
+string(36) "The decoded property name is invalid"
+Done