-
Notifications
You must be signed in to change notification settings - Fork 8k
Json last error msg/error message with location error #20629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
680cdbf
be47a53
448f085
d55103e
b5e5a01
6578f09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -63,13 +63,17 @@ static PHP_GINIT_FUNCTION(json) | |||||||
| #endif | ||||||||
| json_globals->encoder_depth = 0; | ||||||||
| json_globals->error_code = 0; | ||||||||
| json_globals->error_line = 0; | ||||||||
| json_globals->error_column = 0; | ||||||||
| json_globals->encode_max_depth = PHP_JSON_PARSER_DEFAULT_DEPTH; | ||||||||
| } | ||||||||
| /* }}} */ | ||||||||
|
|
||||||||
| static PHP_RINIT_FUNCTION(json) | ||||||||
| { | ||||||||
| JSON_G(error_code) = 0; | ||||||||
| JSON_G(error_line) = 0; | ||||||||
| JSON_G(error_column) = 0; | ||||||||
| return SUCCESS; | ||||||||
| } | ||||||||
|
|
||||||||
|
|
@@ -177,6 +181,18 @@ static const char *php_json_get_error_msg(php_json_error_code error_code) /* {{{ | |||||||
| } | ||||||||
| /* }}} */ | ||||||||
|
|
||||||||
| static zend_string *php_json_get_error_msg_with_location(php_json_error_code error_code, size_t line, size_t column) /* {{{ */ | ||||||||
| { | ||||||||
| const char *base_msg = php_json_get_error_msg(error_code); | ||||||||
|
|
||||||||
| if (line > 0 && column > 0) { | ||||||||
| return zend_strpprintf(0, "%s near location %zu,%zu", base_msg, line, column); | ||||||||
| } | ||||||||
|
|
||||||||
| return zend_string_init(base_msg, strlen(base_msg), 0); | ||||||||
| } | ||||||||
| /* }}} */ | ||||||||
|
|
||||||||
| PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */ | ||||||||
| { | ||||||||
| php_json_parser parser; | ||||||||
|
|
@@ -185,10 +201,17 @@ 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); | ||||||||
| size_t error_line = php_json_parser_error_line(&parser); | ||||||||
| size_t error_column = php_json_parser_error_column(&parser); | ||||||||
|
|
||||||||
| if (!(options & PHP_JSON_THROW_ON_ERROR)) { | ||||||||
| JSON_G(error_code) = error_code; | ||||||||
| JSON_G(error_line) = error_line; | ||||||||
| JSON_G(error_column) = error_column; | ||||||||
| } else { | ||||||||
| zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code); | ||||||||
| zend_string *error_msg = php_json_get_error_msg_with_location(error_code, error_line, error_column); | ||||||||
| zend_throw_exception(php_json_exception_ce, ZSTR_VAL(error_msg), error_code); | ||||||||
| zend_string_release(error_msg); | ||||||||
|
Comment on lines
+213
to
+214
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This not a public API (yet), see #20547
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah good catch (I was just searching for something like that but didn't realise it's not in the header...). Let's wait for that first commit in the PR then... |
||||||||
| } | ||||||||
| RETVAL_NULL(); | ||||||||
| return FAILURE; | ||||||||
|
|
@@ -208,7 +231,12 @@ 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); | ||||||||
| size_t error_line = php_json_parser_error_line(&parser); | ||||||||
| size_t error_column = php_json_parser_error_column(&parser); | ||||||||
|
|
||||||||
| JSON_G(error_code) = error_code; | ||||||||
| JSON_G(error_line) = error_line; | ||||||||
| JSON_G(error_column) = error_column; | ||||||||
| return false; | ||||||||
| } | ||||||||
|
|
||||||||
|
|
@@ -274,11 +302,15 @@ PHP_FUNCTION(json_decode) | |||||||
|
|
||||||||
| if (!(options & PHP_JSON_THROW_ON_ERROR)) { | ||||||||
| JSON_G(error_code) = PHP_JSON_ERROR_NONE; | ||||||||
| JSON_G(error_line) = 0; | ||||||||
| JSON_G(error_column) = 0; | ||||||||
| } | ||||||||
|
|
||||||||
| if (!str_len) { | ||||||||
| if (!(options & PHP_JSON_THROW_ON_ERROR)) { | ||||||||
| JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; | ||||||||
| JSON_G(error_line) = 0; | ||||||||
| JSON_G(error_column) = 0; | ||||||||
| } else { | ||||||||
| zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX); | ||||||||
| } | ||||||||
|
|
@@ -331,10 +363,14 @@ PHP_FUNCTION(json_validate) | |||||||
|
|
||||||||
| if (!str_len) { | ||||||||
| JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; | ||||||||
| JSON_G(error_line) = 0; | ||||||||
| JSON_G(error_column) = 0; | ||||||||
| RETURN_FALSE; | ||||||||
| } | ||||||||
|
|
||||||||
| JSON_G(error_code) = PHP_JSON_ERROR_NONE; | ||||||||
| JSON_G(error_line) = 0; | ||||||||
| JSON_G(error_column) = 0; | ||||||||
|
|
||||||||
| if (depth <= 0) { | ||||||||
| zend_argument_value_error(2, "must be greater than 0"); | ||||||||
|
|
@@ -364,6 +400,15 @@ PHP_FUNCTION(json_last_error_msg) | |||||||
| { | ||||||||
| ZEND_PARSE_PARAMETERS_NONE(); | ||||||||
|
|
||||||||
| RETURN_STRING(php_json_get_error_msg(JSON_G(error_code))); | ||||||||
| if (JSON_G(error_line) > 0 && JSON_G(error_column) > 0) { | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check is not necessary as it is checked in php_json_get_error_msg_with_location. If it was to save creation of zend_string, then it is not necessary because it is created in RETURN_STRING anyway. |
||||||||
| zend_string *error_msg = php_json_get_error_msg_with_location( | ||||||||
| JSON_G(error_code), | ||||||||
| JSON_G(error_line), | ||||||||
| JSON_G(error_column) | ||||||||
| ); | ||||||||
| RETVAL_STR(error_msg); | ||||||||
| } else { | ||||||||
| RETURN_STRING(php_json_get_error_msg(JSON_G(error_code))); | ||||||||
| } | ||||||||
| } | ||||||||
| /* }}} */ | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,7 @@ int json_yydebug = 1; | |
|
|
||
| } | ||
|
|
||
| %locations | ||
| %define api.prefix {php_json_yy} | ||
| %define api.pure full | ||
| %param { php_json_parser *parser } | ||
|
|
@@ -49,7 +50,6 @@ int json_yydebug = 1; | |
| zval value; | ||
| } | ||
|
|
||
|
|
||
| %token <value> PHP_JSON_T_NUL | ||
| %token <value> PHP_JSON_T_TRUE | ||
| %token <value> PHP_JSON_T_FALSE | ||
|
|
@@ -66,8 +66,8 @@ int json_yydebug = 1; | |
| %destructor { zval_ptr_dtor_nogc(&$$); } <value> | ||
|
|
||
| %code { | ||
| static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); | ||
| static void php_json_yyerror(php_json_parser *parser, char const *msg); | ||
| static int php_json_yylex(union YYSTYPE *value, YYLTYPE *location, php_json_parser *parser); | ||
| static void php_json_yyerror(YYLTYPE *location, php_json_parser *parser, char const *msg); | ||
| static int php_json_parser_array_create(php_json_parser *parser, zval *array); | ||
| static int php_json_parser_object_create(php_json_parser *parser, zval *array); | ||
|
|
||
|
|
@@ -277,7 +277,7 @@ static int php_json_parser_object_update_validate(php_json_parser *parser, zval | |
| return SUCCESS; | ||
| } | ||
|
|
||
| static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) | ||
| static int php_json_yylex(union YYSTYPE *value, YYLTYPE *location, php_json_parser *parser) | ||
| { | ||
| int token = php_json_scan(&parser->scanner); | ||
|
|
||
|
|
@@ -293,21 +293,41 @@ static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) | |
| value->value = parser->scanner.value; | ||
| } | ||
|
|
||
| location->first_column = PHP_JSON_SCANNER_LOCATION(parser->scanner, first_column); | ||
| location->first_line = PHP_JSON_SCANNER_LOCATION(parser->scanner, first_line); | ||
| location->last_column = PHP_JSON_SCANNER_LOCATION(parser->scanner, last_column); | ||
| location->last_line = PHP_JSON_SCANNER_LOCATION(parser->scanner, last_line); | ||
|
|
||
| return token; | ||
| } | ||
|
|
||
| static void php_json_yyerror(php_json_parser *parser, char const *msg) | ||
| static void php_json_yyerror(YYLTYPE *location, php_json_parser *parser, char const *msg) | ||
| { | ||
| if (!parser->scanner.errcode) { | ||
| parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; | ||
| } | ||
|
|
||
| parser->scanner.errloc.first_column = location->first_column; | ||
| parser->scanner.errloc.first_line = location->first_line; | ||
| parser->scanner.errloc.last_column = location->last_column; | ||
| parser->scanner.errloc.last_line = location->last_line; | ||
|
Comment on lines
+309
to
+313
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this necessary? Just checking because I don't have this in jso and it seems to still work so wondering why it's added here? |
||
| } | ||
|
|
||
| PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser) | ||
| { | ||
| return parser->scanner.errcode; | ||
| } | ||
|
|
||
| PHP_JSON_API size_t php_json_parser_error_line(const php_json_parser *parser) | ||
| { | ||
| return parser->scanner.errloc.first_line; | ||
| } | ||
|
|
||
| PHP_JSON_API size_t php_json_parser_error_column(const php_json_parser *parser) | ||
| { | ||
| return parser->scanner.errloc.first_column; | ||
| } | ||
|
|
||
| static const php_json_parser_methods default_parser_methods = | ||
| { | ||
| php_json_parser_array_create, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,6 +52,8 @@ | |
|
|
||
| #define PHP_JSON_INT_MAX_LENGTH (MAX_LENGTH_OF_LONG - 1) | ||
|
|
||
| #define PHP_JSON_TOKEN_LENGTH(s) ((size_t) ((s)->cursor - (s)->token)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess |
||
| #define PHP_JSON_TOKEN_LOCATION(location) (s)->errloc.location | ||
|
|
||
| static void php_json_scanner_copy_string(php_json_scanner *s, size_t esc_size) | ||
| { | ||
|
|
@@ -96,6 +98,10 @@ 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; | ||
| PHP_JSON_TOKEN_LOCATION(first_column) = 1; | ||
| PHP_JSON_TOKEN_LOCATION(first_line) = 1; | ||
| PHP_JSON_TOKEN_LOCATION(last_column) = 1; | ||
| PHP_JSON_TOKEN_LOCATION(last_line) = 1; | ||
| PHP_JSON_CONDITION_SET(JS); | ||
| } | ||
|
|
||
|
|
@@ -104,6 +110,8 @@ int php_json_scan(php_json_scanner *s) | |
| ZVAL_NULL(&s->value); | ||
|
|
||
| std: | ||
| PHP_JSON_TOKEN_LOCATION(first_column) = s->errloc.last_column; | ||
| PHP_JSON_TOKEN_LOCATION(first_line) = s->errloc.last_line; | ||
| s->token = s->cursor; | ||
|
|
||
| /*!re2c | ||
|
|
@@ -149,27 +157,50 @@ std: | |
| UTF16_3 = UTFPREF ( ( ( HEXC | [efEF] ) HEX ) | ( [dD] HEX7 ) ) HEX{2} ; | ||
| UTF16_4 = UTFPREF [dD] [89abAB] HEX{2} UTFPREF [dD] [c-fC-F] HEX{2} ; | ||
|
|
||
| <JS>"{" { return '{'; } | ||
| <JS>"}" { return '}'; } | ||
| <JS>"[" { return '['; } | ||
| <JS>"]" { return ']'; } | ||
| <JS>":" { return ':'; } | ||
| <JS>"," { return ','; } | ||
| <JS>"{" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| return '{'; | ||
| } | ||
| <JS>"}" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| return '}'; | ||
| } | ||
| <JS>"[" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| return '['; | ||
| } | ||
| <JS>"]" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| return ']'; | ||
| } | ||
| <JS>":" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| return ':'; | ||
| } | ||
| <JS>"," { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| return ','; | ||
| } | ||
| <JS>"null" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 4; | ||
| ZVAL_NULL(&s->value); | ||
| return PHP_JSON_T_NUL; | ||
| } | ||
| <JS>"true" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 4; | ||
| ZVAL_TRUE(&s->value); | ||
| return PHP_JSON_T_TRUE; | ||
| } | ||
| <JS>"false" { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 5; | ||
| ZVAL_FALSE(&s->value); | ||
| return PHP_JSON_T_FALSE; | ||
| } | ||
| <JS>INT { | ||
| bool bigint = 0, negative = s->token[0] == '-'; | ||
| size_t digits = (size_t) (s->cursor - s->token - negative); | ||
| size_t digits = PHP_JSON_TOKEN_LENGTH(s); | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += digits; | ||
| digits -= negative; | ||
| if (digits >= PHP_JSON_INT_MAX_LENGTH) { | ||
| if (digits == PHP_JSON_INT_MAX_LENGTH) { | ||
| int cmp = strncmp((char *) (s->token + negative), LONG_MIN_DIGITS, PHP_JSON_INT_MAX_LENGTH); | ||
|
|
@@ -192,10 +223,19 @@ std: | |
| } | ||
| } | ||
| <JS>FLOAT|EXP { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += PHP_JSON_TOKEN_LENGTH(s); | ||
| ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); | ||
| return PHP_JSON_T_DOUBLE; | ||
| } | ||
| <JS>NL|WS { goto std; } | ||
| <JS>NL { | ||
| PHP_JSON_TOKEN_LOCATION(last_line)++; | ||
| PHP_JSON_TOKEN_LOCATION(last_column) = 1; | ||
| goto std; | ||
| } | ||
| <JS>WS { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += PHP_JSON_TOKEN_LENGTH(s); | ||
| goto std; | ||
| } | ||
| <JS>EOI { | ||
| if (s->limit < s->cursor) { | ||
| return PHP_JSON_T_EOI; | ||
|
|
@@ -205,6 +245,7 @@ std: | |
| } | ||
| } | ||
| <JS>["] { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| s->str_start = s->cursor; | ||
| s->str_esc = 0; | ||
| s->utf8_invalid = 0; | ||
|
|
@@ -229,18 +270,22 @@ std: | |
| return PHP_JSON_T_ERROR; | ||
| } | ||
| <STR_P1>UTF16_1 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 1; | ||
| s->str_esc += 5; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
| <STR_P1>UTF16_2 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 1; | ||
| s->str_esc += 4; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
| <STR_P1>UTF16_3 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 1; | ||
| s->str_esc += 3; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
| <STR_P1>UTF16_4 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 1; | ||
| s->str_esc += 8; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
|
|
@@ -249,6 +294,7 @@ std: | |
| return PHP_JSON_T_ERROR; | ||
| } | ||
| <STR_P1>ESC { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 2; | ||
| s->str_esc++; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
|
|
@@ -257,6 +303,7 @@ std: | |
| return PHP_JSON_T_ERROR; | ||
| } | ||
| <STR_P1>["] { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| zend_string *str; | ||
| size_t len = (size_t)(s->cursor - s->str_start - s->str_esc - 1 + s->utf8_invalid_count); | ||
| if (len == 0) { | ||
|
|
@@ -277,7 +324,22 @@ std: | |
| return PHP_JSON_T_STRING; | ||
| } | ||
| } | ||
| <STR_P1>UTF8 { PHP_JSON_CONDITION_GOTO(STR_P1); } | ||
| <STR_P1>UTF8_1 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column)++; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
| <STR_P1>UTF8_2 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 1; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
| <STR_P1>UTF8_3 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 1; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
| <STR_P1>UTF8_4 { | ||
| PHP_JSON_TOKEN_LOCATION(last_column) += 1; | ||
| PHP_JSON_CONDITION_GOTO(STR_P1); | ||
| } | ||
| <STR_P1>ANY { | ||
| if (s->options & (PHP_JSON_INVALID_UTF8_IGNORE | PHP_JSON_INVALID_UTF8_SUBSTITUTE)) { | ||
| if (s->options & PHP_JSON_INVALID_UTF8_SUBSTITUTE) { | ||
|
|
@@ -295,7 +357,6 @@ std: | |
| s->errcode = PHP_JSON_ERROR_UTF8; | ||
| return PHP_JSON_T_ERROR; | ||
| } | ||
|
|
||
| <STR_P2_UTF,STR_P2_BIN>UTF16_1 { | ||
| int utf16 = php_json_ucs2_to_int(s, 2); | ||
| PHP_JSON_SCANNER_COPY_UTF(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.