From be910215bddd4e80023ea7875938dae04bb27bc2 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Wed, 26 Jun 2024 01:57:33 -0300 Subject: [PATCH 01/16] WIP - tests are working with GCC warnings --- ext/json/json.c | 32 +++++++++++++++++++++++++-- ext/json/json_parser.y | 24 ++++++++++++++++++++ ext/json/json_scanner.re | 8 +++++++ ext/json/php_json.h | 1 + ext/json/php_json_parser.h | 2 ++ ext/json/php_json_scanner.h | 2 ++ ext/json/tests/json_validate_001.phpt | 2 +- ext/json/tests/json_validate_002.phpt | 6 ++--- ext/json/tests/json_validate_004.phpt | 10 ++++----- 9 files changed, 76 insertions(+), 11 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 1ea8eb56f901f..274b84d9bfe90 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -70,6 +70,17 @@ static PHP_GINIT_FUNCTION(json) static PHP_RINIT_FUNCTION(json) { JSON_G(error_code) = 0; + JSON_G(error_msg) = NULL; + + return SUCCESS; +} + +static PHP_RSHUTDOWN_FUNCTION(json) +{ + if (JSON_G(error_msg)) { + efree(JSON_G(error_msg)); + } + return SUCCESS; } @@ -209,6 +220,8 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); JSON_G(error_code) = error_code; + php_json_ctype* error_msg = php_json_parser_error_msg(&parser); + JSON_G(error_msg) = error_msg; return false; } @@ -359,11 +372,26 @@ PHP_FUNCTION(json_last_error) } /* }}} */ -/* {{{ Returns the error string of the last json_encode() or json_decode() call. */ +/* {{{ Returns the error string of the last json_validate(), json_encode() or json_decode() call. */ PHP_FUNCTION(json_last_error_msg) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_STRING(php_json_get_error_msg(JSON_G(error_code))); + const char* msg = php_json_get_error_msg(JSON_G(error_code)); + + if (JSON_G(error_code) == PHP_JSON_ERROR_NONE) { + RETURN_STRING(msg); + } + + char* msg_combined; + + if (JSON_G(error_msg) && strlen((const char*) JSON_G(error_msg)) > 0) { + spprintf(&msg_combined, 0, "%s - %s", msg, (const char*) JSON_G(error_msg)); + RETVAL_STRING(msg_combined); + efree(msg_combined); + return; + } else { + RETURN_STRING(msg); + } } /* }}} */ diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index d570cddc91e4b..5d97cf631d458 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -19,6 +19,7 @@ #include "php.h" #include "php_json.h" #include "php_json_parser.h" +#include "php_json_scanner.h" #define YYDEBUG 0 @@ -301,6 +302,24 @@ static void php_json_yyerror(php_json_parser *parser, char const *msg) if (!parser->scanner.errcode) { parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; } + + char error_message[256]; + snprintf( + error_message, + sizeof(error_message), + "error: %s, at character %ld near content: %s", + msg, + parser->scanner.character_count, + parser->scanner.token + ); + + if (parser->scanner.error_msg) { + free(parser->scanner.error_msg); + } + + parser->scanner.error_msg = (php_json_ctype *) malloc(strlen(error_message) + 1); + + memcpy(parser->scanner.error_msg, error_message, strlen(error_message) + 1); } PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser) @@ -308,6 +327,11 @@ PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parse return parser->scanner.errcode; } +PHP_JSON_API php_json_ctype* php_json_parser_error_msg(const php_json_parser *parser) +{ + return parser->scanner.error_msg; +} + static const php_json_parser_methods default_parser_methods = { php_json_parser_array_create, diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re index 0debb3b03cb22..34a446821587d 100644 --- a/ext/json/json_scanner.re +++ b/ext/json/json_scanner.re @@ -96,16 +96,24 @@ void php_json_scanner_init(php_json_scanner *s, const char *str, size_t str_len, s->cursor = (php_json_ctype *) str; s->limit = (php_json_ctype *) str + str_len; s->options = options; + s->character_count = 0; PHP_JSON_CONDITION_SET(JS); } int php_json_scan(php_json_scanner *s) { ZVAL_NULL(&s->value); + static unsigned long int token_total_length = 0; std: s->token = s->cursor; + if (token_total_length == 0) { + token_total_length = strlen((const char*) s->token); + } else { + s->character_count = token_total_length + (-1 * strlen((const char*) s->token)); + } + /*!re2c re2c:indent:top = 1; re2c:yyfill:enable = 0; diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 00c87eca53c9e..3ae021996584b 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -90,6 +90,7 @@ ZEND_BEGIN_MODULE_GLOBALS(json) int encoder_depth; int encode_max_depth; php_json_error_code error_code; + unsigned char *error_msg; ZEND_END_MODULE_GLOBALS(json) PHP_JSON_API ZEND_EXTERN_MODULE_GLOBALS(json) diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 8aedce9ac55d6..cacbabada64c8 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -77,6 +77,8 @@ 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 php_json_ctype* php_json_parser_error_msg(const php_json_parser *parser); + PHP_JSON_API int php_json_parse(php_json_parser *parser); int php_json_yyparse(php_json_parser *parser); diff --git a/ext/json/php_json_scanner.h b/ext/json/php_json_scanner.h index a49be68cd6328..b9fa6eeff08bc 100644 --- a/ext/json/php_json_scanner.h +++ b/ext/json/php_json_scanner.h @@ -30,6 +30,7 @@ typedef struct _php_json_scanner { php_json_ctype *ctxmarker; /* marker position for context backtracking */ php_json_ctype *str_start; /* start position of the string */ php_json_ctype *pstr; /* string pointer for escapes conversion */ + php_json_ctype *error_msg; /* error message if there is an error */ zval value; /* value */ int str_esc; /* number of extra characters for escaping */ int state; /* condition state */ @@ -37,6 +38,7 @@ typedef struct _php_json_scanner { php_json_error_code errcode; /* error type if there is an error */ int utf8_invalid; /* whether utf8 is invalid */ int utf8_invalid_count; /* number of extra character for invalid utf8 */ + size_t character_count; /* counts the number of characters scanned (not tokens) */ } php_json_scanner; diff --git a/ext/json/tests/json_validate_001.phpt b/ext/json/tests/json_validate_001.phpt index 2330166aa7c36..8adc0a23e9044 100644 --- a/ext/json/tests/json_validate_001.phpt +++ b/ext/json/tests/json_validate_001.phpt @@ -19,7 +19,7 @@ var_dump( json_validate('{ "": { "foo": "" } }'), json_validate('{ "": { "": "" } }'), json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), - json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test3": {"foo" : "bar" } }'), + json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test3": {"foo" : "bar" } }') ); ?> diff --git a/ext/json/tests/json_validate_002.phpt b/ext/json/tests/json_validate_002.phpt index 53f4e4f2c2ea1..496b22506dc54 100644 --- a/ext/json/tests/json_validate_002.phpt +++ b/ext/json/tests/json_validate_002.phpt @@ -23,10 +23,10 @@ int(4) string(12) "Syntax error" bool(false) int(4) -string(12) "Syntax error" +string(66) "Syntax error - error: syntax error, at character 0 near content: -" bool(false) int(4) -string(12) "Syntax error" +string(66) "Syntax error - error: syntax error, at character 0 near content: -" bool(false) int(1) string(28) "Maximum stack depth exceeded" @@ -44,7 +44,7 @@ int(0) string(8) "No error" bool(false) int(4) -string(12) "Syntax error" +string(66) "Syntax error - error: syntax error, at character 0 near content: -" bool(true) int(0) string(8) "No error" diff --git a/ext/json/tests/json_validate_004.phpt b/ext/json/tests/json_validate_004.phpt index d8a798d943278..3f9652711455a 100644 --- a/ext/json/tests/json_validate_004.phpt +++ b/ext/json/tests/json_validate_004.phpt @@ -19,20 +19,20 @@ json_validate_trycatchdump("\"\x61\xf0\x80\x80\x41\"", 512, JSON_INVALID_UTF8_IG json_validate_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_INVALID_UTF8_IGNORE); ?> ---EXPECT-- +--EXPECTF-- Testing Invalid UTF-8 bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(114) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 0 near content: %s" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(116) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character -1 near content: %s" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(117) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character -2 near content: %s" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(119) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character -4 near content: %s" bool(true) int(0) string(8) "No error" From c8590bfade87774da8c1cc213eeace9888150604 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Thu, 27 Jun 2024 16:56:39 -0300 Subject: [PATCH 02/16] no compiler warnings or memory leaks --- ext/json/json.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 274b84d9bfe90..2e03e60052164 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -78,7 +78,7 @@ static PHP_RINIT_FUNCTION(json) static PHP_RSHUTDOWN_FUNCTION(json) { if (JSON_G(error_msg)) { - efree(JSON_G(error_msg)); + free(JSON_G(error_msg)); } return SUCCESS; @@ -92,7 +92,7 @@ zend_module_entry json_module_entry = { PHP_MINIT(json), NULL, PHP_RINIT(json), - NULL, + PHP_RSHUTDOWN(json), PHP_MINFO(json), PHP_JSON_VERSION, PHP_MODULE_GLOBALS(json), From 60aa905573f88ba97356ead52b32a83018f7a82e Mon Sep 17 00:00:00 2001 From: juan-morales Date: Thu, 27 Jun 2024 18:48:02 -0300 Subject: [PATCH 03/16] switch to char[array] instead of char* for the message --- ext/json/json.c | 19 ++++--------------- ext/json/json_parser.y | 21 +++------------------ ext/json/php_json.h | 2 +- ext/json/php_json_scanner.h | 2 +- 4 files changed, 9 insertions(+), 35 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 2e03e60052164..eaede09eefa45 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -70,17 +70,6 @@ static PHP_GINIT_FUNCTION(json) static PHP_RINIT_FUNCTION(json) { JSON_G(error_code) = 0; - JSON_G(error_msg) = NULL; - - return SUCCESS; -} - -static PHP_RSHUTDOWN_FUNCTION(json) -{ - if (JSON_G(error_msg)) { - free(JSON_G(error_msg)); - } - return SUCCESS; } @@ -92,7 +81,7 @@ zend_module_entry json_module_entry = { PHP_MINIT(json), NULL, PHP_RINIT(json), - PHP_RSHUTDOWN(json), + NULL, PHP_MINFO(json), PHP_JSON_VERSION, PHP_MODULE_GLOBALS(json), @@ -216,12 +205,12 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon zval tmp; const php_json_parser_methods* parser_validate_methods = php_json_get_validate_methods(); php_json_parser_init_ex(&parser, &tmp, str, str_len, (int)options, (int)depth, parser_validate_methods); - + if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); JSON_G(error_code) = error_code; - php_json_ctype* error_msg = php_json_parser_error_msg(&parser); - JSON_G(error_msg) = error_msg; + strcpy(JSON_G(error_msg), parser.scanner.error_msg); + return false; } diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 5d97cf631d458..18530d09b4825 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -303,23 +303,13 @@ static void php_json_yyerror(php_json_parser *parser, char const *msg) parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; } - char error_message[256]; - snprintf( - error_message, - sizeof(error_message), + sprintf( + parser->scanner.error_msg, "error: %s, at character %ld near content: %s", msg, parser->scanner.character_count, - parser->scanner.token + (const char*) parser->scanner.token ); - - if (parser->scanner.error_msg) { - free(parser->scanner.error_msg); - } - - parser->scanner.error_msg = (php_json_ctype *) malloc(strlen(error_message) + 1); - - memcpy(parser->scanner.error_msg, error_message, strlen(error_message) + 1); } PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser) @@ -327,11 +317,6 @@ PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parse return parser->scanner.errcode; } -PHP_JSON_API php_json_ctype* php_json_parser_error_msg(const php_json_parser *parser) -{ - return parser->scanner.error_msg; -} - static const php_json_parser_methods default_parser_methods = { php_json_parser_array_create, diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 3ae021996584b..6946aca763f77 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -90,7 +90,7 @@ ZEND_BEGIN_MODULE_GLOBALS(json) int encoder_depth; int encode_max_depth; php_json_error_code error_code; - unsigned char *error_msg; + char error_msg[256]; ZEND_END_MODULE_GLOBALS(json) PHP_JSON_API ZEND_EXTERN_MODULE_GLOBALS(json) diff --git a/ext/json/php_json_scanner.h b/ext/json/php_json_scanner.h index b9fa6eeff08bc..2aba2f344f01a 100644 --- a/ext/json/php_json_scanner.h +++ b/ext/json/php_json_scanner.h @@ -30,7 +30,7 @@ typedef struct _php_json_scanner { php_json_ctype *ctxmarker; /* marker position for context backtracking */ php_json_ctype *str_start; /* start position of the string */ php_json_ctype *pstr; /* string pointer for escapes conversion */ - php_json_ctype *error_msg; /* error message if there is an error */ + char error_msg[256]; /* error message if there is an error */ zval value; /* value */ int str_esc; /* number of extra characters for escaping */ int state; /* condition state */ From 19672153c57afb17efe11d684d81e777abec3804 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Thu, 27 Jun 2024 18:51:17 -0300 Subject: [PATCH 04/16] prevent bufferoverflow --- ext/json/json_parser.y | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 18530d09b4825..4d2e2d0d0d90b 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -303,8 +303,9 @@ static void php_json_yyerror(php_json_parser *parser, char const *msg) parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; } - sprintf( + snprintf( parser->scanner.error_msg, + sizeof(parser->scanner.error_msg), "error: %s, at character %ld near content: %s", msg, parser->scanner.character_count, From 376c6547afb937c959a94f9d81e286c4c3d12b12 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Thu, 27 Jun 2024 18:55:40 -0300 Subject: [PATCH 05/16] adjust json_last_error_msg php function to the new message type char[256] --- ext/json/json.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index eaede09eefa45..99c9c4c67f26c 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -372,13 +372,11 @@ PHP_FUNCTION(json_last_error_msg) RETURN_STRING(msg); } - char* msg_combined; + char msg_combined[256]; - if (JSON_G(error_msg) && strlen((const char*) JSON_G(error_msg)) > 0) { - spprintf(&msg_combined, 0, "%s - %s", msg, (const char*) JSON_G(error_msg)); + if (strlen(JSON_G(error_msg)) > 0) { + snprintf(msg_combined, sizeof(msg_combined), "%s - %s", msg, JSON_G(error_msg)); RETVAL_STRING(msg_combined); - efree(msg_combined); - return; } else { RETURN_STRING(msg); } From 9125d922e65dff2f357193b4ec5f156dde25e019 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Thu, 27 Jun 2024 20:15:25 -0300 Subject: [PATCH 06/16] - --- ext/json/json_parser.y | 2 +- ext/json/json_scanner.re | 8 +++---- ext/json/php_json_scanner.h | 1 + ext/json/tests/json_validate_001.phpt | 32 ++++++++++++++++++++++++++- ext/json/tests/json_validate_004.phpt | 6 ++--- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 4d2e2d0d0d90b..71cd694b121b2 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -306,7 +306,7 @@ static void php_json_yyerror(php_json_parser *parser, char const *msg) snprintf( parser->scanner.error_msg, sizeof(parser->scanner.error_msg), - "error: %s, at character %ld near content: %s", + "error: %s, at character %zu near content: %s", msg, parser->scanner.character_count, (const char*) parser->scanner.token diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re index 34a446821587d..e47aaf5f53aad 100644 --- a/ext/json/json_scanner.re +++ b/ext/json/json_scanner.re @@ -97,21 +97,21 @@ void php_json_scanner_init(php_json_scanner *s, const char *str, size_t str_len, s->limit = (php_json_ctype *) str + str_len; s->options = options; s->character_count = 0; + s->character_max_count = 0; PHP_JSON_CONDITION_SET(JS); } int php_json_scan(php_json_scanner *s) { ZVAL_NULL(&s->value); - static unsigned long int token_total_length = 0; std: s->token = s->cursor; - if (token_total_length == 0) { - token_total_length = strlen((const char*) s->token); + if (s->character_max_count == 0) { + s->character_max_count = strlen((const char*) s->token); } else { - s->character_count = token_total_length + (-1 * strlen((const char*) s->token)); + s->character_count = s->character_max_count + (-1 * strlen((const char*) s->token)); } /*!re2c diff --git a/ext/json/php_json_scanner.h b/ext/json/php_json_scanner.h index 2aba2f344f01a..e8cd4b752cc45 100644 --- a/ext/json/php_json_scanner.h +++ b/ext/json/php_json_scanner.h @@ -39,6 +39,7 @@ typedef struct _php_json_scanner { int utf8_invalid; /* whether utf8 is invalid */ int utf8_invalid_count; /* number of extra character for invalid utf8 */ size_t character_count; /* counts the number of characters scanned (not tokens) */ + size_t character_max_count; } php_json_scanner; diff --git a/ext/json/tests/json_validate_001.phpt b/ext/json/tests/json_validate_001.phpt index 8adc0a23e9044..1124e8c2df689 100644 --- a/ext/json/tests/json_validate_001.phpt +++ b/ext/json/tests/json_validate_001.phpt @@ -5,37 +5,67 @@ json_validate() - General usage var_dump( json_validate(""), + json_last_error_msg(), json_validate("."), + json_last_error_msg(), json_validate(""), + json_last_error_msg(), json_validate(";"), + json_last_error_msg(), json_validate("руссиш"), + json_last_error_msg(), json_validate("blah"), + json_last_error_msg(), json_validate('{ "": "": "" } }'), + json_last_error_msg(), json_validate('{ "": { "": "" }'), + json_last_error_msg(), json_validate('{ "test": {} "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), + json_last_error_msg(), json_validate('{ "test": { "foo": "bar" } }'), + json_last_error_msg(), json_validate('{ "test": { "foo": "" } }'), + json_last_error_msg(), json_validate('{ "": { "foo": "" } }'), + json_last_error_msg(), json_validate('{ "": { "": "" } }'), + json_last_error_msg(), json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), - json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test3": {"foo" : "bar" } }') + json_last_error_msg(), + json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test3": {"foo" : "bar" } }'), + json_last_error_msg(), ); ?> --EXPECT-- bool(false) +string(12) "Syntax error" bool(false) +string(66) "Syntax error - error: syntax error, at character 0 near content: ." bool(false) +string(68) "Syntax error - error: syntax error, at character 0 near content: " bool(false) +string(66) "Syntax error - error: syntax error, at character 0 near content: ;" bool(false) +string(77) "Syntax error - error: syntax error, at character 0 near content: руссиш" bool(false) +string(69) "Syntax error - error: syntax error, at character 0 near content: blah" bool(false) +string(73) "Syntax error - error: syntax error, at character 8 near content: : "" } }" bool(false) +string(66) "Syntax error - error: syntax error, at character 16 near content: " bool(false) +string(136) "Syntax error - error: syntax error, at character 13 near content: "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }" bool(true) +string(8) "No error" bool(true) +string(8) "No error" bool(true) +string(8) "No error" bool(true) +string(8) "No error" bool(true) +string(8) "No error" bool(true) +string(8) "No error" diff --git a/ext/json/tests/json_validate_004.phpt b/ext/json/tests/json_validate_004.phpt index 3f9652711455a..61d5441baf8fb 100644 --- a/ext/json/tests/json_validate_004.phpt +++ b/ext/json/tests/json_validate_004.phpt @@ -26,13 +26,13 @@ int(5) string(114) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 0 near content: %s" bool(false) int(5) -string(116) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character -1 near content: %s" +string(115) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 0 near content: %s" bool(false) int(5) -string(117) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character -2 near content: %s" +string(116) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 0 near content: %s" bool(false) int(5) -string(119) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character -4 near content: %s" +string(118) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 1 near content: %s" bool(true) int(0) string(8) "No error" From 5e7de7b5fc6d74c5cac6dd91f4e7d7b609ff9ad0 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Thu, 27 Jun 2024 22:48:21 -0300 Subject: [PATCH 07/16] wip --- ext/json/json.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 99c9c4c67f26c..cc5eb408cb6b3 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -209,7 +209,10 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); JSON_G(error_code) = error_code; - strcpy(JSON_G(error_msg), parser.scanner.error_msg); + + if (strlen(parser.scanner.error_msg) > 5) { + strcpy(JSON_G(error_msg), parser.scanner.error_msg); + } return false; } @@ -374,7 +377,7 @@ PHP_FUNCTION(json_last_error_msg) char msg_combined[256]; - if (strlen(JSON_G(error_msg)) > 0) { + if (strlen(JSON_G(error_msg)) > 5) { snprintf(msg_combined, sizeof(msg_combined), "%s - %s", msg, JSON_G(error_msg)); RETVAL_STRING(msg_combined); } else { From 79aa999de1edfcd7873d8c97f0083da43764b9bd Mon Sep 17 00:00:00 2001 From: juan-morales Date: Fri, 28 Jun 2024 00:34:23 -0300 Subject: [PATCH 08/16] - --- ext/json/json.c | 19 +++++++++++++++---- ext/json/json_scanner.re | 2 ++ ext/json/tests/json_validate_002.phpt | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index cc5eb408cb6b3..7c344dbf43595 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -70,6 +70,13 @@ static PHP_GINIT_FUNCTION(json) static PHP_RINIT_FUNCTION(json) { JSON_G(error_code) = 0; + JSON_G(error_msg)[0] = '\0'; + return SUCCESS; +} + +static PHP_RSHUTDOWN_FUNCTION(json) +{ + JSON_G(error_msg)[0] = '\0'; return SUCCESS; } @@ -81,7 +88,7 @@ zend_module_entry json_module_entry = { PHP_MINIT(json), NULL, PHP_RINIT(json), - NULL, + PHP_RSHUTDOWN(json), PHP_MINFO(json), PHP_JSON_VERSION, PHP_MODULE_GLOBALS(json), @@ -210,8 +217,11 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon php_json_error_code error_code = php_json_parser_error_code(&parser); JSON_G(error_code) = error_code; - if (strlen(parser.scanner.error_msg) > 5) { - strcpy(JSON_G(error_msg), parser.scanner.error_msg); + JSON_G(error_msg)[0] = '\0'; + + if (parser.scanner.error_msg[0] != '\0') { + strncpy(JSON_G(error_msg), parser.scanner.error_msg, sizeof(JSON_G(error_msg)) - 1); + JSON_G(error_msg)[sizeof(JSON_G(error_msg)) - 1] = '\0'; } return false; @@ -328,6 +338,7 @@ PHP_FUNCTION(json_validate) Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); + JSON_G(error_msg)[0] = '\0'; if ((options != 0) && (options != PHP_JSON_INVALID_UTF8_IGNORE)) { zend_argument_value_error(3, "must be a valid flag (allowed flags: JSON_INVALID_UTF8_IGNORE)"); @@ -377,7 +388,7 @@ PHP_FUNCTION(json_last_error_msg) char msg_combined[256]; - if (strlen(JSON_G(error_msg)) > 5) { + if (JSON_G(error_msg)[0] != '\0') { snprintf(msg_combined, sizeof(msg_combined), "%s - %s", msg, JSON_G(error_msg)); RETVAL_STRING(msg_combined); } else { diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re index e47aaf5f53aad..2503930f19868 100644 --- a/ext/json/json_scanner.re +++ b/ext/json/json_scanner.re @@ -98,6 +98,7 @@ void php_json_scanner_init(php_json_scanner *s, const char *str, size_t str_len, s->options = options; s->character_count = 0; s->character_max_count = 0; + s->error_msg[0] = '\0'; PHP_JSON_CONDITION_SET(JS); } @@ -110,6 +111,7 @@ std: if (s->character_max_count == 0) { s->character_max_count = strlen((const char*) s->token); + s->error_msg[0] = '\0'; } else { s->character_count = s->character_max_count + (-1 * strlen((const char*) s->token)); } diff --git a/ext/json/tests/json_validate_002.phpt b/ext/json/tests/json_validate_002.phpt index 496b22506dc54..be0a9dbded2c2 100644 --- a/ext/json/tests/json_validate_002.phpt +++ b/ext/json/tests/json_validate_002.phpt @@ -26,7 +26,7 @@ int(4) string(66) "Syntax error - error: syntax error, at character 0 near content: -" bool(false) int(4) -string(66) "Syntax error - error: syntax error, at character 0 near content: -" +string(12) "Syntax error" bool(false) int(1) string(28) "Maximum stack depth exceeded" From e832ae18f191c2276fbd8cfacea2ea20cb145547 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Fri, 28 Jun 2024 20:08:14 -0300 Subject: [PATCH 09/16] switch to a new function json_last_error_info() - first try --- ext/json/json.c | 79 ++++++---- ext/json/json.stub.php | 2 + ext/json/json_arginfo.h | 7 +- ext/json/json_parser.y | 9 -- ext/json/json_scanner.re | 2 - ext/json/php_json.h | 1 - ext/json/php_json_parser.h | 2 - ext/json/php_json_scanner.h | 1 - ext/json/tests/json_validate_001.phpt | 211 +++++++++++++++++++++++++- ext/json/tests/json_validate_002.phpt | 4 +- ext/json/tests/json_validate_004.phpt | 8 +- 11 files changed, 267 insertions(+), 59 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 7c344dbf43595..79f54b9adfa4b 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -25,6 +25,7 @@ #include "php_json.h" #include "php_json_encoder.h" #include "php_json_parser.h" +#include "php_json_scanner.h" #include "json_arginfo.h" #include @@ -35,6 +36,28 @@ PHP_JSON_API zend_class_entry *php_json_exception_ce; PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json) +php_json_scanner parser_scanner_temporal; + +void reset_global_parser_scanner_fields(void) +{ + parser_scanner_temporal.cursor = NULL; + parser_scanner_temporal.token = NULL; + parser_scanner_temporal.limit = NULL; + parser_scanner_temporal.marker = NULL; + parser_scanner_temporal.ctxmarker = NULL; + parser_scanner_temporal.str_start = NULL; + parser_scanner_temporal.pstr = NULL; + //ZVAL_NULL(scanner->value) + parser_scanner_temporal.str_esc = 0; + parser_scanner_temporal.state = 0; + parser_scanner_temporal.options = 0; + parser_scanner_temporal.errcode = 0; + parser_scanner_temporal.utf8_invalid = 0; + parser_scanner_temporal.utf8_invalid_count = 0; + parser_scanner_temporal.character_count = 0; + parser_scanner_temporal.character_max_count = 0; +} + static int php_json_implement_json_serializable(zend_class_entry *interface, zend_class_entry *class_type) { class_type->ce_flags |= ZEND_ACC_USE_GUARDS; @@ -70,13 +93,6 @@ static PHP_GINIT_FUNCTION(json) static PHP_RINIT_FUNCTION(json) { JSON_G(error_code) = 0; - JSON_G(error_msg)[0] = '\0'; - return SUCCESS; -} - -static PHP_RSHUTDOWN_FUNCTION(json) -{ - JSON_G(error_msg)[0] = '\0'; return SUCCESS; } @@ -88,7 +104,7 @@ zend_module_entry json_module_entry = { PHP_MINIT(json), NULL, PHP_RINIT(json), - PHP_RSHUTDOWN(json), + NULL, PHP_MINFO(json), PHP_JSON_VERSION, PHP_MODULE_GLOBALS(json), @@ -192,12 +208,15 @@ PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); + if (!(options & PHP_JSON_THROW_ON_ERROR)) { JSON_G(error_code) = error_code; } else { zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code); } + RETVAL_NULL(); + return FAILURE; } @@ -212,18 +231,11 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon zval tmp; const php_json_parser_methods* parser_validate_methods = php_json_get_validate_methods(); php_json_parser_init_ex(&parser, &tmp, str, str_len, (int)options, (int)depth, parser_validate_methods); - + if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); JSON_G(error_code) = error_code; - - JSON_G(error_msg)[0] = '\0'; - - if (parser.scanner.error_msg[0] != '\0') { - strncpy(JSON_G(error_msg), parser.scanner.error_msg, sizeof(JSON_G(error_msg)) - 1); - JSON_G(error_msg)[sizeof(JSON_G(error_msg)) - 1] = '\0'; - } - + parser_scanner_temporal = parser.scanner; return false; } @@ -338,13 +350,13 @@ PHP_FUNCTION(json_validate) Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); - JSON_G(error_msg)[0] = '\0'; - if ((options != 0) && (options != PHP_JSON_INVALID_UTF8_IGNORE)) { zend_argument_value_error(3, "must be a valid flag (allowed flags: JSON_INVALID_UTF8_IGNORE)"); RETURN_THROWS(); } + reset_global_parser_scanner_fields(); + if (!str_len) { JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; RETURN_FALSE; @@ -366,7 +378,7 @@ PHP_FUNCTION(json_validate) } /* }}} */ -/* {{{ Returns the error code of the last json_encode() or json_decode() call. */ +/* {{{ Returns the error code of the last json_validate(), json_encode() or json_decode() call. */ PHP_FUNCTION(json_last_error) { ZEND_PARSE_PARAMETERS_NONE(); @@ -380,19 +392,28 @@ PHP_FUNCTION(json_last_error_msg) { ZEND_PARSE_PARAMETERS_NONE(); + RETURN_STRING(php_json_get_error_msg(JSON_G(error_code))); +} +/* }}} */ + +/* {{{ Returns an array with parser-scanner information of the last error of the last json_validate(), json_encode() or json_decode() call. */ +PHP_FUNCTION(json_last_error_info) +{ + ZEND_PARSE_PARAMETERS_NONE(); + const char* msg = php_json_get_error_msg(JSON_G(error_code)); - if (JSON_G(error_code) == PHP_JSON_ERROR_NONE) { - RETURN_STRING(msg); - } - - char msg_combined[256]; + array_init(return_value); + + add_assoc_long(return_value, "error_code", parser_scanner_temporal.errcode); + add_assoc_string(return_value, "error_msg", msg); + add_assoc_long(return_value, "error_position", parser_scanner_temporal.character_count); + add_assoc_long(return_value, "total_input_length", parser_scanner_temporal.character_max_count); - if (JSON_G(error_msg)[0] != '\0') { - snprintf(msg_combined, sizeof(msg_combined), "%s - %s", msg, JSON_G(error_msg)); - RETVAL_STRING(msg_combined); + if (parser_scanner_temporal.token) { + add_assoc_string(return_value, "at_content", (char *) parser_scanner_temporal.token); } else { - RETURN_STRING(msg); + add_assoc_string(return_value, "at_content", ""); } } /* }}} */ diff --git a/ext/json/json.stub.php b/ext/json/json.stub.php index a805c3893dd10..ae14271851651 100644 --- a/ext/json/json.stub.php +++ b/ext/json/json.stub.php @@ -163,6 +163,8 @@ function json_last_error(): int {} /** @refcount 1 */ function json_last_error_msg(): string {} +function json_last_error_info(): array {} + interface JsonSerializable { /** @tentative-return-type */ diff --git a/ext/json/json_arginfo.h b/ext/json/json_arginfo.h index a02cfd4a78105..2afa36654dc8e 100644 --- a/ext/json/json_arginfo.h +++ b/ext/json/json_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0ceb50047401c4b9e878c09cc518eacc274f7fff */ + * Stub hash: feb59cc47fa5b6fbca611a9d84f9b5ce9e6d4d0b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_json_encode, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) @@ -26,6 +26,9 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_msg, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_info, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_JsonSerializable_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() @@ -34,6 +37,7 @@ ZEND_FUNCTION(json_decode); ZEND_FUNCTION(json_validate); ZEND_FUNCTION(json_last_error); ZEND_FUNCTION(json_last_error_msg); +ZEND_FUNCTION(json_last_error_info); static const zend_function_entry ext_functions[] = { ZEND_FE(json_encode, arginfo_json_encode) @@ -41,6 +45,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(json_validate, arginfo_json_validate) ZEND_FE(json_last_error, arginfo_json_last_error) ZEND_FE(json_last_error_msg, arginfo_json_last_error_msg) + ZEND_FE(json_last_error_info, arginfo_json_last_error_info) ZEND_FE_END }; diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 71cd694b121b2..f5ed86b767899 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -302,15 +302,6 @@ static void php_json_yyerror(php_json_parser *parser, char const *msg) if (!parser->scanner.errcode) { parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; } - - snprintf( - parser->scanner.error_msg, - sizeof(parser->scanner.error_msg), - "error: %s, at character %zu near content: %s", - msg, - parser->scanner.character_count, - (const char*) parser->scanner.token - ); } PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser) diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re index 2503930f19868..e47aaf5f53aad 100644 --- a/ext/json/json_scanner.re +++ b/ext/json/json_scanner.re @@ -98,7 +98,6 @@ void php_json_scanner_init(php_json_scanner *s, const char *str, size_t str_len, s->options = options; s->character_count = 0; s->character_max_count = 0; - s->error_msg[0] = '\0'; PHP_JSON_CONDITION_SET(JS); } @@ -111,7 +110,6 @@ std: if (s->character_max_count == 0) { s->character_max_count = strlen((const char*) s->token); - s->error_msg[0] = '\0'; } else { s->character_count = s->character_max_count + (-1 * strlen((const char*) s->token)); } diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 6946aca763f77..00c87eca53c9e 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -90,7 +90,6 @@ ZEND_BEGIN_MODULE_GLOBALS(json) int encoder_depth; int encode_max_depth; php_json_error_code error_code; - char error_msg[256]; ZEND_END_MODULE_GLOBALS(json) PHP_JSON_API ZEND_EXTERN_MODULE_GLOBALS(json) diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index cacbabada64c8..8aedce9ac55d6 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -77,8 +77,6 @@ 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 php_json_ctype* php_json_parser_error_msg(const php_json_parser *parser); - PHP_JSON_API int php_json_parse(php_json_parser *parser); int php_json_yyparse(php_json_parser *parser); diff --git a/ext/json/php_json_scanner.h b/ext/json/php_json_scanner.h index e8cd4b752cc45..bcb24049c7009 100644 --- a/ext/json/php_json_scanner.h +++ b/ext/json/php_json_scanner.h @@ -30,7 +30,6 @@ typedef struct _php_json_scanner { php_json_ctype *ctxmarker; /* marker position for context backtracking */ php_json_ctype *str_start; /* start position of the string */ php_json_ctype *pstr; /* string pointer for escapes conversion */ - char error_msg[256]; /* error message if there is an error */ zval value; /* value */ int str_esc; /* number of extra characters for escaping */ int state; /* condition state */ diff --git a/ext/json/tests/json_validate_001.phpt b/ext/json/tests/json_validate_001.phpt index 1124e8c2df689..3d96b25af6681 100644 --- a/ext/json/tests/json_validate_001.phpt +++ b/ext/json/tests/json_validate_001.phpt @@ -6,66 +6,261 @@ json_validate() - General usage var_dump( json_validate(""), json_last_error_msg(), + json_last_error_info(), json_validate("."), json_last_error_msg(), + json_last_error_info(), json_validate(""), json_last_error_msg(), + json_last_error_info(), json_validate(";"), json_last_error_msg(), + json_last_error_info(), json_validate("руссиш"), json_last_error_msg(), + json_last_error_info(), json_validate("blah"), json_last_error_msg(), + json_last_error_info(), json_validate('{ "": "": "" } }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "": { "": "" }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "test": {} "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "test": { "foo": "bar" } }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "test": { "foo": "" } }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "": { "foo": "" } }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "": { "": "" } }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), json_last_error_msg(), + json_last_error_info(), json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test3": {"foo" : "bar" } }'), json_last_error_msg(), + json_last_error_info(), ); ?> --EXPECT-- bool(false) string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(0) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(0) + ["at_content"]=> + string(0) "" +} bool(false) -string(66) "Syntax error - error: syntax error, at character 0 near content: ." +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(1) + ["at_content"]=> + string(1) "." +} bool(false) -string(68) "Syntax error - error: syntax error, at character 0 near content: " +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(3) + ["at_content"]=> + string(3) "" +} bool(false) -string(66) "Syntax error - error: syntax error, at character 0 near content: ;" +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(1) + ["at_content"]=> + string(1) ";" +} bool(false) -string(77) "Syntax error - error: syntax error, at character 0 near content: руссиш" +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(12) + ["at_content"]=> + string(12) "руссиш" +} bool(false) -string(69) "Syntax error - error: syntax error, at character 0 near content: blah" +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(4) + ["at_content"]=> + string(4) "blah" +} bool(false) -string(73) "Syntax error - error: syntax error, at character 8 near content: : "" } }" +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(8) + ["total_input_length"]=> + int(16) + ["at_content"]=> + string(8) ": "" } }" +} bool(false) -string(66) "Syntax error - error: syntax error, at character 16 near content: " +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(16) + ["total_input_length"]=> + int(16) + ["at_content"]=> + string(0) "" +} bool(false) -string(136) "Syntax error - error: syntax error, at character 13 near content: "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }" +string(12) "Syntax error" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(13) + ["total_input_length"]=> + int(83) + ["at_content"]=> + string(70) ""foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }" +} bool(true) string(8) "No error" +array(5) { + ["error_code"]=> + int(0) + ["error_msg"]=> + string(8) "No error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(0) + ["at_content"]=> + string(0) "" +} bool(true) string(8) "No error" +array(5) { + ["error_code"]=> + int(0) + ["error_msg"]=> + string(8) "No error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(0) + ["at_content"]=> + string(0) "" +} bool(true) string(8) "No error" +array(5) { + ["error_code"]=> + int(0) + ["error_msg"]=> + string(8) "No error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(0) + ["at_content"]=> + string(0) "" +} bool(true) string(8) "No error" +array(5) { + ["error_code"]=> + int(0) + ["error_msg"]=> + string(8) "No error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(0) + ["at_content"]=> + string(0) "" +} bool(true) string(8) "No error" +array(5) { + ["error_code"]=> + int(0) + ["error_msg"]=> + string(8) "No error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(0) + ["at_content"]=> + string(0) "" +} bool(true) string(8) "No error" +array(5) { + ["error_code"]=> + int(0) + ["error_msg"]=> + string(8) "No error" + ["error_position"]=> + int(0) + ["total_input_length"]=> + int(0) + ["at_content"]=> + string(0) "" +} \ No newline at end of file diff --git a/ext/json/tests/json_validate_002.phpt b/ext/json/tests/json_validate_002.phpt index be0a9dbded2c2..53f4e4f2c2ea1 100644 --- a/ext/json/tests/json_validate_002.phpt +++ b/ext/json/tests/json_validate_002.phpt @@ -23,7 +23,7 @@ int(4) string(12) "Syntax error" bool(false) int(4) -string(66) "Syntax error - error: syntax error, at character 0 near content: -" +string(12) "Syntax error" bool(false) int(4) string(12) "Syntax error" @@ -44,7 +44,7 @@ int(0) string(8) "No error" bool(false) int(4) -string(66) "Syntax error - error: syntax error, at character 0 near content: -" +string(12) "Syntax error" bool(true) int(0) string(8) "No error" diff --git a/ext/json/tests/json_validate_004.phpt b/ext/json/tests/json_validate_004.phpt index 61d5441baf8fb..6b9b13db48365 100644 --- a/ext/json/tests/json_validate_004.phpt +++ b/ext/json/tests/json_validate_004.phpt @@ -23,16 +23,16 @@ json_validate_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_INVALID_UTF8_IGNORE Testing Invalid UTF-8 bool(false) int(5) -string(114) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 0 near content: %s" +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" bool(false) int(5) -string(115) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 0 near content: %s" +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" bool(false) int(5) -string(116) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 0 near content: %s" +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" bool(false) int(5) -string(118) "Malformed UTF-8 characters, possibly incorrectly encoded - error: syntax error, at character 1 near content: %s" +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" bool(true) int(0) string(8) "No error" From 14b18f695d228eb8745c15843b02699622d16775 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Sun, 7 Jul 2024 18:41:37 -0300 Subject: [PATCH 10/16] - --- ext/json/json.c | 96 +++++++++++++++++++-------- ext/json/php_json_parser.h | 8 +++ ext/json/tests/json_validate_001.phpt | 4 ++ 3 files changed, 81 insertions(+), 27 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 79f54b9adfa4b..599d634b60723 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -36,26 +36,23 @@ PHP_JSON_API zend_class_entry *php_json_exception_ce; PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json) -php_json_scanner parser_scanner_temporal; +json_error_info_type json_error_info_data = { + NULL, + 0, + 0, + 0 +}; -void reset_global_parser_scanner_fields(void) +void reset_json_error_info(json_error_info_type* data) { - parser_scanner_temporal.cursor = NULL; - parser_scanner_temporal.token = NULL; - parser_scanner_temporal.limit = NULL; - parser_scanner_temporal.marker = NULL; - parser_scanner_temporal.ctxmarker = NULL; - parser_scanner_temporal.str_start = NULL; - parser_scanner_temporal.pstr = NULL; - //ZVAL_NULL(scanner->value) - parser_scanner_temporal.str_esc = 0; - parser_scanner_temporal.state = 0; - parser_scanner_temporal.options = 0; - parser_scanner_temporal.errcode = 0; - parser_scanner_temporal.utf8_invalid = 0; - parser_scanner_temporal.utf8_invalid_count = 0; - parser_scanner_temporal.character_count = 0; - parser_scanner_temporal.character_max_count = 0; + if (data->token) { + efree(data->token); + } + + data->token = NULL; + data->errcode = 0; + data->character_count = 0; + data->character_max_count = 0; } static int php_json_implement_json_serializable(zend_class_entry *interface, zend_class_entry *class_type) @@ -96,6 +93,14 @@ static PHP_RINIT_FUNCTION(json) return SUCCESS; } +static PHP_RSHUTDOWN_FUNCTION(json) +{ + if (json_error_info_data.token) { + efree(json_error_info_data.token); + } + return SUCCESS; +} + /* {{{ json_module_entry */ zend_module_entry json_module_entry = { STANDARD_MODULE_HEADER, @@ -104,7 +109,7 @@ zend_module_entry json_module_entry = { PHP_MINIT(json), NULL, PHP_RINIT(json), - NULL, + PHP_RSHUTDOWN(json), PHP_MINFO(json), PHP_JSON_VERSION, PHP_MODULE_GLOBALS(json), @@ -235,7 +240,28 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); JSON_G(error_code) = error_code; - parser_scanner_temporal = parser.scanner; + json_error_info_data.errcode = parser.scanner.errcode; + json_error_info_data.character_count = parser.scanner.character_count; + json_error_info_data.character_max_count = parser.scanner.character_max_count; + + if (json_error_info_data.token) { + efree(json_error_info_data.token); + } + + char token[32]; + snprintf( + token, + sizeof(token), + "%s", + parser.scanner.token + ); + + if (json_error_info_data.token) { + efree(json_error_info_data.token); + } + + json_error_info_data.token = (php_json_ctype*) emalloc(strlen(token) + 1); + memcpy(json_error_info_data.token, token, strlen(token) + 1); return false; } @@ -355,7 +381,7 @@ PHP_FUNCTION(json_validate) RETURN_THROWS(); } - reset_global_parser_scanner_fields(); + reset_json_error_info(&json_error_info_data); if (!str_len) { JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; @@ -392,7 +418,23 @@ PHP_FUNCTION(json_last_error_msg) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_STRING(php_json_get_error_msg(JSON_G(error_code))); + const char* msg = php_json_get_error_msg(JSON_G(error_code)); + + if (JSON_G(error_code) == PHP_JSON_ERROR_NONE || !json_error_info_data.token || strlen((const char*)json_error_info_data.token) == 0 || json_error_info_data.character_count < 0) { + RETURN_STRING(msg); + } + + char msg2[128]; + snprintf( + msg2, + sizeof(msg2), + "%s, at character %zu near content: %s", + msg, + json_error_info_data.character_count, + json_error_info_data.token + ); + + RETURN_STRING(msg2); } /* }}} */ @@ -405,13 +447,13 @@ PHP_FUNCTION(json_last_error_info) array_init(return_value); - add_assoc_long(return_value, "error_code", parser_scanner_temporal.errcode); + add_assoc_long(return_value, "error_code", json_error_info_data.errcode); add_assoc_string(return_value, "error_msg", msg); - add_assoc_long(return_value, "error_position", parser_scanner_temporal.character_count); - add_assoc_long(return_value, "total_input_length", parser_scanner_temporal.character_max_count); + add_assoc_long(return_value, "error_position", json_error_info_data.character_count); + add_assoc_long(return_value, "total_input_length", json_error_info_data.character_max_count); - if (parser_scanner_temporal.token) { - add_assoc_string(return_value, "at_content", (char *) parser_scanner_temporal.token); + if (json_error_info_data.token) { + add_assoc_string(return_value, "at_content", (char *) json_error_info_data.token); } else { add_assoc_string(return_value, "at_content", ""); } diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 8aedce9ac55d6..b92885a4b03d3 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -21,6 +21,7 @@ #include "php_json_scanner.h" typedef struct _php_json_parser php_json_parser; +typedef struct _json_error_info_type json_error_info_type; typedef int (*php_json_parser_func_array_create_t)( php_json_parser *parser, zval *array); @@ -58,6 +59,13 @@ struct _php_json_parser { php_json_parser_methods methods; }; +struct _json_error_info_type { + php_json_ctype* token; + php_json_error_code errcode; + size_t character_count; + size_t character_max_count; +}; + PHP_JSON_API void php_json_parser_init_ex( php_json_parser *parser, zval *return_value, diff --git a/ext/json/tests/json_validate_001.phpt b/ext/json/tests/json_validate_001.phpt index 3d96b25af6681..49bfb43e3aff9 100644 --- a/ext/json/tests/json_validate_001.phpt +++ b/ext/json/tests/json_validate_001.phpt @@ -4,6 +4,10 @@ json_validate() - General usage Date: Sun, 7 Jul 2024 20:18:55 -0300 Subject: [PATCH 11/16] - --- ext/json/json.c | 53 +++++++++++++++------------ ext/json/tests/007.phpt | 8 ++-- ext/json/tests/bug62010.phpt | 2 +- ext/json/tests/bug68546.phpt | 2 +- ext/json/tests/json_validate_001.phpt | 31 +++++++++++----- ext/json/tests/json_validate_002.phpt | 8 ++-- ext/json/tests/json_validate_004.phpt | 10 ++--- 7 files changed, 66 insertions(+), 48 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 599d634b60723..5580b312eb728 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -43,6 +43,27 @@ json_error_info_type json_error_info_data = { 0 }; +void update_json_error_info_data(php_json_parser *parser) { + json_error_info_data.errcode = parser->scanner.errcode; + json_error_info_data.character_count = parser->scanner.character_count; + json_error_info_data.character_max_count = parser->scanner.character_max_count; + + if (json_error_info_data.token) { + efree(json_error_info_data.token); + } + + char token[32]; + snprintf( + token, + sizeof(token), + "%s", + parser->scanner.token + ); + + json_error_info_data.token = (php_json_ctype*) emalloc(strlen(token) + 1); + memcpy(json_error_info_data.token, token, strlen(token) + 1); +} + void reset_json_error_info(json_error_info_type* data) { if (data->token) { @@ -213,7 +234,8 @@ PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); - + update_json_error_info_data(&parser); + if (!(options & PHP_JSON_THROW_ON_ERROR)) { JSON_G(error_code) = error_code; } else { @@ -240,28 +262,7 @@ PHP_JSON_API bool php_json_validate_ex(const char *str, size_t str_len, zend_lon if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); JSON_G(error_code) = error_code; - json_error_info_data.errcode = parser.scanner.errcode; - json_error_info_data.character_count = parser.scanner.character_count; - json_error_info_data.character_max_count = parser.scanner.character_max_count; - - if (json_error_info_data.token) { - efree(json_error_info_data.token); - } - - char token[32]; - snprintf( - token, - sizeof(token), - "%s", - parser.scanner.token - ); - - if (json_error_info_data.token) { - efree(json_error_info_data.token); - } - - json_error_info_data.token = (php_json_ctype*) emalloc(strlen(token) + 1); - memcpy(json_error_info_data.token, token, strlen(token) + 1); + update_json_error_info_data(&parser); return false; } @@ -285,6 +286,8 @@ PHP_FUNCTION(json_encode) Z_PARAM_LONG(depth) ZEND_PARSE_PARAMETERS_END(); + reset_json_error_info(&json_error_info_data); + php_json_encode_init(&encoder); encoder.max_depth = (int)depth; php_json_encode_zval(&buf, parameter, (int)options, &encoder); @@ -325,6 +328,8 @@ PHP_FUNCTION(json_decode) Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); + reset_json_error_info(&json_error_info_data); + if (!(options & PHP_JSON_THROW_ON_ERROR)) { JSON_G(error_code) = PHP_JSON_ERROR_NONE; } @@ -420,7 +425,7 @@ PHP_FUNCTION(json_last_error_msg) const char* msg = php_json_get_error_msg(JSON_G(error_code)); - if (JSON_G(error_code) == PHP_JSON_ERROR_NONE || !json_error_info_data.token || strlen((const char*)json_error_info_data.token) == 0 || json_error_info_data.character_count < 0) { + if (JSON_G(error_code) == PHP_JSON_ERROR_NONE || !json_error_info_data.token || strlen((const char*)json_error_info_data.token) == 0) { RETURN_STRING(msg); } diff --git a/ext/json/tests/007.phpt b/ext/json/tests/007.phpt index dea641317e97f..f72d373686ab5 100644 --- a/ext/json/tests/007.phpt +++ b/ext/json/tests/007.phpt @@ -24,14 +24,14 @@ int(0) string(8) "No error" NULL int(1) -string(28) "Maximum stack depth exceeded" +string(63) "Maximum stack depth exceeded, at character 1 near content: [1]]" NULL int(2) -string(42) "State mismatch (invalid or malformed JSON)" +string(74) "State mismatch (invalid or malformed JSON), at character 2 near content: }" NULL int(3) -string(53) "Control character error, possibly incorrectly encoded" +string(85) "Control character error, possibly incorrectly encoded, at character 1 near content: "" NULL int(4) string(12) "Syntax error" -Done +Done \ No newline at end of file diff --git a/ext/json/tests/bug62010.phpt b/ext/json/tests/bug62010.phpt index 2591231dcdda1..1e2325ceb536f 100644 --- a/ext/json/tests/bug62010.phpt +++ b/ext/json/tests/bug62010.phpt @@ -10,4 +10,4 @@ var_dump(json_last_error_msg()); --EXPECT-- NULL bool(true) -string(50) "Single unpaired UTF-16 surrogate in unicode escape" +string(89) "Single unpaired UTF-16 surrogate in unicode escape, at character 0 near content: "\ud834"" diff --git a/ext/json/tests/bug68546.phpt b/ext/json/tests/bug68546.phpt index 8835a72c5eac7..6d9bf6d36e2d3 100644 --- a/ext/json/tests/bug68546.phpt +++ b/ext/json/tests/bug68546.phpt @@ -16,5 +16,5 @@ NULL bool(true) NULL bool(true) -string(36) "The decoded property name is invalid" +string(71) "The decoded property name is invalid, at character 23 near content: 1}]" Done diff --git a/ext/json/tests/json_validate_001.phpt b/ext/json/tests/json_validate_001.phpt index 49bfb43e3aff9..a61b8fc294feb 100644 --- a/ext/json/tests/json_validate_001.phpt +++ b/ext/json/tests/json_validate_001.phpt @@ -7,7 +7,6 @@ var_dump( json_validate('{"key":"'.str_repeat('x', 1000).'"foobar}'), json_last_error_msg(), json_last_error_info(), - json_validate(""), json_last_error_msg(), json_last_error_info(), @@ -59,6 +58,20 @@ var_dump( ?> --EXPECT-- bool(false) +string(53) "Syntax error, at character 1009 near content: foobar}" +array(5) { + ["error_code"]=> + int(4) + ["error_msg"]=> + string(12) "Syntax error" + ["error_position"]=> + int(1009) + ["total_input_length"]=> + int(1016) + ["at_content"]=> + string(7) "foobar}" +} +bool(false) string(12) "Syntax error" array(5) { ["error_code"]=> @@ -73,7 +86,7 @@ array(5) { string(0) "" } bool(false) -string(12) "Syntax error" +string(44) "Syntax error, at character 0 near content: ." array(5) { ["error_code"]=> int(4) @@ -87,7 +100,7 @@ array(5) { string(1) "." } bool(false) -string(12) "Syntax error" +string(46) "Syntax error, at character 0 near content: " array(5) { ["error_code"]=> int(4) @@ -101,7 +114,7 @@ array(5) { string(3) "" } bool(false) -string(12) "Syntax error" +string(44) "Syntax error, at character 0 near content: ;" array(5) { ["error_code"]=> int(4) @@ -115,7 +128,7 @@ array(5) { string(1) ";" } bool(false) -string(12) "Syntax error" +string(55) "Syntax error, at character 0 near content: руссиш" array(5) { ["error_code"]=> int(4) @@ -129,7 +142,7 @@ array(5) { string(12) "руссиш" } bool(false) -string(12) "Syntax error" +string(47) "Syntax error, at character 0 near content: blah" array(5) { ["error_code"]=> int(4) @@ -143,7 +156,7 @@ array(5) { string(4) "blah" } bool(false) -string(12) "Syntax error" +string(51) "Syntax error, at character 8 near content: : "" } }" array(5) { ["error_code"]=> int(4) @@ -171,7 +184,7 @@ array(5) { string(0) "" } bool(false) -string(12) "Syntax error" +string(75) "Syntax error, at character 13 near content: "foo": "bar" }, "test2": {"foo"" array(5) { ["error_code"]=> int(4) @@ -182,7 +195,7 @@ array(5) { ["total_input_length"]=> int(83) ["at_content"]=> - string(70) ""foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }" + string(31) ""foo": "bar" }, "test2": {"foo"" } bool(true) string(8) "No error" diff --git a/ext/json/tests/json_validate_002.phpt b/ext/json/tests/json_validate_002.phpt index 53f4e4f2c2ea1..b65a148fb1a4f 100644 --- a/ext/json/tests/json_validate_002.phpt +++ b/ext/json/tests/json_validate_002.phpt @@ -23,13 +23,13 @@ int(4) string(12) "Syntax error" bool(false) int(4) -string(12) "Syntax error" +string(44) "Syntax error, at character 0 near content: -" bool(false) int(4) string(12) "Syntax error" bool(false) int(1) -string(28) "Maximum stack depth exceeded" +string(90) "Maximum stack depth exceeded, at character 0 near content: {"key1":"value1", "key2":"value" bool(true) int(0) string(8) "No error" @@ -44,7 +44,7 @@ int(0) string(8) "No error" bool(false) int(4) -string(12) "Syntax error" +string(44) "Syntax error, at character 0 near content: -" bool(true) int(0) -string(8) "No error" +string(8) "No error" \ No newline at end of file diff --git a/ext/json/tests/json_validate_004.phpt b/ext/json/tests/json_validate_004.phpt index 6b9b13db48365..b2da373a6f614 100644 --- a/ext/json/tests/json_validate_004.phpt +++ b/ext/json/tests/json_validate_004.phpt @@ -23,16 +23,16 @@ json_validate_trycatchdump("[\"\xc1\xc1\",\"a\"]", 512, JSON_INVALID_UTF8_IGNORE Testing Invalid UTF-8 bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(92) "Malformed UTF-8 characters, possibly incorrectly encoded, at character 0 near content: %s" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(93) "Malformed UTF-8 characters, possibly incorrectly encoded, at character 0 near content: %s" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(94) "Malformed UTF-8 characters, possibly incorrectly encoded, at character 0 near content: %s" bool(false) int(5) -string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" +string(96) "Malformed UTF-8 characters, possibly incorrectly encoded, at character 1 near content: %s" bool(true) int(0) string(8) "No error" @@ -44,4 +44,4 @@ int(0) string(8) "No error" bool(true) int(0) -string(8) "No error" +string(8) "No error" \ No newline at end of file From a79a7f328c71e0c3836340f8fc8a02642204e8e7 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Sat, 13 Jul 2024 11:10:17 -0300 Subject: [PATCH 12/16] Remove new function json_last_error_info(), comments on new data type, and test fixes --- ext/json/json.c | 30 +--- ext/json/json.stub.php | 2 - ext/json/json_arginfo.h | 5 - ext/json/php_json_parser.h | 8 +- ext/json/tests/007.phpt | 2 +- ext/json/tests/json_validate_001.phpt | 209 -------------------------- ext/json/tests/json_validate_002.phpt | 2 +- ext/json/tests/json_validate_004.phpt | 2 +- 8 files changed, 11 insertions(+), 249 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index 5580b312eb728..d962096840e15 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -37,10 +37,10 @@ PHP_JSON_API zend_class_entry *php_json_exception_ce; PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json) json_error_info_type json_error_info_data = { - NULL, - 0, - 0, - 0 + NULL, // Parse token + 0, // Error ode + 0, // Character count + 0 // Total number of characters to parse }; void update_json_error_info_data(php_json_parser *parser) { @@ -442,25 +442,3 @@ PHP_FUNCTION(json_last_error_msg) RETURN_STRING(msg2); } /* }}} */ - -/* {{{ Returns an array with parser-scanner information of the last error of the last json_validate(), json_encode() or json_decode() call. */ -PHP_FUNCTION(json_last_error_info) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - const char* msg = php_json_get_error_msg(JSON_G(error_code)); - - array_init(return_value); - - add_assoc_long(return_value, "error_code", json_error_info_data.errcode); - add_assoc_string(return_value, "error_msg", msg); - add_assoc_long(return_value, "error_position", json_error_info_data.character_count); - add_assoc_long(return_value, "total_input_length", json_error_info_data.character_max_count); - - if (json_error_info_data.token) { - add_assoc_string(return_value, "at_content", (char *) json_error_info_data.token); - } else { - add_assoc_string(return_value, "at_content", ""); - } -} -/* }}} */ diff --git a/ext/json/json.stub.php b/ext/json/json.stub.php index ae14271851651..a805c3893dd10 100644 --- a/ext/json/json.stub.php +++ b/ext/json/json.stub.php @@ -163,8 +163,6 @@ function json_last_error(): int {} /** @refcount 1 */ function json_last_error_msg(): string {} -function json_last_error_info(): array {} - interface JsonSerializable { /** @tentative-return-type */ diff --git a/ext/json/json_arginfo.h b/ext/json/json_arginfo.h index 2afa36654dc8e..1feebf5d4cb98 100644 --- a/ext/json/json_arginfo.h +++ b/ext/json/json_arginfo.h @@ -26,9 +26,6 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_msg, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_info, 0, 0, IS_ARRAY, 0) -ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_JsonSerializable_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() @@ -37,7 +34,6 @@ ZEND_FUNCTION(json_decode); ZEND_FUNCTION(json_validate); ZEND_FUNCTION(json_last_error); ZEND_FUNCTION(json_last_error_msg); -ZEND_FUNCTION(json_last_error_info); static const zend_function_entry ext_functions[] = { ZEND_FE(json_encode, arginfo_json_encode) @@ -45,7 +41,6 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(json_validate, arginfo_json_validate) ZEND_FE(json_last_error, arginfo_json_last_error) ZEND_FE(json_last_error_msg, arginfo_json_last_error_msg) - ZEND_FE(json_last_error_info, arginfo_json_last_error_info) ZEND_FE_END }; diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index b92885a4b03d3..cf68e83bf4a68 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -60,10 +60,10 @@ struct _php_json_parser { }; struct _json_error_info_type { - php_json_ctype* token; - php_json_error_code errcode; - size_t character_count; - size_t character_max_count; + php_json_ctype* token; // Parse token + php_json_error_code errcode; // Error ode + size_t character_count; // Character count + size_t character_max_count; // Total number of characters to parse }; PHP_JSON_API void php_json_parser_init_ex( diff --git a/ext/json/tests/007.phpt b/ext/json/tests/007.phpt index f72d373686ab5..d83adf5dd9c9f 100644 --- a/ext/json/tests/007.phpt +++ b/ext/json/tests/007.phpt @@ -34,4 +34,4 @@ string(85) "Control character error, possibly incorrectly encoded, at character NULL int(4) string(12) "Syntax error" -Done \ No newline at end of file +Done diff --git a/ext/json/tests/json_validate_001.phpt b/ext/json/tests/json_validate_001.phpt index a61b8fc294feb..662e276b8be48 100644 --- a/ext/json/tests/json_validate_001.phpt +++ b/ext/json/tests/json_validate_001.phpt @@ -6,278 +6,69 @@ json_validate() - General usage var_dump( json_validate('{"key":"'.str_repeat('x', 1000).'"foobar}'), json_last_error_msg(), - json_last_error_info(), json_validate(""), json_last_error_msg(), - json_last_error_info(), json_validate("."), json_last_error_msg(), - json_last_error_info(), json_validate(""), json_last_error_msg(), - json_last_error_info(), json_validate(";"), json_last_error_msg(), - json_last_error_info(), json_validate("руссиш"), json_last_error_msg(), - json_last_error_info(), json_validate("blah"), json_last_error_msg(), - json_last_error_info(), json_validate('{ "": "": "" } }'), json_last_error_msg(), - json_last_error_info(), json_validate('{ "": { "": "" }'), json_last_error_msg(), - json_last_error_info(), json_validate('{ "test": {} "foo": "bar" }, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), json_last_error_msg(), - json_last_error_info(), - json_validate('{ "test": { "foo": "bar" } }'), json_last_error_msg(), - json_last_error_info(), json_validate('{ "test": { "foo": "" } }'), json_last_error_msg(), - json_last_error_info(), json_validate('{ "": { "foo": "" } }'), json_last_error_msg(), - json_last_error_info(), json_validate('{ "": { "": "" } }'), json_last_error_msg(), - json_last_error_info(), json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test2": {"foo" : "bar" } }'), json_last_error_msg(), - json_last_error_info(), json_validate('{ "test": {"foo": "bar"}, "test2": {"foo" : "bar" }, "test3": {"foo" : "bar" } }'), json_last_error_msg(), - json_last_error_info(), ); ?> --EXPECT-- bool(false) string(53) "Syntax error, at character 1009 near content: foobar}" -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(1009) - ["total_input_length"]=> - int(1016) - ["at_content"]=> - string(7) "foobar}" -} bool(false) string(12) "Syntax error" -array(5) { - ["error_code"]=> - int(0) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(0) - ["at_content"]=> - string(0) "" -} bool(false) string(44) "Syntax error, at character 0 near content: ." -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(1) - ["at_content"]=> - string(1) "." -} bool(false) string(46) "Syntax error, at character 0 near content: " -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(3) - ["at_content"]=> - string(3) "" -} bool(false) string(44) "Syntax error, at character 0 near content: ;" -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(1) - ["at_content"]=> - string(1) ";" -} bool(false) string(55) "Syntax error, at character 0 near content: руссиш" -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(12) - ["at_content"]=> - string(12) "руссиш" -} bool(false) string(47) "Syntax error, at character 0 near content: blah" -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(4) - ["at_content"]=> - string(4) "blah" -} bool(false) string(51) "Syntax error, at character 8 near content: : "" } }" -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(8) - ["total_input_length"]=> - int(16) - ["at_content"]=> - string(8) ": "" } }" -} bool(false) string(12) "Syntax error" -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(16) - ["total_input_length"]=> - int(16) - ["at_content"]=> - string(0) "" -} bool(false) string(75) "Syntax error, at character 13 near content: "foo": "bar" }, "test2": {"foo"" -array(5) { - ["error_code"]=> - int(4) - ["error_msg"]=> - string(12) "Syntax error" - ["error_position"]=> - int(13) - ["total_input_length"]=> - int(83) - ["at_content"]=> - string(31) ""foo": "bar" }, "test2": {"foo"" -} bool(true) string(8) "No error" -array(5) { - ["error_code"]=> - int(0) - ["error_msg"]=> - string(8) "No error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(0) - ["at_content"]=> - string(0) "" -} bool(true) string(8) "No error" -array(5) { - ["error_code"]=> - int(0) - ["error_msg"]=> - string(8) "No error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(0) - ["at_content"]=> - string(0) "" -} bool(true) string(8) "No error" -array(5) { - ["error_code"]=> - int(0) - ["error_msg"]=> - string(8) "No error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(0) - ["at_content"]=> - string(0) "" -} bool(true) string(8) "No error" -array(5) { - ["error_code"]=> - int(0) - ["error_msg"]=> - string(8) "No error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(0) - ["at_content"]=> - string(0) "" -} bool(true) string(8) "No error" -array(5) { - ["error_code"]=> - int(0) - ["error_msg"]=> - string(8) "No error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(0) - ["at_content"]=> - string(0) "" -} bool(true) string(8) "No error" -array(5) { - ["error_code"]=> - int(0) - ["error_msg"]=> - string(8) "No error" - ["error_position"]=> - int(0) - ["total_input_length"]=> - int(0) - ["at_content"]=> - string(0) "" -} \ No newline at end of file diff --git a/ext/json/tests/json_validate_002.phpt b/ext/json/tests/json_validate_002.phpt index b65a148fb1a4f..6fd213ab54bad 100644 --- a/ext/json/tests/json_validate_002.phpt +++ b/ext/json/tests/json_validate_002.phpt @@ -47,4 +47,4 @@ int(4) string(44) "Syntax error, at character 0 near content: -" bool(true) int(0) -string(8) "No error" \ No newline at end of file +string(8) "No error" diff --git a/ext/json/tests/json_validate_004.phpt b/ext/json/tests/json_validate_004.phpt index b2da373a6f614..631487b4337be 100644 --- a/ext/json/tests/json_validate_004.phpt +++ b/ext/json/tests/json_validate_004.phpt @@ -44,4 +44,4 @@ int(0) string(8) "No error" bool(true) int(0) -string(8) "No error" \ No newline at end of file +string(8) "No error" From 66423ec1eb8fd67bbdecaec03970fcefcda9d2ff Mon Sep 17 00:00:00 2001 From: juan-morales Date: Sat, 13 Jul 2024 11:39:33 -0300 Subject: [PATCH 13/16] json_arginfo.h out --- ext/json/json_arginfo.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ext/json/json_arginfo.h b/ext/json/json_arginfo.h index 1feebf5d4cb98..2afa36654dc8e 100644 --- a/ext/json/json_arginfo.h +++ b/ext/json/json_arginfo.h @@ -26,6 +26,9 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_msg, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_info, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_JsonSerializable_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() @@ -34,6 +37,7 @@ ZEND_FUNCTION(json_decode); ZEND_FUNCTION(json_validate); ZEND_FUNCTION(json_last_error); ZEND_FUNCTION(json_last_error_msg); +ZEND_FUNCTION(json_last_error_info); static const zend_function_entry ext_functions[] = { ZEND_FE(json_encode, arginfo_json_encode) @@ -41,6 +45,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(json_validate, arginfo_json_validate) ZEND_FE(json_last_error, arginfo_json_last_error) ZEND_FE(json_last_error_msg, arginfo_json_last_error_msg) + ZEND_FE(json_last_error_info, arginfo_json_last_error_info) ZEND_FE_END }; From 02378dc7f27bf6e4db888e6a7a132f707d52d5c9 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Sat, 13 Jul 2024 11:41:26 -0300 Subject: [PATCH 14/16] json_arginfo.h out --- ext/json/tests/json_validate_005.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/json/tests/json_validate_005.phpt b/ext/json/tests/json_validate_005.phpt index f5cb9d6f732b5..a1cc80271f3f4 100644 --- a/ext/json/tests/json_validate_005.phpt +++ b/ext/json/tests/json_validate_005.phpt @@ -1,5 +1,5 @@ --TEST-- -json_validate() - compare against json_decode() for different types of inputs +json_validate() - compare against json_decode() for different types of inputs --FILE-- Date: Sat, 13 Jul 2024 11:45:05 -0300 Subject: [PATCH 15/16] - --- ext/json/json_arginfo.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ext/json/json_arginfo.h b/ext/json/json_arginfo.h index 2afa36654dc8e..a02cfd4a78105 100644 --- a/ext/json/json_arginfo.h +++ b/ext/json/json_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: feb59cc47fa5b6fbca611a9d84f9b5ce9e6d4d0b */ + * Stub hash: 0ceb50047401c4b9e878c09cc518eacc274f7fff */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_json_encode, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) @@ -26,9 +26,6 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_msg, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_json_last_error_info, 0, 0, IS_ARRAY, 0) -ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_JsonSerializable_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() @@ -37,7 +34,6 @@ ZEND_FUNCTION(json_decode); ZEND_FUNCTION(json_validate); ZEND_FUNCTION(json_last_error); ZEND_FUNCTION(json_last_error_msg); -ZEND_FUNCTION(json_last_error_info); static const zend_function_entry ext_functions[] = { ZEND_FE(json_encode, arginfo_json_encode) @@ -45,7 +41,6 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(json_validate, arginfo_json_validate) ZEND_FE(json_last_error, arginfo_json_last_error) ZEND_FE(json_last_error_msg, arginfo_json_last_error_msg) - ZEND_FE(json_last_error_info, arginfo_json_last_error_info) ZEND_FE_END }; From e198cea619746eedf8db6011ed6a682bedf78a76 Mon Sep 17 00:00:00 2001 From: juan-morales Date: Wed, 17 Jul 2024 09:22:32 -0300 Subject: [PATCH 16/16] fix comment typeO --- ext/json/json.c | 8 ++++---- ext/json/php_json_parser.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/json/json.c b/ext/json/json.c index d962096840e15..3cdcf2e46dabc 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -37,10 +37,10 @@ PHP_JSON_API zend_class_entry *php_json_exception_ce; PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json) json_error_info_type json_error_info_data = { - NULL, // Parse token - 0, // Error ode - 0, // Character count - 0 // Total number of characters to parse + NULL, // Parsed token + 0, // Error code + 0, // Character count + 0 // Total number of characters to parse }; void update_json_error_info_data(php_json_parser *parser) { diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index cf68e83bf4a68..504e11ada3614 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -60,8 +60,8 @@ struct _php_json_parser { }; struct _json_error_info_type { - php_json_ctype* token; // Parse token - php_json_error_code errcode; // Error ode + php_json_ctype* token; // Parsed token + php_json_error_code errcode; // Error code size_t character_count; // Character count size_t character_max_count; // Total number of characters to parse };