From 72ccfda25aadf7eb225d7f899475e7d274bd1e72 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 28 Feb 2016 17:45:53 +0000 Subject: [PATCH 1/5] Add method hooking support to json parser This commit is just a slight modification (renaming and some small changes) of the patch that has been provided by Andrey Hristov. It adds support for hooking of the json parser operations and allows re-using of modified JSON parsing outside of json ext. --- ext/json/json_parser.tab.c | 164 ++++++++++++++++++++++++++----------- ext/json/json_parser.y | 156 +++++++++++++++++++++++++---------- ext/json/php_json_parser.h | 64 +++++++++++++-- 3 files changed, 286 insertions(+), 98 deletions(-) diff --git a/ext/json/json_parser.tab.c b/ext/json/json_parser.tab.c index b01d031f144..7ad54e3b778 100644 --- a/ext/json/json_parser.tab.c +++ b/ext/json/json_parser.tab.c @@ -201,20 +201,9 @@ int php_json_yyparse (php_json_parser *parser); /* Unqualified %code blocks. */ -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); -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); +static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); +static void php_json_yyerror(php_json_parser *parser, char const *msg); -#define PHP_JSON_DEPTH_DEC --parser->depth -#define PHP_JSON_DEPTH_INC \ - if (parser->max_depth && parser->depth >= parser->max_depth) { \ - parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \ - YYERROR; \ - } \ - ++parser->depth @@ -514,10 +503,10 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 92, 92, 98, 105, 105, 113, 114, 123, 126, - 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 + 0, 81, 81, 87, 94, 94, 104, 105, 114, 117, + 121, 127, 133, 140, 145, 152, 152, 162, 163, 172, + 175, 179, 184, 189, 196, 197, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 214 }; #endif @@ -1465,15 +1454,17 @@ yyreduce: case 4: - { PHP_JSON_DEPTH_INC; } + { if (FAILURE == parser->methods->object_start(parser)) YYERROR; } break; case 5: { - PHP_JSON_DEPTH_DEC; (yyval.value) = (yyvsp[-1].value); + if (FAILURE == parser->methods->object_end(parser, &(yyval.value))) { + YYERROR; + } } break; @@ -1490,7 +1481,7 @@ yyreduce: case 8: { - php_json_parser_object_init(parser, &(yyval.value)); + parser->methods->object_create(parser, &(yyval.value)); } break; @@ -1498,8 +1489,8 @@ yyreduce: case 10: { - php_json_parser_object_init(parser, &(yyval.value)); - if (php_json_parser_object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + parser->methods->object_create(parser, &(yyval.value)); + if (parser->methods->object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) YYERROR; } @@ -1508,7 +1499,7 @@ yyreduce: case 11: { - if (php_json_parser_object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + if (parser->methods->object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) YYERROR; ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); } @@ -1542,15 +1533,17 @@ yyreduce: case 15: - { PHP_JSON_DEPTH_INC; } + { if (FAILURE == parser->methods->array_start(parser)) YYERROR; } break; case 16: { - PHP_JSON_DEPTH_DEC; ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); + if (FAILURE == parser->methods->array_end(parser, &(yyval.value))) { + YYERROR; + } } break; @@ -1567,7 +1560,7 @@ yyreduce: case 19: { - php_json_parser_array_init(&(yyval.value)); + parser->methods->array_create(parser, &(yyval.value)); } break; @@ -1575,8 +1568,8 @@ yyreduce: case 21: { - php_json_parser_array_init(&(yyval.value)); - php_json_parser_array_append(&(yyval.value), &(yyvsp[0].value)); + parser->methods->array_create(parser, &(yyval.value)); + parser->methods->array_append(parser, &(yyval.value), &(yyvsp[0].value)); } break; @@ -1584,7 +1577,7 @@ yyreduce: case 22: { - php_json_parser_array_append(&(yyvsp[-2].value), &(yyvsp[0].value)); + parser->methods->array_append(parser, &(yyvsp[-2].value), &(yyvsp[0].value)); ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); } @@ -1839,30 +1832,37 @@ yyreturn: /* Functions */ -void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth) +static int php_json_parser_array_create(php_json_parser *parser, zval *array) { - memset(parser, 0, sizeof(php_json_parser)); - php_json_scanner_init(&parser->scanner, str, str_len, options); - parser->depth = 1; - parser->max_depth = max_depth; - parser->return_value = return_value; + return array_init(array); } -php_json_error_code php_json_parser_error_code(php_json_parser *parser) +static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue) { - return parser->scanner.errcode; + zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); + return SUCCESS; } -void php_json_parser_object_init(php_json_parser *parser, zval *object) +static int php_json_parser_array_start(php_json_parser *parser) +{ + return parser->methods->depth_increase(parser); +} + +static int php_json_parser_array_end(php_json_parser *parser, zval *object) +{ + return parser->methods->depth_decrease(parser); +} + +static int php_json_parser_object_create(php_json_parser *parser, zval *object) { if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { - array_init(object); + return array_init(object); } else { - object_init(object); + return object_init(object); } } -int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +static 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) { @@ -1891,26 +1891,94 @@ int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_st return SUCCESS; } -void php_json_parser_array_init(zval *array) +static int php_json_parser_object_start(php_json_parser *parser) { - array_init(array); + return parser->methods->depth_increase(parser); } -void php_json_parser_array_append(zval *array, zval *zvalue) +static int php_json_parser_object_end(php_json_parser *parser, zval *object) { - zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); + return parser->methods->depth_decrease(parser); } - -int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) + +static int php_json_parser_depth_increase(php_json_parser *parser) +{ + if (parser->max_depth && parser->depth >= parser->max_depth) { + parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; + return FAILURE; + } + ++parser->depth; + return SUCCESS; +} + +static int php_json_parser_depth_decrease(php_json_parser *parser) +{ + --parser->depth; + return SUCCESS; +} + +static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) { int token = php_json_scan(&parser->scanner); value->value = parser->scanner.value; return token; } -void php_json_yyerror(php_json_parser *parser, char const *msg) +static void php_json_yyerror(php_json_parser *parser, char const *msg) { if (!parser->scanner.errcode) { parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; } } + +php_json_error_code php_json_parser_error_code(const php_json_parser *parser) +{ + return parser->scanner.errcode; +} + +static const php_json_parser_methods default_parser_methods = +{ + php_json_parser_array_create, + php_json_parser_array_append, + php_json_parser_array_start, + php_json_parser_array_end, + php_json_parser_object_create, + php_json_parser_object_update, + php_json_parser_object_start, + php_json_parser_object_end, + php_json_parser_depth_increase, + php_json_parser_depth_decrease +}; + +void php_json_parser_init_ex(php_json_parser *parser, + zval *return_value, + char *str, + size_t str_len, + int options, + int max_depth, + const php_json_parser_methods *parser_methods) +{ + memset(parser, 0, sizeof(php_json_parser)); + php_json_scanner_init(&parser->scanner, str, str_len, options); + parser->depth = 1; + parser->max_depth = max_depth; + parser->return_value = return_value; + parser->methods = parser_methods; +} + +void php_json_parser_init(php_json_parser *parser, + zval *return_value, + char *str, + size_t str_len, + int options, + int max_depth) +{ + php_json_parser_init_ex( + parser, + return_value, + str, + str_len, + options, + max_depth, + &default_parser_methods); +} diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 2f37641c0c5..f359c608d2e 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -70,20 +70,9 @@ int json_yydebug = 1; %destructor { zend_string_release($$.key); zval_dtor(&$$.val); } %code { -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); -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); +static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); +static void php_json_yyerror(php_json_parser *parser, char const *msg); -#define PHP_JSON_DEPTH_DEC --parser->depth -#define PHP_JSON_DEPTH_INC \ - if (parser->max_depth && parser->depth >= parser->max_depth) { \ - parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \ - YYERROR; \ - } \ - ++parser->depth } %% /* Rules */ @@ -102,10 +91,12 @@ start: ; object: - '{' { PHP_JSON_DEPTH_INC; } members object_end + '{' { if (FAILURE == parser->methods->object_start(parser)) YYERROR; } members object_end { - PHP_JSON_DEPTH_DEC; $$ = $3; + if (FAILURE == parser->methods->object_end(parser, &$$)) { + YYERROR; + } } ; @@ -121,7 +112,7 @@ object_end: members: /* empty */ { - php_json_parser_object_init(parser, &$$); + parser->methods->object_create(parser, &$$); } | member ; @@ -129,13 +120,13 @@ members: member: pair { - php_json_parser_object_init(parser, &$$); - if (php_json_parser_object_update(parser, &$$, $1.key, &$1.val) == FAILURE) + parser->methods->object_create(parser, &$$); + if (parser->methods->object_update(parser, &$$, $1.key, &$1.val) == FAILURE) YYERROR; } | member ',' pair { - if (php_json_parser_object_update(parser, &$1, $3.key, &$3.val) == FAILURE) + if (parser->methods->object_update(parser, &$1, $3.key, &$3.val) == FAILURE) YYERROR; ZVAL_COPY_VALUE(&$$, &$1); } @@ -158,10 +149,12 @@ pair: ; array: - '[' { PHP_JSON_DEPTH_INC; } elements array_end + '[' { if (FAILURE == parser->methods->array_start(parser)) YYERROR; } elements array_end { - PHP_JSON_DEPTH_DEC; ZVAL_COPY_VALUE(&$$, &$3); + if (FAILURE == parser->methods->array_end(parser, &$$)) { + YYERROR; + } } ; @@ -177,7 +170,7 @@ array_end: elements: /* empty */ { - php_json_parser_array_init(&$$); + parser->methods->array_create(parser, &$$); } | element ; @@ -185,12 +178,12 @@ elements: element: value { - php_json_parser_array_init(&$$); - php_json_parser_array_append(&$$, &$1); + parser->methods->array_create(parser, &$$); + parser->methods->array_append(parser, &$$, &$1); } | element ',' value { - php_json_parser_array_append(&$1, &$3); + parser->methods->array_append(parser, &$1, &$3); ZVAL_COPY_VALUE(&$$, &$1); } | element errlex @@ -227,30 +220,37 @@ errlex: %% /* Functions */ -void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth) +static int php_json_parser_array_create(php_json_parser *parser, zval *array) { - memset(parser, 0, sizeof(php_json_parser)); - php_json_scanner_init(&parser->scanner, str, str_len, options); - parser->depth = 1; - parser->max_depth = max_depth; - parser->return_value = return_value; + return array_init(array); } -php_json_error_code php_json_parser_error_code(php_json_parser *parser) +static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue) { - return parser->scanner.errcode; + zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); + return SUCCESS; } -void php_json_parser_object_init(php_json_parser *parser, zval *object) +static int php_json_parser_array_start(php_json_parser *parser) +{ + return parser->methods->depth_increase(parser); +} + +static int php_json_parser_array_end(php_json_parser *parser, zval *object) +{ + return parser->methods->depth_decrease(parser); +} + +static int php_json_parser_object_create(php_json_parser *parser, zval *object) { if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { - array_init(object); + return array_init(object); } else { - object_init(object); + return object_init(object); } } -int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +static 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) { @@ -279,26 +279,94 @@ int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_st return SUCCESS; } -void php_json_parser_array_init(zval *array) +static int php_json_parser_object_start(php_json_parser *parser) { - array_init(array); + return parser->methods->depth_increase(parser); } -void php_json_parser_array_append(zval *array, zval *zvalue) +static int php_json_parser_object_end(php_json_parser *parser, zval *object) { - zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); + return parser->methods->depth_decrease(parser); } - -int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) + +static int php_json_parser_depth_increase(php_json_parser *parser) +{ + if (parser->max_depth && parser->depth >= parser->max_depth) { + parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; + return FAILURE; + } + ++parser->depth; + return SUCCESS; +} + +static int php_json_parser_depth_decrease(php_json_parser *parser) +{ + --parser->depth; + return SUCCESS; +} + +static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) { int token = php_json_scan(&parser->scanner); value->value = parser->scanner.value; return token; } -void php_json_yyerror(php_json_parser *parser, char const *msg) +static void php_json_yyerror(php_json_parser *parser, char const *msg) { if (!parser->scanner.errcode) { parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; } } + +php_json_error_code php_json_parser_error_code(const php_json_parser *parser) +{ + return parser->scanner.errcode; +} + +static const php_json_parser_methods default_parser_methods = +{ + php_json_parser_array_create, + php_json_parser_array_append, + php_json_parser_array_start, + php_json_parser_array_end, + php_json_parser_object_create, + php_json_parser_object_update, + php_json_parser_object_start, + php_json_parser_object_end, + php_json_parser_depth_increase, + php_json_parser_depth_decrease +}; + +void php_json_parser_init_ex(php_json_parser *parser, + zval *return_value, + char *str, + size_t str_len, + int options, + int max_depth, + const php_json_parser_methods *parser_methods) +{ + memset(parser, 0, sizeof(php_json_parser)); + php_json_scanner_init(&parser->scanner, str, str_len, options); + parser->depth = 1; + parser->max_depth = max_depth; + parser->return_value = return_value; + parser->methods = parser_methods; +} + +void php_json_parser_init(php_json_parser *parser, + zval *return_value, + char *str, + size_t str_len, + int options, + int max_depth) +{ + php_json_parser_init_ex( + parser, + return_value, + str, + str_len, + options, + max_depth, + &default_parser_methods); +} diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 6964ef8e8e0..9a3f2066676 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -22,18 +22,70 @@ #include "php.h" #include "php_json_scanner.h" -typedef struct _php_json_parser { +typedef struct _php_json_parser php_json_parser; + +typedef int (*php_json_parser_func_array_create_t)( + php_json_parser *parser, zval *array); +typedef int (*php_json_parser_func_array_append_t)( + php_json_parser *parser, zval *array, zval *zvalue); +typedef int (*php_json_parser_func_array_start_t)( + php_json_parser *parser); +typedef int (*php_json_parser_func_array_end_t)( + php_json_parser *parser, zval *object); +typedef int (*php_json_parser_func_object_create_t)( + php_json_parser *parser, zval *object); +typedef int (*php_json_parser_func_object_update_t)( + php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); +typedef int (*php_json_parser_func_object_start_t)( + php_json_parser *parser); +typedef int (*php_json_parser_func_object_end_t)( + php_json_parser *parser, zval *object); +typedef int (*php_json_parser_func_depth_increase_t)( + php_json_parser *parser); +typedef int (*php_json_parser_func_depth_decrease_t)( + php_json_parser *parser); + +typedef struct _php_json_parser_methods { + php_json_parser_func_array_create_t array_create; + php_json_parser_func_array_append_t array_append; + php_json_parser_func_array_start_t array_start; + php_json_parser_func_array_end_t array_end; + php_json_parser_func_object_create_t object_create; + php_json_parser_func_object_update_t object_update; + php_json_parser_func_object_start_t object_start; + php_json_parser_func_object_end_t object_end; + php_json_parser_func_depth_increase_t depth_increase; + php_json_parser_func_depth_decrease_t depth_decrease; +} php_json_parser_methods; + +struct _php_json_parser { php_json_scanner scanner; zval *return_value; - int depth; + unsigned int depth; int max_depth; -} php_json_parser; + const php_json_parser_methods *methods; +}; -void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth); +PHP_JSON_API void php_json_parser_init_ex( + php_json_parser *parser, + zval *return_value, + char *str, + size_t str_len, + int options, + int max_depth, + const php_json_parser_methods *methods); -php_json_error_code php_json_parser_error_code(php_json_parser *parser); +PHP_JSON_API void php_json_parser_init( + php_json_parser *parser, + zval *return_value, + char *str, + size_t str_len, + int options, + int max_depth); -int php_json_yyparse(php_json_parser *parser); +PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser); + +PHP_JSON_API int php_json_yyparse(php_json_parser *parser); #endif /* PHP_JSON_PARSER_H */ From 93b67dd511fdf890931e2b18846886368798ca5a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 10 Apr 2016 16:10:26 +0100 Subject: [PATCH 2/5] Remove json parser depth methods and tidy it up --- ext/json/json_parser.tab.c | 92 ++++++++++++++++---------------------- ext/json/json_parser.y | 90 ++++++++++++++++--------------------- ext/json/php_json_parser.h | 6 --- 3 files changed, 77 insertions(+), 111 deletions(-) diff --git a/ext/json/json_parser.tab.c b/ext/json/json_parser.tab.c index 7ad54e3b778..eb8c6be5ff6 100644 --- a/ext/json/json_parser.tab.c +++ b/ext/json/json_parser.tab.c @@ -98,6 +98,14 @@ int json_yydebug = 1; #define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1) #define PHP_JSON_USE_2(uvr, uv1, uv2) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2) +#define PHP_JSON_DEPTH_DEC --parser->depth +#define PHP_JSON_DEPTH_INC \ + if (parser->max_depth && parser->depth >= parser->max_depth) { \ + parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \ + YYERROR; \ + } \ + ++parser->depth + @@ -503,10 +511,10 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 81, 81, 87, 94, 94, 104, 105, 114, 117, - 121, 127, 133, 140, 145, 152, 152, 162, 163, 172, - 175, 179, 184, 189, 196, 197, 201, 202, 203, 204, - 205, 206, 207, 208, 209, 210, 214 + 0, 89, 89, 95, 103, 102, 120, 121, 130, 133, + 137, 144, 151, 158, 163, 171, 170, 188, 189, 198, + 201, 205, 210, 215, 222, 223, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 240 }; #endif @@ -1454,15 +1462,21 @@ yyreduce: case 4: - { if (FAILURE == parser->methods->object_start(parser)) YYERROR; } + { + PHP_JSON_DEPTH_INC; + if (parser->methods->object_start && FAILURE == parser->methods->object_start(parser)) { + YYERROR; + } + } break; case 5: { - (yyval.value) = (yyvsp[-1].value); - if (FAILURE == parser->methods->object_end(parser, &(yyval.value))) { + ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); + PHP_JSON_DEPTH_DEC; + if (parser->methods->object_end && FAILURE == parser->methods->object_end(parser, &(yyval.value))) { YYERROR; } } @@ -1490,8 +1504,9 @@ yyreduce: { parser->methods->object_create(parser, &(yyval.value)); - if (parser->methods->object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + if (parser->methods->object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) { YYERROR; + } } break; @@ -1499,8 +1514,9 @@ yyreduce: case 11: { - if (parser->methods->object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + if (parser->methods->object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) { YYERROR; + } ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); } @@ -1533,7 +1549,12 @@ yyreduce: case 15: - { if (FAILURE == parser->methods->array_start(parser)) YYERROR; } + { + PHP_JSON_DEPTH_INC; + if (parser->methods->array_start && FAILURE == parser->methods->array_start(parser)) { + YYERROR; + } + } break; @@ -1541,7 +1562,8 @@ yyreduce: { ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); - if (FAILURE == parser->methods->array_end(parser, &(yyval.value))) { + PHP_JSON_DEPTH_DEC; + if (parser->methods->array_end && FAILURE == parser->methods->array_end(parser, &(yyval.value))) { YYERROR; } } @@ -1843,16 +1865,6 @@ static int php_json_parser_array_append(php_json_parser *parser, zval *array, zv return SUCCESS; } -static int php_json_parser_array_start(php_json_parser *parser) -{ - return parser->methods->depth_increase(parser); -} - -static int php_json_parser_array_end(php_json_parser *parser, zval *object) -{ - return parser->methods->depth_decrease(parser); -} - static int php_json_parser_object_create(php_json_parser *parser, zval *object) { if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { @@ -1880,7 +1892,7 @@ static int php_json_parser_object_update(php_json_parser *parser, zval *object, return FAILURE; } ZVAL_NEW_STR(&zkey, key); - zend_std_write_property(object, &zkey, zvalue, NULL); + zend_std_write_property(object, &zkey, zvalue, NULL); if (Z_REFCOUNTED_P(zvalue)) { Z_DELREF_P(zvalue); @@ -1891,32 +1903,6 @@ static int php_json_parser_object_update(php_json_parser *parser, zval *object, return SUCCESS; } -static int php_json_parser_object_start(php_json_parser *parser) -{ - return parser->methods->depth_increase(parser); -} - -static int php_json_parser_object_end(php_json_parser *parser, zval *object) -{ - return parser->methods->depth_decrease(parser); -} - -static int php_json_parser_depth_increase(php_json_parser *parser) -{ - if (parser->max_depth && parser->depth >= parser->max_depth) { - parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; - return FAILURE; - } - ++parser->depth; - return SUCCESS; -} - -static int php_json_parser_depth_decrease(php_json_parser *parser) -{ - --parser->depth; - return SUCCESS; -} - static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) { int token = php_json_scan(&parser->scanner); @@ -1940,14 +1926,12 @@ static const php_json_parser_methods default_parser_methods = { php_json_parser_array_create, php_json_parser_array_append, - php_json_parser_array_start, - php_json_parser_array_end, + NULL, + NULL, php_json_parser_object_create, php_json_parser_object_update, - php_json_parser_object_start, - php_json_parser_object_end, - php_json_parser_depth_increase, - php_json_parser_depth_decrease + NULL, + NULL, }; void php_json_parser_init_ex(php_json_parser *parser, diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index f359c608d2e..c7c4f74a160 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -36,6 +36,14 @@ int json_yydebug = 1; #define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1) #define PHP_JSON_USE_2(uvr, uv1, uv2) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2) +#define PHP_JSON_DEPTH_DEC --parser->depth +#define PHP_JSON_DEPTH_INC \ + if (parser->max_depth && parser->depth >= parser->max_depth) { \ + parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \ + YYERROR; \ + } \ + ++parser->depth + } %pure-parser @@ -91,10 +99,18 @@ start: ; object: - '{' { if (FAILURE == parser->methods->object_start(parser)) YYERROR; } members object_end + '{' { - $$ = $3; - if (FAILURE == parser->methods->object_end(parser, &$$)) { + PHP_JSON_DEPTH_INC; + if (parser->methods->object_start && FAILURE == parser->methods->object_start(parser)) { + YYERROR; + } + } + members object_end + { + ZVAL_COPY_VALUE(&$$, &$3); + PHP_JSON_DEPTH_DEC; + if (parser->methods->object_end && FAILURE == parser->methods->object_end(parser, &$$)) { YYERROR; } } @@ -121,13 +137,15 @@ member: pair { parser->methods->object_create(parser, &$$); - if (parser->methods->object_update(parser, &$$, $1.key, &$1.val) == FAILURE) + if (parser->methods->object_update(parser, &$$, $1.key, &$1.val) == FAILURE) { YYERROR; + } } | member ',' pair { - if (parser->methods->object_update(parser, &$1, $3.key, &$3.val) == FAILURE) + if (parser->methods->object_update(parser, &$1, $3.key, &$3.val) == FAILURE) { YYERROR; + } ZVAL_COPY_VALUE(&$$, &$1); } | member errlex @@ -149,10 +167,18 @@ pair: ; array: - '[' { if (FAILURE == parser->methods->array_start(parser)) YYERROR; } elements array_end + '[' + { + PHP_JSON_DEPTH_INC; + if (parser->methods->array_start && FAILURE == parser->methods->array_start(parser)) { + YYERROR; + } + } + elements array_end { ZVAL_COPY_VALUE(&$$, &$3); - if (FAILURE == parser->methods->array_end(parser, &$$)) { + PHP_JSON_DEPTH_DEC; + if (parser->methods->array_end && FAILURE == parser->methods->array_end(parser, &$$)) { YYERROR; } } @@ -217,7 +243,7 @@ errlex: YYERROR; } ; - + %% /* Functions */ static int php_json_parser_array_create(php_json_parser *parser, zval *array) @@ -231,16 +257,6 @@ static int php_json_parser_array_append(php_json_parser *parser, zval *array, zv return SUCCESS; } -static int php_json_parser_array_start(php_json_parser *parser) -{ - return parser->methods->depth_increase(parser); -} - -static int php_json_parser_array_end(php_json_parser *parser, zval *object) -{ - return parser->methods->depth_decrease(parser); -} - static int php_json_parser_object_create(php_json_parser *parser, zval *object) { if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { @@ -268,7 +284,7 @@ static int php_json_parser_object_update(php_json_parser *parser, zval *object, return FAILURE; } ZVAL_NEW_STR(&zkey, key); - zend_std_write_property(object, &zkey, zvalue, NULL); + zend_std_write_property(object, &zkey, zvalue, NULL); if (Z_REFCOUNTED_P(zvalue)) { Z_DELREF_P(zvalue); @@ -279,32 +295,6 @@ static int php_json_parser_object_update(php_json_parser *parser, zval *object, return SUCCESS; } -static int php_json_parser_object_start(php_json_parser *parser) -{ - return parser->methods->depth_increase(parser); -} - -static int php_json_parser_object_end(php_json_parser *parser, zval *object) -{ - return parser->methods->depth_decrease(parser); -} - -static int php_json_parser_depth_increase(php_json_parser *parser) -{ - if (parser->max_depth && parser->depth >= parser->max_depth) { - parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; - return FAILURE; - } - ++parser->depth; - return SUCCESS; -} - -static int php_json_parser_depth_decrease(php_json_parser *parser) -{ - --parser->depth; - return SUCCESS; -} - static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) { int token = php_json_scan(&parser->scanner); @@ -328,14 +318,12 @@ static const php_json_parser_methods default_parser_methods = { php_json_parser_array_create, php_json_parser_array_append, - php_json_parser_array_start, - php_json_parser_array_end, + NULL, + NULL, php_json_parser_object_create, php_json_parser_object_update, - php_json_parser_object_start, - php_json_parser_object_end, - php_json_parser_depth_increase, - php_json_parser_depth_decrease + NULL, + NULL, }; void php_json_parser_init_ex(php_json_parser *parser, diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 9a3f2066676..edc6c4ee41b 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -40,10 +40,6 @@ typedef int (*php_json_parser_func_object_start_t)( php_json_parser *parser); typedef int (*php_json_parser_func_object_end_t)( php_json_parser *parser, zval *object); -typedef int (*php_json_parser_func_depth_increase_t)( - php_json_parser *parser); -typedef int (*php_json_parser_func_depth_decrease_t)( - php_json_parser *parser); typedef struct _php_json_parser_methods { php_json_parser_func_array_create_t array_create; @@ -54,8 +50,6 @@ typedef struct _php_json_parser_methods { php_json_parser_func_object_update_t object_update; php_json_parser_func_object_start_t object_start; php_json_parser_func_object_end_t object_end; - php_json_parser_func_depth_increase_t depth_increase; - php_json_parser_func_depth_decrease_t depth_decrease; } php_json_parser_methods; struct _php_json_parser { From 37048c0f6cef53b015c04c8370f94e6597588fdc Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Mon, 2 May 2016 13:02:40 +0100 Subject: [PATCH 3/5] Use embedded json parser method structure --- ext/json/json_parser.tab.c | 26 +++++++++++++------------- ext/json/json_parser.y | 26 +++++++++++++------------- ext/json/php_json_parser.h | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ext/json/json_parser.tab.c b/ext/json/json_parser.tab.c index eb8c6be5ff6..7a799f9739e 100644 --- a/ext/json/json_parser.tab.c +++ b/ext/json/json_parser.tab.c @@ -1464,7 +1464,7 @@ yyreduce: { PHP_JSON_DEPTH_INC; - if (parser->methods->object_start && FAILURE == parser->methods->object_start(parser)) { + if (parser->methods.object_start && FAILURE == parser->methods.object_start(parser)) { YYERROR; } } @@ -1476,7 +1476,7 @@ yyreduce: { ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); PHP_JSON_DEPTH_DEC; - if (parser->methods->object_end && FAILURE == parser->methods->object_end(parser, &(yyval.value))) { + if (parser->methods.object_end && FAILURE == parser->methods.object_end(parser, &(yyval.value))) { YYERROR; } } @@ -1495,7 +1495,7 @@ yyreduce: case 8: { - parser->methods->object_create(parser, &(yyval.value)); + parser->methods.object_create(parser, &(yyval.value)); } break; @@ -1503,8 +1503,8 @@ yyreduce: case 10: { - parser->methods->object_create(parser, &(yyval.value)); - if (parser->methods->object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) { + parser->methods.object_create(parser, &(yyval.value)); + if (parser->methods.object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) { YYERROR; } } @@ -1514,7 +1514,7 @@ yyreduce: case 11: { - if (parser->methods->object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) { + if (parser->methods.object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) { YYERROR; } ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); @@ -1551,7 +1551,7 @@ yyreduce: { PHP_JSON_DEPTH_INC; - if (parser->methods->array_start && FAILURE == parser->methods->array_start(parser)) { + if (parser->methods.array_start && FAILURE == parser->methods.array_start(parser)) { YYERROR; } } @@ -1563,7 +1563,7 @@ yyreduce: { ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); PHP_JSON_DEPTH_DEC; - if (parser->methods->array_end && FAILURE == parser->methods->array_end(parser, &(yyval.value))) { + if (parser->methods.array_end && FAILURE == parser->methods.array_end(parser, &(yyval.value))) { YYERROR; } } @@ -1582,7 +1582,7 @@ yyreduce: case 19: { - parser->methods->array_create(parser, &(yyval.value)); + parser->methods.array_create(parser, &(yyval.value)); } break; @@ -1590,8 +1590,8 @@ yyreduce: case 21: { - parser->methods->array_create(parser, &(yyval.value)); - parser->methods->array_append(parser, &(yyval.value), &(yyvsp[0].value)); + parser->methods.array_create(parser, &(yyval.value)); + parser->methods.array_append(parser, &(yyval.value), &(yyvsp[0].value)); } break; @@ -1599,7 +1599,7 @@ yyreduce: case 22: { - parser->methods->array_append(parser, &(yyvsp[-2].value), &(yyvsp[0].value)); + parser->methods.array_append(parser, &(yyvsp[-2].value), &(yyvsp[0].value)); ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); } @@ -1947,7 +1947,7 @@ void php_json_parser_init_ex(php_json_parser *parser, parser->depth = 1; parser->max_depth = max_depth; parser->return_value = return_value; - parser->methods = parser_methods; + memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods)); } void php_json_parser_init(php_json_parser *parser, diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index c7c4f74a160..a2d96efd8e5 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -102,7 +102,7 @@ object: '{' { PHP_JSON_DEPTH_INC; - if (parser->methods->object_start && FAILURE == parser->methods->object_start(parser)) { + if (parser->methods.object_start && FAILURE == parser->methods.object_start(parser)) { YYERROR; } } @@ -110,7 +110,7 @@ object: { ZVAL_COPY_VALUE(&$$, &$3); PHP_JSON_DEPTH_DEC; - if (parser->methods->object_end && FAILURE == parser->methods->object_end(parser, &$$)) { + if (parser->methods.object_end && FAILURE == parser->methods.object_end(parser, &$$)) { YYERROR; } } @@ -128,7 +128,7 @@ object_end: members: /* empty */ { - parser->methods->object_create(parser, &$$); + parser->methods.object_create(parser, &$$); } | member ; @@ -136,14 +136,14 @@ members: member: pair { - parser->methods->object_create(parser, &$$); - if (parser->methods->object_update(parser, &$$, $1.key, &$1.val) == FAILURE) { + parser->methods.object_create(parser, &$$); + if (parser->methods.object_update(parser, &$$, $1.key, &$1.val) == FAILURE) { YYERROR; } } | member ',' pair { - if (parser->methods->object_update(parser, &$1, $3.key, &$3.val) == FAILURE) { + if (parser->methods.object_update(parser, &$1, $3.key, &$3.val) == FAILURE) { YYERROR; } ZVAL_COPY_VALUE(&$$, &$1); @@ -170,7 +170,7 @@ array: '[' { PHP_JSON_DEPTH_INC; - if (parser->methods->array_start && FAILURE == parser->methods->array_start(parser)) { + if (parser->methods.array_start && FAILURE == parser->methods.array_start(parser)) { YYERROR; } } @@ -178,7 +178,7 @@ array: { ZVAL_COPY_VALUE(&$$, &$3); PHP_JSON_DEPTH_DEC; - if (parser->methods->array_end && FAILURE == parser->methods->array_end(parser, &$$)) { + if (parser->methods.array_end && FAILURE == parser->methods.array_end(parser, &$$)) { YYERROR; } } @@ -196,7 +196,7 @@ array_end: elements: /* empty */ { - parser->methods->array_create(parser, &$$); + parser->methods.array_create(parser, &$$); } | element ; @@ -204,12 +204,12 @@ elements: element: value { - parser->methods->array_create(parser, &$$); - parser->methods->array_append(parser, &$$, &$1); + parser->methods.array_create(parser, &$$); + parser->methods.array_append(parser, &$$, &$1); } | element ',' value { - parser->methods->array_append(parser, &$1, &$3); + parser->methods.array_append(parser, &$1, &$3); ZVAL_COPY_VALUE(&$$, &$1); } | element errlex @@ -339,7 +339,7 @@ void php_json_parser_init_ex(php_json_parser *parser, parser->depth = 1; parser->max_depth = max_depth; parser->return_value = return_value; - parser->methods = parser_methods; + memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods)); } void php_json_parser_init(php_json_parser *parser, diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index edc6c4ee41b..997213f42e4 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -57,7 +57,7 @@ struct _php_json_parser { zval *return_value; unsigned int depth; int max_depth; - const php_json_parser_methods *methods; + php_json_parser_methods methods; }; PHP_JSON_API void php_json_parser_init_ex( From b91c05ea1411778876d7afd85461864cbde0d67a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 11 May 2016 20:54:42 +0100 Subject: [PATCH 4/5] Fix and clean up exporting of json parser --- ext/json/json_parser.tab.c | 11 ++++++++--- ext/json/json_parser.y | 11 ++++++++--- ext/json/php_json_parser.h | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ext/json/json_parser.tab.c b/ext/json/json_parser.tab.c index 7a799f9739e..02002d681b2 100644 --- a/ext/json/json_parser.tab.c +++ b/ext/json/json_parser.tab.c @@ -1917,7 +1917,7 @@ static void php_json_yyerror(php_json_parser *parser, char const *msg) } } -php_json_error_code php_json_parser_error_code(const php_json_parser *parser) +PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser) { return parser->scanner.errcode; } @@ -1934,7 +1934,7 @@ static const php_json_parser_methods default_parser_methods = NULL, }; -void php_json_parser_init_ex(php_json_parser *parser, +PHP_JSON_API void php_json_parser_init_ex(php_json_parser *parser, zval *return_value, char *str, size_t str_len, @@ -1950,7 +1950,7 @@ void php_json_parser_init_ex(php_json_parser *parser, memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods)); } -void php_json_parser_init(php_json_parser *parser, +PHP_JSON_API void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, @@ -1966,3 +1966,8 @@ void php_json_parser_init(php_json_parser *parser, max_depth, &default_parser_methods); } + +PHP_JSON_API int php_json_parse(php_json_parser *parser) +{ + return php_json_yyparse(parser); +} diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index a2d96efd8e5..fafe75cbf34 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -309,7 +309,7 @@ static void php_json_yyerror(php_json_parser *parser, char const *msg) } } -php_json_error_code php_json_parser_error_code(const php_json_parser *parser) +PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser) { return parser->scanner.errcode; } @@ -326,7 +326,7 @@ static const php_json_parser_methods default_parser_methods = NULL, }; -void php_json_parser_init_ex(php_json_parser *parser, +PHP_JSON_API void php_json_parser_init_ex(php_json_parser *parser, zval *return_value, char *str, size_t str_len, @@ -342,7 +342,7 @@ void php_json_parser_init_ex(php_json_parser *parser, memcpy(&parser->methods, parser_methods, sizeof(php_json_parser_methods)); } -void php_json_parser_init(php_json_parser *parser, +PHP_JSON_API void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, @@ -358,3 +358,8 @@ void php_json_parser_init(php_json_parser *parser, max_depth, &default_parser_methods); } + +PHP_JSON_API int php_json_parse(php_json_parser *parser) +{ + return php_json_yyparse(parser); +} diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 997213f42e4..0eb9da30735 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -79,7 +79,7 @@ PHP_JSON_API void php_json_parser_init( PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser); -PHP_JSON_API int php_json_yyparse(php_json_parser *parser); +PHP_JSON_API int php_json_parse(php_json_parser *parser); #endif /* PHP_JSON_PARSER_H */ From 0a0e42d1f5867ae273198092b0eecc2e5edc25bd Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 11 May 2016 21:11:47 +0100 Subject: [PATCH 5/5] Add php_json_yyparse for direct use in json ext --- ext/json/php_json_parser.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 0eb9da30735..f817a2da70c 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -81,5 +81,7 @@ PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parse PHP_JSON_API int php_json_parse(php_json_parser *parser); +int php_json_yyparse(php_json_parser *parser); + #endif /* PHP_JSON_PARSER_H */