From 814243a6282fd4c5ac599ba6757baebe99e6e11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 1 Jul 2025 14:49:12 +0200 Subject: [PATCH 1/2] zend_execute: Mark `zend_get_executed_*()` as `__attribute__((pure))` These functions do not modify the state of the program and depend on thread-safe global variables only. --- Zend/zend_execute.h | 8 ++++---- Zend/zend_execute_API.c | 8 ++++---- Zend/zend_portability.h | 6 ++++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index cf15c9e3b2db5..e7b5be8751058 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -460,10 +460,10 @@ static zend_always_inline zend_function *zend_active_function(void) ZEND_API zend_string *get_active_function_or_method_name(void); ZEND_API zend_string *get_function_or_method_name(const zend_function *func); -ZEND_API const char *zend_get_executed_filename(void); -ZEND_API zend_string *zend_get_executed_filename_ex(void); -ZEND_API uint32_t zend_get_executed_lineno(void); -ZEND_API zend_class_entry *zend_get_executed_scope(void); +ZEND_ATTRIBUTE_PURE ZEND_API const char *zend_get_executed_filename(void); +ZEND_ATTRIBUTE_PURE ZEND_API zend_string *zend_get_executed_filename_ex(void); +ZEND_ATTRIBUTE_PURE ZEND_API uint32_t zend_get_executed_lineno(void); +ZEND_ATTRIBUTE_PURE ZEND_API zend_class_entry *zend_get_executed_scope(void); ZEND_API bool zend_is_executing(void); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 18e7028957f71..86e5f43b944a1 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -656,14 +656,14 @@ ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t a } /* }}} */ -ZEND_API const char *zend_get_executed_filename(void) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API const char *zend_get_executed_filename(void) /* {{{ */ { zend_string *filename = zend_get_executed_filename_ex(); return filename != NULL ? ZSTR_VAL(filename) : "[no active file]"; } /* }}} */ -ZEND_API zend_string *zend_get_executed_filename_ex(void) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API zend_string *zend_get_executed_filename_ex(void) /* {{{ */ { zend_string *filename_override = EG(filename_override); if (filename_override != NULL) { @@ -683,7 +683,7 @@ ZEND_API zend_string *zend_get_executed_filename_ex(void) /* {{{ */ } /* }}} */ -ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ { zend_long lineno_override = EG(lineno_override); if (lineno_override != -1) { @@ -711,7 +711,7 @@ ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */ } /* }}} */ -ZEND_API zend_class_entry *zend_get_executed_scope(void) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API zend_class_entry *zend_get_executed_scope(void) /* {{{ */ { zend_execute_data *ex = EG(current_execute_data); diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 7a41a496a0ed7..7db18ad8baf6b 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -251,6 +251,12 @@ char *alloca(); # define ZEND_ATTRIBUTE_CONST #endif +#if ZEND_GCC_VERSION >= 3000 +# define ZEND_ATTRIBUTE_PURE __attribute__((pure)) +#else +# define ZEND_ATTRIBUTE_PURE +#endif + #if ZEND_GCC_VERSION >= 2007 || __has_attribute(format) # define ZEND_ATTRIBUTE_FORMAT(type, idx, first) __attribute__ ((format(type, idx, first))) #else From edf10a4e86d08a4a47c782891885758bdc7b2790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 3 Jul 2025 14:33:52 +0200 Subject: [PATCH 2/2] Additional purity --- Zend/zend_API.c | 8 ++++---- Zend/zend_API.h | 6 +++--- Zend/zend_execute.h | 12 ++++++------ Zend/zend_execute_API.c | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e05422395ec19..3741ed6b7118c 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -116,7 +116,7 @@ ZEND_API ZEND_COLD void zend_wrong_property_read(zval *object, zval *property) } /* Argument parsing API -- andrei */ -ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */ +ZEND_ATTRIBUTE_CONST ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */ { switch(type) { case IS_FALSE: @@ -152,7 +152,7 @@ ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */ } /* }}} */ -ZEND_API const char *zend_zval_value_name(const zval *arg) +ZEND_ATTRIBUTE_PURE ZEND_API const char *zend_zval_value_name(const zval *arg) { ZVAL_DEREF(arg); @@ -171,7 +171,7 @@ ZEND_API const char *zend_zval_value_name(const zval *arg) return zend_get_type_by_const(Z_TYPE_P(arg)); } -ZEND_API const char *zend_zval_type_name(const zval *arg) +ZEND_ATTRIBUTE_PURE ZEND_API const char *zend_zval_type_name(const zval *arg) { ZVAL_DEREF(arg); @@ -3762,7 +3762,7 @@ ZEND_API zend_result zend_disable_class(const char *class_name, size_t class_nam } /* }}} */ -static zend_always_inline zend_class_entry *get_scope(zend_execute_data *frame) +ZEND_ATTRIBUTE_PURE static zend_always_inline zend_class_entry *get_scope(const zend_execute_data *frame) { return frame && frame->func ? frame->func->common.scope : NULL; } diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 02ec1b18a6b69..6ef41a2cb5dd2 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -366,8 +366,8 @@ ZEND_API zend_result zend_parse_parameters_ex(int flags, uint32_t num_args, cons /* NOTE: This must have at least one value in __VA_ARGS__ for the expression to be valid */ #define zend_parse_parameters_throw(num_args, ...) \ zend_parse_parameters(num_args, __VA_ARGS__) -ZEND_API const char *zend_zval_type_name(const zval *arg); -ZEND_API const char *zend_zval_value_name(const zval *arg); +ZEND_ATTRIBUTE_PURE ZEND_API const char *zend_zval_type_name(const zval *arg); +ZEND_ATTRIBUTE_PURE ZEND_API const char *zend_zval_value_name(const zval *arg); ZEND_API zend_string *zend_zval_get_legacy_type(const zval *arg); ZEND_API zend_result zend_parse_method_parameters(uint32_t num_args, zval *this_ptr, const char *type_spec, ...); @@ -520,7 +520,7 @@ ZEND_API zval *zend_read_property(zend_class_entry *scope, zend_object *object, ZEND_API zval *zend_read_static_property_ex(zend_class_entry *scope, zend_string *name, bool silent); ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, size_t name_length, bool silent); -ZEND_API const char *zend_get_type_by_const(int type); +ZEND_ATTRIBUTE_CONST ZEND_API const char *zend_get_type_by_const(int type); #define ZEND_THIS (&EX(This)) diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index e7b5be8751058..42eaca6081f72 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -443,12 +443,12 @@ ZEND_API void ZEND_FASTCALL zend_free_extra_named_params(zend_array *extra_named /* services */ ZEND_API const char *get_active_class_name(const char **space); -ZEND_API const char *get_active_function_name(void); -ZEND_API const char *get_active_function_arg_name(uint32_t arg_num); -ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t arg_num); -ZEND_API zend_function *zend_active_function_ex(zend_execute_data *execute_data); +ZEND_ATTRIBUTE_PURE ZEND_API const char *get_active_function_name(void); +ZEND_ATTRIBUTE_PURE ZEND_API const char *get_active_function_arg_name(uint32_t arg_num); +ZEND_ATTRIBUTE_PURE ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t arg_num); +ZEND_ATTRIBUTE_PURE ZEND_API zend_function *zend_active_function_ex(const zend_execute_data *execute_data); -static zend_always_inline zend_function *zend_active_function(void) +ZEND_ATTRIBUTE_PURE static zend_always_inline zend_function *zend_active_function(void) { zend_function *func = EG(current_execute_data)->func; if (ZEND_USER_CODE(func->type)) { @@ -464,7 +464,7 @@ ZEND_ATTRIBUTE_PURE ZEND_API const char *zend_get_executed_filename(void); ZEND_ATTRIBUTE_PURE ZEND_API zend_string *zend_get_executed_filename_ex(void); ZEND_ATTRIBUTE_PURE ZEND_API uint32_t zend_get_executed_lineno(void); ZEND_ATTRIBUTE_PURE ZEND_API zend_class_entry *zend_get_executed_scope(void); -ZEND_API bool zend_is_executing(void); +ZEND_ATTRIBUTE_PURE ZEND_API bool zend_is_executing(void); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num); ZEND_API void zend_set_timeout(zend_long seconds, bool reset_signals); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 86e5f43b944a1..426d8214186a1 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -567,7 +567,7 @@ ZEND_API const char *get_active_class_name(const char **space) /* {{{ */ } /* }}} */ -ZEND_API const char *get_active_function_name(void) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API const char *get_active_function_name(void) /* {{{ */ { zend_function *func; @@ -597,7 +597,7 @@ ZEND_API const char *get_active_function_name(void) /* {{{ */ } /* }}} */ -ZEND_API zend_function *zend_active_function_ex(zend_execute_data *execute_data) +ZEND_ATTRIBUTE_PURE ZEND_API zend_function *zend_active_function_ex(const zend_execute_data *execute_data) { zend_function *func = EX(func); @@ -630,7 +630,7 @@ ZEND_API zend_string *get_function_or_method_name(const zend_function *func) /* } /* }}} */ -ZEND_API const char *get_active_function_arg_name(uint32_t arg_num) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API const char *get_active_function_arg_name(uint32_t arg_num) /* {{{ */ { if (!zend_is_executing()) { return NULL; @@ -642,7 +642,7 @@ ZEND_API const char *get_active_function_arg_name(uint32_t arg_num) /* {{{ */ } /* }}} */ -ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t arg_num) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t arg_num) /* {{{ */ { if (!func || arg_num == 0 || func->common.num_args < arg_num) { return NULL; @@ -726,7 +726,7 @@ ZEND_ATTRIBUTE_PURE ZEND_API zend_class_entry *zend_get_executed_scope(void) /* } /* }}} */ -ZEND_API bool zend_is_executing(void) /* {{{ */ +ZEND_ATTRIBUTE_PURE ZEND_API bool zend_is_executing(void) /* {{{ */ { return EG(current_execute_data) != 0; }