-
Notifications
You must be signed in to change notification settings - Fork 7.9k
better json error message #14672
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?
better json error message #14672
Changes from 15 commits
be91021
c8590bf
60aa905
1967215
376c654
9125d92
5e7de7b
79aa999
e832ae1
14b18f6
929baa3
a79a7f3
66423ec
02378dc
5848b08
e198cea
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 |
---|---|---|
|
@@ -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 <zend_exceptions.h> | ||
|
||
|
@@ -35,6 +36,46 @@ 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 | ||
}; | ||
|
||
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 | ||
); | ||
Comment on lines
+56
to
+61
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. Do we want to print something in the function called to update data? This might very well be justified, I just don't understand it for now, and so I wanted to ask. |
||
|
||
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) { | ||
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) | ||
{ | ||
class_type->ce_flags |= ZEND_ACC_USE_GUARDS; | ||
|
@@ -73,6 +114,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, | ||
|
@@ -81,7 +130,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), | ||
|
@@ -185,12 +234,16 @@ 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 { | ||
zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code); | ||
} | ||
|
||
RETVAL_NULL(); | ||
|
||
return FAILURE; | ||
} | ||
|
||
|
@@ -209,6 +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; | ||
update_json_error_info_data(&parser); | ||
return false; | ||
} | ||
|
||
|
@@ -232,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); | ||
|
@@ -272,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; | ||
} | ||
|
@@ -323,12 +381,13 @@ PHP_FUNCTION(json_validate) | |
Z_PARAM_LONG(options) | ||
ZEND_PARSE_PARAMETERS_END(); | ||
|
||
|
||
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_json_error_info(&json_error_info_data); | ||
|
||
if (!str_len) { | ||
JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; | ||
RETURN_FALSE; | ||
|
@@ -350,7 +409,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(); | ||
|
@@ -359,11 +418,27 @@ 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 || !json_error_info_data.token || strlen((const char*)json_error_info_data.token) == 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); | ||
} | ||
/* }}} */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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}]" | ||
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 is exactly what I was talking about when I mentioned that the might not be exactly right. This is not where ther error is. 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. There are likely many more examples where this would fail. |
||
Done |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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(92) "Malformed UTF-8 characters, possibly incorrectly encoded, at character 0 near content: %s" | ||
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. You should check for the exact error message (i.e. the |
||
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" | ||
|
Uh oh!
There was an error while loading. Please reload this page.