From 941b07ff72b67171196322776f162dc28344876e Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Apr 2025 00:48:31 +0100 Subject: [PATCH 1/3] ext/json: Various small refactorings --- ext/json/json_encoder.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index c147b8eb23d73..72185126b9632 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -41,15 +41,9 @@ static zend_always_inline bool php_json_check_stack_limit(void) #endif } -static int php_json_determine_array_type(zval *val) /* {{{ */ +static int php_json_determine_array_type(const HashTable *ht) /* {{{ */ { - zend_array *myht = Z_ARRVAL_P(val); - - if (myht) { - return zend_array_is_list(myht) ? PHP_JSON_OUTPUT_ARRAY : PHP_JSON_OUTPUT_OBJECT; - } - - return PHP_JSON_OUTPUT_ARRAY; + return zend_array_is_list(ht) ? PHP_JSON_OUTPUT_ARRAY : PHP_JSON_OUTPUT_OBJECT; } /* }}} */ @@ -63,12 +57,10 @@ static inline void php_json_pretty_print_char(smart_str *buf, int options, char } /* }}} */ -static inline void php_json_pretty_print_indent(smart_str *buf, int options, php_json_encoder *encoder) /* {{{ */ +static inline void php_json_pretty_print_indent(smart_str *buf, int options, const php_json_encoder *encoder) /* {{{ */ { - int i; - if (options & PHP_JSON_PRETTY_PRINT) { - for (i = 0; i < encoder->depth; ++i) { + for (int i = 0; i < encoder->depth; ++i) { smart_str_appendl(buf, " ", 4); } } @@ -122,7 +114,8 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options) static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, php_json_encoder *encoder) /* {{{ */ { - int r, need_comma = 0; + int r; + bool need_comma = false; HashTable *myht, *prop_ht; zend_refcounted *recursion_rc; @@ -138,7 +131,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, myht = Z_ARRVAL_P(val); recursion_rc = (zend_refcounted *)myht; prop_ht = NULL; - r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(val); + r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(myht); } else if (Z_OBJ_P(val)->properties == NULL && Z_OBJ_HT_P(val)->get_properties_for == NULL && Z_OBJ_HT_P(val)->get_properties == zend_std_get_properties @@ -146,9 +139,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, && !zend_object_is_lazy(Z_OBJ_P(val))) { /* Optimized version without rebuilding properties HashTable */ zend_object *obj = Z_OBJ_P(val); - zend_class_entry *ce = obj->ce; - zend_property_info *prop_info; - zval *prop; + const zend_class_entry *ce = obj->ce; if (GC_IS_RECURSIVE(obj)) { encoder->error_code = PHP_JSON_ERROR_RECURSION; @@ -163,7 +154,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, ++encoder->depth; for (int i = 0; i < ce->default_properties_count; i++) { - prop_info = ce->properties_info_table[i]; + zend_property_info *prop_info = ce->properties_info_table[i]; if (!prop_info) { continue; } @@ -171,7 +162,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, /* Skip protected and private members. */ continue; } - prop = OBJ_PROP(obj, prop_info->offset); + zval *prop = OBJ_PROP(obj, prop_info->offset); if (Z_TYPE_P(prop) == IS_UNDEF) { continue; } @@ -270,7 +261,8 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, php_json_pretty_print_char(buf, options, '\n'); php_json_pretty_print_indent(buf, options, encoder); - } else if (r == PHP_JSON_OUTPUT_OBJECT) { + } else { + ZEND_ASSERT(r == PHP_JSON_OUTPUT_OBJECT); if (key) { if (ZSTR_VAL(key)[0] == '\0' && ZSTR_LEN(key) > 0 && Z_TYPE_P(val) == IS_OBJECT) { /* Skip protected and private members. */ @@ -369,7 +361,6 @@ zend_result php_json_escape_string( smart_str *buf, const char *s, size_t len, int options, php_json_encoder *encoder) /* {{{ */ { - unsigned int us; size_t pos, checkpoint; char *dst; @@ -407,7 +398,7 @@ zend_result php_json_escape_string( 0xffffffff, 0x500080c4, 0x10000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}; - us = (unsigned char)s[pos]; + unsigned int us = (unsigned char)s[pos]; if (EXPECTED(!ZEND_BIT_TEST(charmap, us))) { pos++; len--; @@ -626,7 +617,7 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zend_obje static zend_result php_json_encode_serializable_enum(smart_str *buf, zval *val, int options, php_json_encoder *encoder) { - zend_class_entry *ce = Z_OBJCE_P(val); + const zend_class_entry *ce = Z_OBJCE_P(val); if (ce->enum_backing_type == IS_UNDEF) { encoder->error_code = PHP_JSON_ERROR_NON_BACKED_ENUM; smart_str_appendc(buf, '0'); From c275f910a79d9be2f72836cec920f300c7982130 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Apr 2025 01:00:49 +0100 Subject: [PATCH 2/3] ext/json: Refactor php_json_encode_array() Stop relying on internal flags which were published in the header Use a more descriptive variable name and have it be a boolean --- ext/json/json_encoder.c | 19 ++++++------------- ext/json/php_json.h | 4 ---- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 72185126b9632..a73277915405d 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -41,12 +41,6 @@ static zend_always_inline bool php_json_check_stack_limit(void) #endif } -static int php_json_determine_array_type(const HashTable *ht) /* {{{ */ -{ - return zend_array_is_list(ht) ? PHP_JSON_OUTPUT_ARRAY : PHP_JSON_OUTPUT_OBJECT; -} -/* }}} */ - /* {{{ Pretty printing support functions */ static inline void php_json_pretty_print_char(smart_str *buf, int options, char c) /* {{{ */ @@ -114,7 +108,7 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options) static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, php_json_encoder *encoder) /* {{{ */ { - int r; + bool encode_as_object = options & PHP_JSON_FORCE_OBJECT; bool need_comma = false; HashTable *myht, *prop_ht; zend_refcounted *recursion_rc; @@ -131,7 +125,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, myht = Z_ARRVAL_P(val); recursion_rc = (zend_refcounted *)myht; prop_ht = NULL; - r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(myht); + encode_as_object = encode_as_object || !zend_array_is_list(myht); } else if (Z_OBJ_P(val)->properties == NULL && Z_OBJ_HT_P(val)->get_properties_for == NULL && Z_OBJ_HT_P(val)->get_properties == zend_std_get_properties @@ -219,7 +213,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, * referenced from a different place in the object graph. */ recursion_rc = (zend_refcounted *)obj; } - r = PHP_JSON_OUTPUT_OBJECT; + encode_as_object = true; } if (recursion_rc && GC_IS_RECURSIVE(recursion_rc)) { @@ -231,7 +225,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, PHP_JSON_HASH_PROTECT_RECURSION(recursion_rc); - if (r == PHP_JSON_OUTPUT_ARRAY) { + if (!encode_as_object) { smart_str_appendc(buf, '['); } else { smart_str_appendc(buf, '{'); @@ -250,7 +244,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, zval tmp; ZVAL_UNDEF(&tmp); - if (r == PHP_JSON_OUTPUT_ARRAY) { + if (!encode_as_object) { ZEND_ASSERT(Z_TYPE_P(data) != IS_PTR); if (need_comma) { @@ -262,7 +256,6 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, php_json_pretty_print_char(buf, options, '\n'); php_json_pretty_print_indent(buf, options, encoder); } else { - ZEND_ASSERT(r == PHP_JSON_OUTPUT_OBJECT); if (key) { if (ZSTR_VAL(key)[0] == '\0' && ZSTR_LEN(key) > 0 && Z_TYPE_P(val) == IS_OBJECT) { /* Skip protected and private members. */ @@ -346,7 +339,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, php_json_pretty_print_indent(buf, options, encoder); } - if (r == PHP_JSON_OUTPUT_ARRAY) { + if (!encode_as_object) { smart_str_appendc(buf, ']'); } else { smart_str_appendc(buf, '}'); diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 00c87eca53c9e..b79c7c836f7a3 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -79,10 +79,6 @@ typedef enum { #define PHP_JSON_INVALID_UTF8_SUBSTITUTE (1<<21) #define PHP_JSON_THROW_ON_ERROR (1<<22) -/* Internal flags */ -#define PHP_JSON_OUTPUT_ARRAY 0 -#define PHP_JSON_OUTPUT_OBJECT 1 - /* default depth */ #define PHP_JSON_PARSER_DEFAULT_DEPTH 512 From 9863f62a3ed547d2c9f697ef806d71b0323c0ef7 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 26 Apr 2025 01:22:21 +0100 Subject: [PATCH 3/3] ext/json: Refactor parser methods Remove unused parser functions Voidify functions that always return SUCCESS Use zend_return type as return type for php_json_parser_func_object_update_t instead of int --- ext/json/json_parser.y | 46 +++++++++----------------------------- ext/json/php_json_parser.h | 20 ++++------------- 2 files changed, 14 insertions(+), 52 deletions(-) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index d570cddc91e4b..aa0293964d0b4 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -68,8 +68,8 @@ int json_yydebug = 1; %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_parser_array_create(php_json_parser *parser, zval *array); -static int php_json_parser_object_create(php_json_parser *parser, zval *array); +static void php_json_parser_array_create(php_json_parser *parser, zval *array); +static void php_json_parser_object_create(php_json_parser *parser, zval *array); } @@ -89,17 +89,11 @@ object: '{' { PHP_JSON_DEPTH_INC; - if (parser->methods.object_start && FAILURE == parser->methods.object_start(parser)) { - YYERROR; - } } members object_end { ZVAL_COPY_VALUE(&$$, &$3); PHP_JSON_DEPTH_DEC; - if (parser->methods.object_end && FAILURE == parser->methods.object_end(parser, &$$)) { - YYERROR; - } } ; @@ -145,17 +139,11 @@ array: '[' { PHP_JSON_DEPTH_INC; - if (parser->methods.array_start && FAILURE == parser->methods.array_start(parser)) { - YYERROR; - } } elements array_end { ZVAL_COPY_VALUE(&$$, &$3); PHP_JSON_DEPTH_DEC; - if (parser->methods.array_end && FAILURE == parser->methods.array_end(parser, &$$)) { - YYERROR; - } } ; @@ -212,29 +200,26 @@ value: %% /* Functions */ -static int php_json_parser_array_create(php_json_parser *parser, zval *array) +static void php_json_parser_array_create(php_json_parser *parser, zval *array) { array_init(array); - return SUCCESS; } -static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue) +static void php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue) { zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); - return SUCCESS; } -static int php_json_parser_object_create(php_json_parser *parser, zval *object) +static void php_json_parser_object_create(php_json_parser *parser, zval *object) { if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { array_init(object); } else { object_init(object); } - return SUCCESS; } -static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +static zend_result php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) { /* if JSON_OBJECT_AS_ARRAY is set */ if (Z_TYPE_P(object) == IS_ARRAY) { @@ -255,24 +240,21 @@ static int php_json_parser_object_update(php_json_parser *parser, zval *object, return SUCCESS; } -static int php_json_parser_array_create_validate(php_json_parser *parser, zval *array) +static void php_json_parser_array_create_validate(php_json_parser *parser, zval *array) { ZVAL_NULL(array); - return SUCCESS; } -static int php_json_parser_array_append_validate(php_json_parser *parser, zval *array, zval *zvalue) +static void php_json_parser_array_append_validate(php_json_parser *parser, zval *array, zval *zvalue) { - return SUCCESS; } -static int php_json_parser_object_create_validate(php_json_parser *parser, zval *object) +static void php_json_parser_object_create_validate(php_json_parser *parser, zval *object) { ZVAL_NULL(object); - return SUCCESS; } -static int php_json_parser_object_update_validate(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +static zend_result php_json_parser_object_update_validate(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) { return SUCCESS; } @@ -312,24 +294,16 @@ static const php_json_parser_methods default_parser_methods = { php_json_parser_array_create, php_json_parser_array_append, - NULL, - NULL, php_json_parser_object_create, php_json_parser_object_update, - NULL, - NULL, }; static const php_json_parser_methods validate_parser_methods = { php_json_parser_array_create_validate, php_json_parser_array_append_validate, - NULL, - NULL, php_json_parser_object_create_validate, php_json_parser_object_update_validate, - NULL, - NULL, }; PHP_JSON_API void php_json_parser_init_ex(php_json_parser *parser, diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h index 8aedce9ac55d6..e65b33c498be5 100644 --- a/ext/json/php_json_parser.h +++ b/ext/json/php_json_parser.h @@ -22,32 +22,20 @@ typedef struct _php_json_parser php_json_parser; -typedef int (*php_json_parser_func_array_create_t)( +typedef void (*php_json_parser_func_array_create_t)( php_json_parser *parser, zval *array); -typedef int (*php_json_parser_func_array_append_t)( +typedef void (*php_json_parser_func_array_append_t)( php_json_parser *parser, zval *array, zval *zvalue); -typedef int (*php_json_parser_func_array_start_t)( - php_json_parser *parser); -typedef int (*php_json_parser_func_array_end_t)( +typedef void (*php_json_parser_func_object_create_t)( php_json_parser *parser, zval *object); -typedef int (*php_json_parser_func_object_create_t)( - php_json_parser *parser, zval *object); -typedef int (*php_json_parser_func_object_update_t)( +typedef zend_result (*php_json_parser_func_object_update_t)( php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); -typedef int (*php_json_parser_func_object_start_t)( - php_json_parser *parser); -typedef int (*php_json_parser_func_object_end_t)( - php_json_parser *parser, zval *object); typedef struct _php_json_parser_methods { php_json_parser_func_array_create_t array_create; php_json_parser_func_array_append_t array_append; - php_json_parser_func_array_start_t array_start; - php_json_parser_func_array_end_t array_end; php_json_parser_func_object_create_t object_create; php_json_parser_func_object_update_t object_update; - php_json_parser_func_object_start_t object_start; - php_json_parser_func_object_end_t object_end; } php_json_parser_methods; struct _php_json_parser {