From 86b49211577ffe146950b561cbe7e9aacfdcf674 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 16 Feb 2026 11:44:15 +0000 Subject: [PATCH 01/10] ext/session: only return false when could not encode session at all (#21181) * ext/session: only return false when could not encode session at all This also fixes bug 71162 --- ext/session/session.c | 64 +++++++++---------- ext/session/tests/session_encode_error2.phpt | 8 +-- .../tests/session_encode_partial_data.phpt | 30 +++++++++ .../tests/session_encode_variation1.phpt | 6 +- .../tests/session_encode_variation2.phpt | 2 +- .../tests/session_encode_variation6.phpt | 6 +- .../tests/user_session_module/bug71162.phpt | 4 +- .../session_set_save_handler_variation5.phpt | 2 +- 8 files changed, 75 insertions(+), 47 deletions(-) create mode 100644 ext/session/tests/session_encode_partial_data.phpt diff --git a/ext/session/session.c b/ext/session/session.c index d9a4e2b5a4d2b..5a05700608cc2 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -507,24 +507,24 @@ static void php_session_save_current_state(bool write) IF_SESSION_VARS() { zval *handler_function = &PS(mod_user_names).ps_write; if (PS(mod_data) || PS(mod_user_implemented)) { - zend_string *val; - - val = php_session_encode(); - if (val) { - if (PS(lazy_write) && PS(session_vars) - && PS(mod)->s_update_timestamp - && PS(mod)->s_update_timestamp != php_session_update_timestamp - && zend_string_equals(val, PS(session_vars)) - ) { - ret = PS(mod)->s_update_timestamp(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); - handler_function = &PS(mod_user_names).ps_update_timestamp; - } else { - ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); - } - zend_string_release_ex(val, false); + zend_string *val = php_session_encode(); + /* Not being able to encode the session data means there is some kind of issue that prevents a write + * (e.g. a key containing the '|' character with the default serialization) */ + if (UNEXPECTED(val == NULL)) { + return; + } + + if (PS(lazy_write) && PS(session_vars) + && PS(mod)->s_update_timestamp + && PS(mod)->s_update_timestamp != php_session_update_timestamp + && zend_string_equals(val, PS(session_vars)) + ) { + ret = PS(mod)->s_update_timestamp(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); + handler_function = &PS(mod_user_names).ps_update_timestamp; } else { - ret = PS(mod)->s_write(&PS(mod_data), PS(id), ZSTR_EMPTY_ALLOC(), PS(gc_maxlifetime)); + ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, PS(gc_maxlifetime)); } + zend_string_release_ex(val, false); } if ((ret == FAILURE) && !EG(exception)) { @@ -929,7 +929,7 @@ PS_SERIALIZER_ENCODE_FUNC(php_serialize) php_var_serialize(&buf, Z_REFVAL(PS(http_session_vars)), &var_hash); PHP_VAR_SERIALIZE_DESTROY(var_hash); } - return buf.s; + return smart_str_extract(&buf); } PS_SERIALIZER_DECODE_FUNC(php_serialize) @@ -980,11 +980,9 @@ PS_SERIALIZER_ENCODE_FUNC(php_binary) smart_str_append(&buf, key); php_var_serialize(&buf, struc, &var_hash); ); - - smart_str_0(&buf); PHP_VAR_SERIALIZE_DESTROY(var_hash); - return buf.s; + return smart_str_extract(&buf); } PS_SERIALIZER_DECODE_FUNC(php_binary) @@ -1038,7 +1036,6 @@ PS_SERIALIZER_ENCODE_FUNC(php) PS_ENCODE_LOOP( smart_str_append(&buf, key); if (memchr(ZSTR_VAL(key), PS_DELIMITER, ZSTR_LEN(key))) { - PHP_VAR_SERIALIZE_DESTROY(var_hash); smart_str_free(&buf); fail = true; php_error_docref(NULL, E_WARNING, "Failed to write session data. Data contains invalid key \"%s\"", ZSTR_VAL(key)); @@ -1047,15 +1044,15 @@ PS_SERIALIZER_ENCODE_FUNC(php) smart_str_appendc(&buf, PS_DELIMITER); php_var_serialize(&buf, struc, &var_hash); ); + PHP_VAR_SERIALIZE_DESTROY(var_hash); if (fail) { return NULL; } - smart_str_0(&buf); + zend_string *encoded = smart_str_extract(&buf); - PHP_VAR_SERIALIZE_DESTROY(var_hash); - return buf.s; + return encoded; } PS_SERIALIZER_DECODE_FUNC(php) @@ -2280,7 +2277,6 @@ PHP_FUNCTION(session_id) PHP_FUNCTION(session_regenerate_id) { bool del_ses = false; - zend_string *data; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &del_ses) == FAILURE) { RETURN_THROWS(); @@ -2307,14 +2303,17 @@ PHP_FUNCTION(session_regenerate_id) RETURN_FALSE; } } else { - zend_result ret; - data = php_session_encode(); - if (data) { - ret = PS(mod)->s_write(&PS(mod_data), PS(id), data, PS(gc_maxlifetime)); - zend_string_release_ex(data, false); - } else { - ret = PS(mod)->s_write(&PS(mod_data), PS(id), ZSTR_EMPTY_ALLOC(), PS(gc_maxlifetime)); + zend_string *old_session_data = php_session_encode(); + /* If we have no data we must destroy the related session ID */ + if (UNEXPECTED(old_session_data == NULL)) { + PS(mod)->s_close(&PS(mod_data)); + PS(session_status) = php_session_none; + RETURN_FALSE; } + + zend_result ret = PS(mod)->s_write(&PS(mod_data), PS(id), old_session_data, PS(gc_maxlifetime)); + zend_string_release_ex(old_session_data, false); + if (ret == FAILURE) { PS(mod)->s_close(&PS(mod_data)); PS(session_status) = php_session_none; @@ -2368,6 +2367,7 @@ PHP_FUNCTION(session_regenerate_id) // TODO warn that ID cannot be verified? else { } } /* Read is required to make new session data at this point. */ + zend_string *data = NULL; if (PS(mod)->s_read(&PS(mod_data), PS(id), &data, PS(gc_maxlifetime)) == FAILURE) { PS(mod)->s_close(&PS(mod_data)); PS(session_status) = php_session_none; diff --git a/ext/session/tests/session_encode_error2.phpt b/ext/session/tests/session_encode_error2.phpt index e112d69353933..42f5c4dd6888b 100644 --- a/ext/session/tests/session_encode_error2.phpt +++ b/ext/session/tests/session_encode_error2.phpt @@ -51,28 +51,28 @@ ob_end_flush(); bool(true) Warning: session_encode(): Skipping numeric key 0 in %s on line %d -bool(false) +string(0) "" bool(true) -- Iteration 2 -- bool(true) Warning: session_encode(): Skipping numeric key 1 in %s on line %d -bool(false) +string(0) "" bool(true) -- Iteration 3 -- bool(true) Warning: session_encode(): Skipping numeric key 12345 in %s on line %d -bool(false) +string(0) "" bool(true) -- Iteration 4 -- bool(true) Warning: session_encode(): Skipping numeric key -2345 in %s on line %d -bool(false) +string(0) "" bool(true) -- Iteration 5 -- diff --git a/ext/session/tests/session_encode_partial_data.phpt b/ext/session/tests/session_encode_partial_data.phpt new file mode 100644 index 0000000000000..9236dbcb11117 --- /dev/null +++ b/ext/session/tests/session_encode_partial_data.phpt @@ -0,0 +1,30 @@ +--TEST-- +session_encode(): partial session data +--INI-- +serialize_precision=100 +--EXTENSIONS-- +session +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: session_encode(): Failed to write session data. Data contains invalid key "partial|data" in %s on line %d +bool(false) +bool(true) diff --git a/ext/session/tests/session_encode_variation1.phpt b/ext/session/tests/session_encode_variation1.phpt index 1b5be5e42dcb6..4a948eba69c0d 100644 --- a/ext/session/tests/session_encode_variation1.phpt +++ b/ext/session/tests/session_encode_variation1.phpt @@ -30,11 +30,11 @@ ob_end_flush(); Warning: session_encode(): Cannot encode non-existent session in %s on line %d bool(false) bool(true) -bool(false) +string(0) "" bool(true) -bool(false) +string(0) "" bool(true) -bool(false) +string(0) "" bool(true) Warning: session_encode(): Cannot encode non-existent session in %s on line %d diff --git a/ext/session/tests/session_encode_variation2.phpt b/ext/session/tests/session_encode_variation2.phpt index 8803c3080696b..3984ec7110081 100644 --- a/ext/session/tests/session_encode_variation2.phpt +++ b/ext/session/tests/session_encode_variation2.phpt @@ -22,7 +22,7 @@ ob_end_flush(); ?> --EXPECTF-- *** Testing session_encode() : variation *** -bool(false) +string(0) "" bool(true) Warning: session_encode(): Cannot encode non-existent session in %s on line %d diff --git a/ext/session/tests/session_encode_variation6.phpt b/ext/session/tests/session_encode_variation6.phpt index 301dbd61679ac..2b3ab0e78a095 100644 --- a/ext/session/tests/session_encode_variation6.phpt +++ b/ext/session/tests/session_encode_variation6.phpt @@ -32,16 +32,16 @@ ob_end_flush(); bool(true) Warning: session_encode(): Skipping numeric key 0 in %s on line %d -bool(false) +string(0) "" bool(true) bool(true) Warning: session_encode(): Skipping numeric key 1234567890 in %s on line %d -bool(false) +string(0) "" bool(true) bool(true) Warning: session_encode(): Skipping numeric key -1234567890 in %s on line %d -bool(false) +string(0) "" bool(true) Done diff --git a/ext/session/tests/user_session_module/bug71162.phpt b/ext/session/tests/user_session_module/bug71162.phpt index 673e6ac2ecb19..54679973dc31d 100644 --- a/ext/session/tests/user_session_module/bug71162.phpt +++ b/ext/session/tests/user_session_module/bug71162.phpt @@ -4,8 +4,6 @@ updateTimestamp never called when session data is empty session --INI-- session.use_strict_mode=0 ---XFAIL-- -Current session module is designed to write empty session always. --FILE-- Date: Mon, 16 Feb 2026 11:51:48 +0000 Subject: [PATCH 02/10] Update NEWS and UPGRADING for ext/session changes --- NEWS | 4 ++++ UPGRADING | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/NEWS b/NEWS index 782ee4be4d185..e6688bb6791be 100644 --- a/NEWS +++ b/NEWS @@ -87,6 +87,10 @@ PHP NEWS . Fixed bug GH-20217 (ReflectionClass::isIterable() incorrectly returns true for classes with property hooks). (alexandre-daubois) +- Session: + . Fixed bug 71162 (updateTimestamp never called when session data is empty). + (Girgias) + - Soap: . Soap::__setCookie() when cookie name is a digit is now not stored and represented as a string anymore but a int. (David Carlier) diff --git a/UPGRADING b/UPGRADING index f5bf9729855a1..2bf6d4953388d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -26,6 +26,10 @@ PHP 8.6 UPGRADE NOTES - Session: . A ValueError is not thrown if $name is a string containing null bytes in session_module_name(). + . session_encode() now returns an empty string instead of false for empty + sessions. It only returns false now when the session data could not be + encoded. This mainly happens with the default serialization handler + if a key contains the pipe | character. - Standard: . Invalid mode values now throw in array_filter() instead of being silently From 9c900b6e3485d49b4fc5d677ff3d139926f61644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 16 Feb 2026 14:19:29 +0100 Subject: [PATCH 03/10] zend_compile: Bundle function type constants into an `zend_function_type` enum (#21208) * zend_compile: Bundle function type constants into an `zend_function_type` enum This clarifies the relationship between these constants and improves type safety a little. * Add C23_ENUM() helper macro * zend_portability: Rename `size` to `underlying_type` in `C23_ENUM()` * zend_portability: Include the leading `enum` in the `C23_ENUM` macro * Fix comment for C23_ENUM() --- UPGRADING.INTERNALS | 2 ++ Zend/zend_compile.h | 20 +++++++++++--------- Zend/zend_language_scanner.l | 2 +- Zend/zend_opcode.c | 2 +- Zend/zend_portability.h | 13 +++++++++++++ 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 06c1d52826229..0c8e10e17f084 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -72,6 +72,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES zend_string* parameter. . EG(in_autoload) was renamed to EG(autoload_current_classnames) and no longer is a pointer, but a directly embedded HashTable struct. + . Added a C23_ENUM() helper macro to define forward-compatible fixed-size + enums. ======================== 2. Build system changes diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 587ae485ec821..41bbdde5a38de 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -497,6 +497,12 @@ typedef struct _zend_class_constant { #define ZEND_CLASS_CONST_FLAGS(c) Z_CONSTANT_FLAGS((c)->value) +C23_ENUM(zend_function_type, uint8_t) { + ZEND_INTERNAL_FUNCTION = 1, + ZEND_USER_FUNCTION = 2, + ZEND_EVAL_CODE = 4, +}; + /* arg_info for internal functions */ typedef struct _zend_internal_arg_info { const char *name; @@ -524,7 +530,7 @@ typedef struct _zend_internal_function_info { struct _zend_op_array { /* Common elements */ - uint8_t type; + zend_function_type type; uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; @@ -584,7 +590,7 @@ typedef void (ZEND_FASTCALL *zif_handler)(INTERNAL_FUNCTION_PARAMETERS); typedef struct _zend_internal_function { /* Common elements */ - uint8_t type; + zend_function_type type; uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string* function_name; @@ -610,11 +616,11 @@ typedef struct _zend_internal_function { #define ZEND_FN_SCOPE_NAME(function) ((function) && (function)->common.scope ? ZSTR_VAL((function)->common.scope->name) : "") union _zend_function { - uint8_t type; /* MUST be the first element of this struct! */ + zend_function_type type; /* MUST be the first element of this struct! */ uint32_t quick_arg_flags; struct { - uint8_t type; /* never used */ + zend_function_type type; /* never used */ uint8_t arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; @@ -956,7 +962,7 @@ ZEND_API zend_ast *zend_compile_string_to_ast( ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count, ...); ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handle *file_handle); ZEND_API zend_result open_file_for_scanning(zend_file_handle *file_handle); -ZEND_API void init_op_array(zend_op_array *op_array, uint8_t type, int initial_ops_size); +ZEND_API void init_op_array(zend_op_array *op_array, zend_function_type type, int initial_ops_size); ZEND_API void destroy_op_array(zend_op_array *op_array); ZEND_API void zend_destroy_static_vars(zend_op_array *op_array); ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle); @@ -1071,10 +1077,6 @@ ZEND_API zend_string *zend_type_to_string(zend_type type); #define BP_VAR_FUNC_ARG 4 #define BP_VAR_UNSET 5 -#define ZEND_INTERNAL_FUNCTION 1 -#define ZEND_USER_FUNCTION 2 -#define ZEND_EVAL_CODE 4 - #define ZEND_USER_CODE(type) ((type) != ZEND_INTERNAL_FUNCTION) #define ZEND_INTERNAL_CLASS 1 diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 5a8a78cc3bd7b..1c985189fd3c0 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -591,7 +591,7 @@ ZEND_API zend_result open_file_for_scanning(zend_file_handle *file_handle) return SUCCESS; } -static zend_op_array *zend_compile(int type) +static zend_op_array *zend_compile(zend_function_type type) { zend_op_array *op_array = NULL; bool original_in_compilation = CG(in_compilation); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index d874f566dc87d..24b480ad71e66 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -45,7 +45,7 @@ static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend } } -void init_op_array(zend_op_array *op_array, uint8_t type, int initial_ops_size) +void init_op_array(zend_op_array *op_array, zend_function_type type, int initial_ops_size) { op_array->type = type; op_array->arg_flags[0] = 0; diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 6546ebfb5b790..c8a6dfa871b5a 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -146,6 +146,19 @@ #define zend_quiet_write(...) ZEND_IGNORE_VALUE(write(__VA_ARGS__)) +/* Define an enum with a fixed underlying type as C23_ENUM(name, underlying_type) { }. */ +#if __STDC_VERSION__ >= 202311L || defined(__cplusplus) +# define C23_ENUM(name, underlying_type) \ + enum name: underlying_type; \ + typedef enum name name; \ + enum name: underlying_type +#else +# define C23_ENUM(name, underlying_type) \ + enum name; \ + typedef underlying_type name; \ + enum name +#endif + /* all HAVE_XXX test have to be after the include of zend_config above */ #if defined(HAVE_LIBDL) && !defined(ZEND_WIN32) From e35b381564eaeb46c76665650432e5b56fe0e38d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Feb 2026 17:53:01 +0000 Subject: [PATCH 04/10] zend_ini: use bool type instead of int type --- Zend/zend_ini.c | 14 +++++++------- Zend/zend_ini.h | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 5e3a12e455379..1f25b2e7926de 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -348,7 +348,7 @@ ZEND_API zend_result zend_alter_ini_entry_chars(zend_string *name, const char *v } /* }}} */ -ZEND_API zend_result zend_alter_ini_entry_chars_ex(zend_string *name, const char *value, size_t value_length, int modify_type, int stage, int force_change) /* {{{ */ +ZEND_API zend_result zend_alter_ini_entry_chars_ex(zend_string *name, const char *value, size_t value_length, int modify_type, int stage, bool force_change) /* {{{ */ { zend_result ret; zend_string *new_value; @@ -457,7 +457,7 @@ ZEND_API zend_result zend_ini_register_displayer(const char *name, uint32_t name * Data retrieval */ -ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, int orig) /* {{{ */ +ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, bool orig) /* {{{ */ { zend_ini_entry *ini_entry; @@ -474,7 +474,7 @@ ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, int orig) } /* }}} */ -ZEND_API double zend_ini_double(const char *name, size_t name_length, int orig) /* {{{ */ +ZEND_API double zend_ini_double(const char *name, size_t name_length, bool orig) /* {{{ */ { zend_ini_entry *ini_entry; @@ -491,7 +491,7 @@ ZEND_API double zend_ini_double(const char *name, size_t name_length, int orig) } /* }}} */ -ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, int orig, bool *exists) /* {{{ */ +ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, bool orig, bool *exists) /* {{{ */ { zend_string *str = zend_ini_str_ex(name, name_length, orig, exists); @@ -499,7 +499,7 @@ ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, int orig } /* }}} */ -ZEND_API char *zend_ini_string(const char *name, size_t name_length, int orig) /* {{{ */ +ZEND_API char *zend_ini_string(const char *name, size_t name_length, bool orig) /* {{{ */ { zend_string *str = zend_ini_str(name, name_length, orig); @@ -886,7 +886,7 @@ ZEND_API zend_ulong zend_ini_parse_uquantity_warn(zend_string *value, zend_strin ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ { - int value; + bool value; zend_string *tmp_value; if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { @@ -900,7 +900,7 @@ ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ if (tmp_value) { value = zend_ini_parse_bool(tmp_value); } else { - value = 0; + value = false; } if (value) { diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 4bb90d6ef0a74..21483d4ddcdff 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -82,14 +82,14 @@ ZEND_API void zend_ini_refresh_caches(int stage); ZEND_API zend_result zend_alter_ini_entry(zend_string *name, zend_string *new_value, int modify_type, int stage); ZEND_API zend_result zend_alter_ini_entry_ex(zend_string *name, zend_string *new_value, int modify_type, int stage, bool force_change); ZEND_API zend_result zend_alter_ini_entry_chars(zend_string *name, const char *value, size_t value_length, int modify_type, int stage); -ZEND_API zend_result zend_alter_ini_entry_chars_ex(zend_string *name, const char *value, size_t value_length, int modify_type, int stage, int force_change); +ZEND_API zend_result zend_alter_ini_entry_chars_ex(zend_string *name, const char *value, size_t value_length, int modify_type, int stage, bool force_change); ZEND_API zend_result zend_restore_ini_entry(zend_string *name, int stage); ZEND_API void display_ini_entries(zend_module_entry *module); -ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, int orig); -ZEND_API double zend_ini_double(const char *name, size_t name_length, int orig); -ZEND_API char *zend_ini_string(const char *name, size_t name_length, int orig); -ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, int orig, bool *exists); +ZEND_API zend_long zend_ini_long(const char *name, size_t name_length, bool orig); +ZEND_API double zend_ini_double(const char *name, size_t name_length, bool orig); +ZEND_API char *zend_ini_string(const char *name, size_t name_length, bool orig); +ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, bool orig, bool *exists); ZEND_API zend_string *zend_ini_str(const char *name, size_t name_length, bool orig); ZEND_API zend_string *zend_ini_str_ex(const char *name, size_t name_length, bool orig, bool *exists); ZEND_API zend_string *zend_ini_get_value(zend_string *name); From ed67072893655b674f885ce5cf2c20a7c100f673 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Feb 2026 18:04:45 +0000 Subject: [PATCH 05/10] zend_ini: use bool type instead of uint8_t type --- Zend/zend_ini.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 21483d4ddcdff..44933cf2dafa9 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -58,7 +58,7 @@ struct _zend_ini_entry { uint8_t modifiable; uint8_t orig_modifiable; - uint8_t modified; + bool modified; const zend_ini_entry_def *def; }; From c2a957135738a1a96f11642eb819783d3f1e45be Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Feb 2026 18:02:12 +0000 Subject: [PATCH 06/10] zend_ini: Use true/false rather than 1/0 for bool arguments --- Zend/zend_ini.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 1f25b2e7926de..4263f653963dc 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -70,9 +70,9 @@ static zend_result zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stag } ini_entry->value = ini_entry->orig_value; ini_entry->modifiable = ini_entry->orig_modifiable; - ini_entry->modified = 0; + ini_entry->modified = false; ini_entry->orig_value = NULL; - ini_entry->orig_modifiable = 0; + ini_entry->orig_modifiable = false; } return SUCCESS; } @@ -82,12 +82,12 @@ static void free_ini_entry(zval *zv) /* {{{ */ { zend_ini_entry *entry = (zend_ini_entry*)Z_PTR_P(zv); - zend_string_release_ex(entry->name, 1); + zend_string_release_ex(entry->name, true); if (entry->value) { zend_string_release(entry->value); } if (entry->orig_value) { - zend_string_release_ex(entry->orig_value, 1); + zend_string_release_ex(entry->orig_value, true); } free(entry); } @@ -103,7 +103,7 @@ ZEND_API void zend_ini_startup(void) /* {{{ */ EG(ini_directives) = registered_zend_ini_directives; EG(modified_ini_directives) = NULL; EG(error_reporting_ini_entry) = NULL; - zend_hash_init(registered_zend_ini_directives, 128, NULL, free_ini_entry, 1); + zend_hash_init(registered_zend_ini_directives, 128, NULL, free_ini_entry, true); } /* }}} */ @@ -146,18 +146,18 @@ ZEND_API void zend_ini_deactivate(void) /* {{{ */ static void copy_ini_entry(zval *zv) /* {{{ */ { zend_ini_entry *old_entry = (zend_ini_entry*)Z_PTR_P(zv); - zend_ini_entry *new_entry = pemalloc(sizeof(zend_ini_entry), 1); + zend_ini_entry *new_entry = pemalloc(sizeof(zend_ini_entry), true); Z_PTR_P(zv) = new_entry; memcpy(new_entry, old_entry, sizeof(zend_ini_entry)); if (old_entry->name) { - new_entry->name = zend_string_dup(old_entry->name, 1); + new_entry->name = zend_string_dup(old_entry->name, true); } if (old_entry->value) { - new_entry->value = zend_string_dup(old_entry->value, 1); + new_entry->value = zend_string_dup(old_entry->value, true); } if (old_entry->orig_value) { - new_entry->orig_value = zend_string_dup(old_entry->orig_value, 1); + new_entry->orig_value = zend_string_dup(old_entry->orig_value, true); } } /* }}} */ @@ -167,7 +167,7 @@ ZEND_API void zend_copy_ini_directives(void) /* {{{ */ EG(modified_ini_directives) = NULL; EG(error_reporting_ini_entry) = NULL; EG(ini_directives) = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init(EG(ini_directives), registered_zend_ini_directives->nNumOfElements, NULL, free_ini_entry, 1); + zend_hash_init(EG(ini_directives), registered_zend_ini_directives->nNumOfElements, NULL, free_ini_entry, true); zend_hash_copy(EG(ini_directives), registered_zend_ini_directives, copy_ini_entry); } /* }}} */ @@ -194,7 +194,7 @@ static int ini_key_compare(Bucket *f, Bucket *s) /* {{{ */ ZEND_API void zend_ini_sort_entries(void) /* {{{ */ { - zend_hash_sort(EG(ini_directives), ini_key_compare, 0); + zend_hash_sort(EG(ini_directives), ini_key_compare, false); } /* }}} */ @@ -224,9 +224,9 @@ ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_ #endif while (ini_entry->name) { - p = pemalloc(sizeof(zend_ini_entry), 1); + p = pemalloc(sizeof(zend_ini_entry), true); p->def = ini_entry; - p->name = zend_string_init_interned(ini_entry->name, ini_entry->name_length, 1); + p->name = zend_string_init_interned(ini_entry->name, ini_entry->name_length, true); p->on_modify = ini_entry->on_modify; p->mh_arg1 = ini_entry->mh_arg1; p->mh_arg2 = ini_entry->mh_arg2; @@ -236,13 +236,13 @@ ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_ p->displayer = ini_entry->displayer; p->modifiable = ini_entry->modifiable; - p->orig_modifiable = 0; - p->modified = 0; + p->orig_modifiable = false; + p->modified = false; p->module_number = module_number; if (zend_hash_add_ptr(directives, p->name, (void*)p) == NULL) { if (p->name) { - zend_string_release_ex(p->name, 1); + zend_string_release_ex(p->name, true); } pefree(p, true); zend_unregister_ini_entries_ex(module_number, module_type); @@ -260,7 +260,7 @@ ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_ } } else { p->value = ini_entry->value ? - zend_string_init_interned(ini_entry->value, ini_entry->value_length, 1) : NULL; + zend_string_init_interned(ini_entry->value, ini_entry->value_length, true) : NULL; if (p->on_modify) { p->on_modify(p, p->value, p->mh_arg1, p->mh_arg2, p->mh_arg3, ZEND_INI_STAGE_STARTUP); @@ -386,12 +386,12 @@ ZEND_API zend_result zend_alter_ini_entry_ex(zend_string *name, zend_string *new if (!EG(modified_ini_directives)) { ALLOC_HASHTABLE(EG(modified_ini_directives)); - zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0); + zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, false); } if (!modified) { ini_entry->orig_value = ini_entry->value; ini_entry->orig_modifiable = modifiable; - ini_entry->modified = 1; + ini_entry->modified = true; zend_hash_add_ptr(EG(modified_ini_directives), ini_entry->name, ini_entry); } @@ -566,7 +566,7 @@ ZEND_API bool zend_ini_parse_bool(zend_string *str) || zend_string_equals_literal_ci(str, "yes") || zend_string_equals_literal_ci(str, "on") ) { - return 1; + return true; } else { return atoi(ZSTR_VAL(str)) != 0; } From 30c09fff6239b78cfe28507cbe25a1ffb27a9588 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Feb 2026 19:52:26 +0000 Subject: [PATCH 07/10] zend_ini: use SUCCESS instead of 0 to compare return value of function returning zend_result --- Zend/zend_ini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 4263f653963dc..9b2c8db59b8ac 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -428,7 +428,7 @@ ZEND_API zend_result zend_restore_ini_entry(zend_string *name, int stage) /* {{{ } if (EG(modified_ini_directives)) { - if (zend_restore_ini_entry_cb(ini_entry, stage) == 0) { + if (zend_restore_ini_entry_cb(ini_entry, stage) == SUCCESS) { zend_hash_del(EG(modified_ini_directives), name); } else { return FAILURE; From d2710685ddc53cf898b9011446652bc18f8ea1e5 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Feb 2026 18:01:16 +0000 Subject: [PATCH 08/10] zend_ini: add const qualifiers --- Zend/zend_ini.c | 26 +++++++++++++------------- Zend/zend_ini.h | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 9b2c8db59b8ac..c7cfd3c6d57a2 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -41,7 +41,7 @@ static inline bool zend_is_whitespace(char c) { */ static int zend_remove_ini_entries(zval *el, void *arg) /* {{{ */ { - zend_ini_entry *ini_entry = (zend_ini_entry *)Z_PTR_P(el); + const zend_ini_entry *ini_entry = (zend_ini_entry *)Z_PTR_P(el); int module_number = *(int *)arg; return ini_entry->module_number == module_number; @@ -560,7 +560,7 @@ ZEND_API zend_string *zend_ini_get_value(zend_string *name) /* {{{ */ } /* }}} */ -ZEND_API bool zend_ini_parse_bool(zend_string *str) +ZEND_API bool zend_ini_parse_bool(const zend_string *str) { if (zend_string_equals_literal_ci(str, "true") || zend_string_equals_literal_ci(str, "yes") @@ -610,12 +610,12 @@ static const char *zend_ini_consume_quantity_prefix(const char *const digits, co return digits_consumed; } -static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_parse_quantity_signed_result_t signed_result, zend_string **errstr) /* {{{ */ +static zend_ulong zend_ini_parse_quantity_internal(const zend_string *value, zend_ini_parse_quantity_signed_result_t signed_result, zend_string **errstr) /* {{{ */ { char *digits_end = NULL; - char *str = ZSTR_VAL(value); - char *str_end = &str[ZSTR_LEN(value)]; - char *digits = str; + const char *str = ZSTR_VAL(value); + const char *str_end = &str[ZSTR_LEN(value)]; + const char *digits = str; bool overflow = false; zend_ulong factor; smart_str invalid = {0}; @@ -844,19 +844,19 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ } /* }}} */ -ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr) /* {{{ */ +ZEND_API zend_long zend_ini_parse_quantity(const zend_string *value, zend_string **errstr) /* {{{ */ { return (zend_long) zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_SIGNED, errstr); } /* }}} */ -ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr) /* {{{ */ +ZEND_API zend_ulong zend_ini_parse_uquantity(const zend_string *value, zend_string **errstr) /* {{{ */ { return zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_UNSIGNED, errstr); } /* }}} */ -ZEND_API zend_long zend_ini_parse_quantity_warn(zend_string *value, zend_string *setting) /* {{{ */ +ZEND_API zend_long zend_ini_parse_quantity_warn(const zend_string *value, zend_string *setting) /* {{{ */ { zend_string *errstr; zend_long retval = zend_ini_parse_quantity(value, &errstr); @@ -870,7 +870,7 @@ ZEND_API zend_long zend_ini_parse_quantity_warn(zend_string *value, zend_string } /* }}} */ -ZEND_API zend_ulong zend_ini_parse_uquantity_warn(zend_string *value, zend_string *setting) /* {{{ */ +ZEND_API zend_ulong zend_ini_parse_uquantity_warn(const zend_string *value, zend_string *setting) /* {{{ */ { zend_string *errstr; zend_ulong retval = zend_ini_parse_uquantity(value, &errstr); @@ -887,7 +887,7 @@ ZEND_API zend_ulong zend_ini_parse_uquantity_warn(zend_string *value, zend_strin ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ { bool value; - zend_string *tmp_value; + const zend_string *tmp_value; if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { tmp_value = (ini_entry->orig_value ? ini_entry->orig_value : NULL ); @@ -913,7 +913,7 @@ ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ ZEND_INI_DISP(zend_ini_color_displayer_cb) /* {{{ */ { - char *value; + const char *value; if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { value = ZSTR_VAL(ini_entry->orig_value); @@ -940,7 +940,7 @@ ZEND_INI_DISP(zend_ini_color_displayer_cb) /* {{{ */ ZEND_INI_DISP(display_link_numbers) /* {{{ */ { - char *value; + const char *value; if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { value = ZSTR_VAL(ini_entry->orig_value); diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 44933cf2dafa9..d8d7f599f461e 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -93,7 +93,7 @@ ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, bool ori ZEND_API zend_string *zend_ini_str(const char *name, size_t name_length, bool orig); ZEND_API zend_string *zend_ini_str_ex(const char *name, size_t name_length, bool orig, bool *exists); ZEND_API zend_string *zend_ini_get_value(zend_string *name); -ZEND_API bool zend_ini_parse_bool(zend_string *str); +ZEND_API bool zend_ini_parse_bool(const zend_string *str); /** * Parses an ini quantity @@ -130,16 +130,16 @@ ZEND_API bool zend_ini_parse_bool(zend_string *str); * In any of these cases an error string is stored in *errstr (caller must * release it), otherwise *errstr is set to NULL. */ -ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr); +ZEND_API zend_long zend_ini_parse_quantity(const zend_string *value, zend_string **errstr); /** * Unsigned variant of zend_ini_parse_quantity */ -ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr); +ZEND_API zend_ulong zend_ini_parse_uquantity(const zend_string *value, zend_string **errstr); -ZEND_API zend_long zend_ini_parse_quantity_warn(zend_string *value, zend_string *setting); +ZEND_API zend_long zend_ini_parse_quantity_warn(const zend_string *value, zend_string *setting); -ZEND_API zend_ulong zend_ini_parse_uquantity_warn(zend_string *value, zend_string *setting); +ZEND_API zend_ulong zend_ini_parse_uquantity_warn(const zend_string *value, zend_string *setting); ZEND_API zend_result zend_ini_register_displayer(const char *name, uint32_t name_length, void (*displayer)(zend_ini_entry *ini_entry, int type)); From b65ccc08ddb341e080164fabd2a737f7cca94f8d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 5 Feb 2026 18:12:59 +0000 Subject: [PATCH 09/10] zend_ini: refactor zend_ini_boolean_displayer_cb --- Zend/zend_ini.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index c7cfd3c6d57a2..d8f1d4f50f95d 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -887,18 +887,11 @@ ZEND_API zend_ulong zend_ini_parse_uquantity_warn(const zend_string *value, zend ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ { bool value; - const zend_string *tmp_value; if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { - tmp_value = (ini_entry->orig_value ? ini_entry->orig_value : NULL ); + value = zend_ini_parse_bool(ini_entry->orig_value); } else if (ini_entry->value) { - tmp_value = ini_entry->value; - } else { - tmp_value = NULL; - } - - if (tmp_value) { - value = zend_ini_parse_bool(tmp_value); + value = zend_ini_parse_bool(ini_entry->value); } else { value = false; } From ede7c673892a0d25947dcbd12f32cc23adf9f9e1 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 16 Feb 2026 12:58:01 +0100 Subject: [PATCH 10/10] Fix build with -std= When building in strict mode (e.g. -std=c11), compilation of main/debug_gdb_scripts.c fails because asm() is not a standard top level statement. __asm__() however can be reserved by the compiler even in strict mode. Partially fixes GH-21215. IR needs a similar fix (dstogov/ir#128). Closes GH-21226. --- NEWS | 1 + main/debug_gdb_scripts.c | 2 +- scripts/gdb/debug_gdb_scripts_gen.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index b8c10e2be2f4a..4f965513037f8 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ PHP NEWS accessing properties on Reflection LazyProxy via isset()). (Arnaud) . Fixed OSS-Fuzz #478009707 (Borked assign-op/inc/dec on untyped hooked property backing value). (ilutov) + . Fixed bug GH-21215 (Build fails with -std=). (Arnaud) - Curl: . Fixed bug GH-21023 (CURLOPT_XFERINFOFUNCTION crash with a null callback). diff --git a/main/debug_gdb_scripts.c b/main/debug_gdb_scripts.c index 032dd09491bac..43282857cf1e6 100644 --- a/main/debug_gdb_scripts.c +++ b/main/debug_gdb_scripts.c @@ -6,7 +6,7 @@ * * See https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html#dotdebug_005fgdb_005fscripts-section */ -asm( +__asm__( ".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n" ".byte 4 /* Python Text */\n" ".ascii \"gdb.inlined-script\\n\"\n" diff --git a/scripts/gdb/debug_gdb_scripts_gen.php b/scripts/gdb/debug_gdb_scripts_gen.php index 1b33d9a63aa6e..2667f249fe4bb 100755 --- a/scripts/gdb/debug_gdb_scripts_gen.php +++ b/scripts/gdb/debug_gdb_scripts_gen.php @@ -27,7 +27,7 @@ * * See https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html#dotdebug_005fgdb_005fscripts-section */ - asm( + __asm__( ".pushsection \".debug_gdb_scripts\", \"MS\",%%progbits,1\n" ".byte 4 /* Python Text */\n" ".ascii \"gdb.inlined-script\\n\"\n"