2626#include "zend_types.h"
2727#include "zend_vm.h"
2828#include "zend_observer.h"
29+ #include "zend_attributes.h"
2930
3031typedef struct _zend_partial {
3132 /* Common zend_closure fields */
@@ -98,6 +99,23 @@ static zend_always_inline uint32_t zend_partial_signature_size(zend_partial *par
9899 return count * sizeof (zend_arg_info );
99100}
100101
102+ static void zend_partial_signature_copy_attributes (zend_array * dest , zend_array * src , uint32_t dest_offset , uint32_t src_offset ) {
103+ zend_attribute * attr ;
104+ ZEND_HASH_PACKED_FOREACH_PTR (src , attr ) {
105+ if (attr -> offset == src_offset ) {
106+ if (src_offset != 0 ) {
107+ zend_attribute * copy = emalloc (sizeof (zend_attribute ));
108+ memcpy (copy , attr , sizeof (zend_attribute ));
109+ copy -> offset = dest_offset ;
110+ attr = copy ;
111+ }
112+ zend_hash_next_index_insert_ptr (dest , attr );
113+ } else if (attr -> offset > src_offset ) {
114+ break ;
115+ }
116+ } ZEND_HASH_FOREACH_END ();
117+ }
118+
101119static zend_always_inline void zend_partial_signature_create (zend_partial * partial ) {
102120 zend_arg_info * signature = emalloc (zend_partial_signature_size (partial )), * info = signature ;
103121
@@ -113,6 +131,16 @@ static zend_always_inline void zend_partial_signature_create(zend_partial *parti
113131 memset (partial -> trampoline .op_array .arg_flags , 0 ,
114132 sizeof (partial -> trampoline .op_array .arg_flags ));
115133
134+ zend_array * attributes ;
135+ if (zend_hash_num_elements (partial -> func .common .attributes )) {
136+ attributes = emalloc (sizeof (zend_array ));
137+ zend_hash_init (attributes , 0 , NULL , NULL , false);
138+ zend_partial_signature_copy_attributes (attributes , partial -> func .common .attributes , 0 , 0 );
139+ partial -> trampoline .common .attributes = attributes ;
140+ } else {
141+ attributes = NULL ;
142+ }
143+
116144 while (offset < limit ) {
117145 zval * arg = & partial -> argv [offset ];
118146
@@ -132,6 +160,9 @@ static zend_always_inline void zend_partial_signature_create(zend_partial *parti
132160 byref = true;
133161 }
134162 }
163+ if (UNEXPECTED (attributes )) {
164+ zend_partial_signature_copy_attributes (attributes , partial -> func .common .attributes , num , offset + 1 );
165+ }
135166 info ++ ;
136167 } else {
137168 ZEND_ASSERT (ZEND_PARTIAL_FUNC_FLAG (& partial -> func , ZEND_ACC_VARIADIC ));
@@ -154,6 +185,9 @@ static zend_always_inline void zend_partial_signature_create(zend_partial *parti
154185 byref = true;
155186 }
156187 }
188+ if (UNEXPECTED (attributes )) {
189+ zend_partial_signature_copy_attributes (attributes , partial -> func .common .attributes , num , partial -> func .common .num_args + 1 );
190+ }
157191 info ++ ;
158192 }
159193 } else if (Z_ISUNDEF_P (arg )) {
@@ -188,6 +222,9 @@ static zend_always_inline void zend_partial_signature_create(zend_partial *parti
188222 }
189223 byref = true;
190224 }
225+ if (UNEXPECTED (attributes )) {
226+ zend_partial_signature_copy_attributes (attributes , partial -> func .common .attributes , num + 1 , partial -> func .common .num_args + 1 );
227+ }
191228 info ++ ;
192229 }
193230
@@ -267,7 +304,7 @@ static zend_always_inline void zend_partial_trampoline_create(zend_partial *part
267304 static const void * dummy = (void * )(intptr_t )2 ;
268305
269306 const uint32_t keep_flags =
270- ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_HAS_RETURN_TYPE | ZEND_ACC_STRICT_TYPES ;
307+ ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_HAS_RETURN_TYPE | ZEND_ACC_STRICT_TYPES | ZEND_ACC_NODISCARD | ZEND_ACC_DEPRECATED ;
271308
272309 trampoline -> common = partial -> func .common ;
273310 trampoline -> type = ZEND_USER_FUNCTION ;
@@ -500,6 +537,19 @@ static void zend_partial_free(zend_object *object) {
500537 destroy_op_array (& partial -> func .op_array );
501538 }
502539
540+ /* When partial->func.common.attributes has elements,
541+ * partial->trampoline.common.attributes is a copy that must be destroyed */
542+ if (zend_hash_num_elements (partial -> func .common .attributes )) {
543+ zend_attribute * attr ;
544+ ZEND_HASH_PACKED_FOREACH_PTR (partial -> trampoline .common .attributes , attr ) {
545+ if (attr -> offset > 0 ) {
546+ efree (attr );
547+ }
548+ } ZEND_HASH_FOREACH_END ();
549+ zend_hash_destroy (partial -> trampoline .common .attributes );
550+ efree (partial -> trampoline .common .attributes );
551+ }
552+
503553 if (Z_TYPE (partial -> This ) == IS_OBJECT ) {
504554 zval_ptr_dtor (& partial -> This );
505555 }
0 commit comments