2020*/
2121
2222#include "zend.h"
23+ #include "zend_compile.h"
2324#include "zend_execute.h"
2425#include "zend_API.h"
2526#include "zend_hash.h"
@@ -2927,6 +2928,80 @@ static zend_always_inline void zend_normalize_internal_type(zend_type *type) {
29272928 } ZEND_TYPE_FOREACH_END ();
29282929}
29292930
2931+ static void zend_convert_internal_arg_info_type (zend_type * type , bool persistent )
2932+ {
2933+ if (ZEND_TYPE_HAS_LITERAL_NAME (* type )) {
2934+ // gen_stubs.php does not support codegen for compound types. As a
2935+ // temporary workaround, we support union types by splitting
2936+ // the type name on `|` characters if necessary.
2937+ const char * class_name = ZEND_TYPE_LITERAL_NAME (* type );
2938+ type -> type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT ;
2939+
2940+ size_t num_types = 1 ;
2941+ const char * p = class_name ;
2942+ while ((p = strchr (p , '|' ))) {
2943+ num_types ++ ;
2944+ p ++ ;
2945+ }
2946+
2947+ if (num_types == 1 ) {
2948+ /* Simple class type */
2949+ zend_string * str = zend_string_init_interned (class_name , strlen (class_name ), persistent );
2950+ zend_alloc_ce_cache (str );
2951+ ZEND_TYPE_SET_PTR (* type , str );
2952+ type -> type_mask |= _ZEND_TYPE_NAME_BIT ;
2953+ } else {
2954+ /* Union type */
2955+ zend_type_list * list = pemalloc (ZEND_TYPE_LIST_SIZE (num_types ), persistent );
2956+ list -> num_types = num_types ;
2957+ ZEND_TYPE_SET_LIST (* type , list );
2958+ ZEND_TYPE_FULL_MASK (* type ) |= _ZEND_TYPE_UNION_BIT ;
2959+
2960+ const char * start = class_name ;
2961+ uint32_t j = 0 ;
2962+ while (true) {
2963+ const char * end = strchr (start , '|' );
2964+ zend_string * str = zend_string_init_interned (start , end ? end - start : strlen (start ), persistent );
2965+ zend_alloc_ce_cache (str );
2966+ list -> types [j ] = (zend_type ) ZEND_TYPE_INIT_CLASS (str , 0 , 0 );
2967+ if (!end ) {
2968+ break ;
2969+ }
2970+ start = end + 1 ;
2971+ j ++ ;
2972+ }
2973+ }
2974+ }
2975+ if (ZEND_TYPE_IS_ITERABLE_FALLBACK (* type )) {
2976+ /* Warning generated an extension load warning which is emitted for every test
2977+ zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable,"
2978+ " regenerate the argument info via the php-src gen_stub build script");
2979+ */
2980+ zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK (
2981+ ZSTR_KNOWN (ZEND_STR_TRAVERSABLE ),
2982+ (type -> type_mask | MAY_BE_ARRAY )
2983+ );
2984+ * type = legacy_iterable ;
2985+ }
2986+ }
2987+
2988+ ZEND_API void zend_convert_internal_arg_info (zend_arg_info * new_arg_info , const zend_internal_arg_info * arg_info , bool is_return_info , bool persistent )
2989+ {
2990+ if (!is_return_info ) {
2991+ new_arg_info -> name = zend_string_init_interned (arg_info -> name , strlen (arg_info -> name ), persistent );
2992+ if (arg_info -> default_value ) {
2993+ new_arg_info -> default_value = zend_string_init_interned (arg_info -> default_value , strlen (arg_info -> default_value ), persistent );
2994+ } else {
2995+ new_arg_info -> default_value = NULL ;
2996+ }
2997+ } else {
2998+ new_arg_info -> name = NULL ;
2999+ new_arg_info -> default_value = NULL ;
3000+ }
3001+ new_arg_info -> type = arg_info -> type ;
3002+ zend_convert_internal_arg_info_type (& new_arg_info -> type , persistent );
3003+ }
3004+
29303005/* registers all functions in *library_functions in the function hash */
29313006ZEND_API zend_result zend_register_functions (zend_class_entry * scope , const zend_function_entry * functions , HashTable * function_table , int type ) /* {{{ */
29323007{
@@ -2938,6 +3013,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
29383013 int error_type ;
29393014 zend_string * lowercase_name ;
29403015 size_t fname_len ;
3016+ const zend_internal_arg_info * internal_arg_info ;
29413017
29423018 if (type == MODULE_PERSISTENT ) {
29433019 error_type = E_CORE_WARNING ;
@@ -2994,7 +3070,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
29943070
29953071 if (ptr -> arg_info ) {
29963072 zend_internal_function_info * info = (zend_internal_function_info * )ptr -> arg_info ;
2997- internal_function -> arg_info = ( zend_internal_arg_info * ) ptr -> arg_info + 1 ;
3073+ internal_arg_info = ptr -> arg_info + 1 ;
29983074 internal_function -> num_args = ptr -> num_args ;
29993075 /* Currently you cannot denote that the function can accept less arguments than num_args */
30003076 if (info -> required_num_args == (uintptr_t )-1 ) {
@@ -3024,7 +3100,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
30243100 zend_error (E_CORE_WARNING , "Missing arginfo for %s%s%s()" ,
30253101 scope ? ZSTR_VAL (scope -> name ) : "" , scope ? "::" : "" , ptr -> fname );
30263102
3027- internal_function -> arg_info = NULL ;
3103+ internal_arg_info = NULL ;
30283104 internal_function -> num_args = 0 ;
30293105 internal_function -> required_num_args = 0 ;
30303106 }
@@ -3035,13 +3111,11 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
30353111 !(internal_function -> fn_flags & ZEND_ACC_HAS_RETURN_TYPE )) {
30363112 zend_error (E_CORE_WARNING , "%s::__toString() implemented without string return type" ,
30373113 ZSTR_VAL (scope -> name ));
3038- internal_function -> arg_info = (zend_internal_arg_info * ) arg_info_toString + 1 ;
3114+ internal_arg_info = (zend_internal_arg_info * ) arg_info_toString + 1 ;
30393115 internal_function -> fn_flags |= ZEND_ACC_HAS_RETURN_TYPE ;
30403116 internal_function -> num_args = internal_function -> required_num_args = 0 ;
30413117 }
30423118
3043-
3044- zend_set_function_arg_flags ((zend_function * )internal_function );
30453119 if (ptr -> flags & ZEND_ACC_ABSTRACT ) {
30463120 if (scope ) {
30473121 /* This is a class that must be abstract itself. Here we set the check info. */
@@ -3106,17 +3180,17 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
31063180 }
31073181
31083182 /* If types of arguments have to be checked */
3109- if (reg_function -> arg_info && num_args ) {
3183+ if (internal_arg_info && num_args ) {
31103184 uint32_t i ;
31113185 for (i = 0 ; i < num_args ; i ++ ) {
3112- zend_internal_arg_info * arg_info = & reg_function -> arg_info [i ];
3186+ const zend_internal_arg_info * arg_info = & internal_arg_info [i ];
31133187 ZEND_ASSERT (arg_info -> name && "Parameter must have a name" );
31143188 if (ZEND_TYPE_IS_SET (arg_info -> type )) {
31153189 reg_function -> fn_flags |= ZEND_ACC_HAS_TYPE_HINTS ;
31163190 }
31173191#if ZEND_DEBUG
31183192 for (uint32_t j = 0 ; j < i ; j ++ ) {
3119- if (!strcmp (arg_info -> name , reg_function -> arg_info [j ].name )) {
3193+ if (!strcmp (arg_info -> name , internal_arg_info [j ].name )) {
31203194 zend_error_noreturn (E_CORE_ERROR ,
31213195 "Duplicate parameter name $%s for function %s%s%s()" , arg_info -> name ,
31223196 scope ? ZSTR_VAL (scope -> name ) : "" , scope ? "::" : "" , ptr -> fname );
@@ -3126,78 +3200,24 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
31263200 }
31273201 }
31283202
3129- /* Rebuild arginfos if parameter/property types and/or a return type are used */
3130- if (reg_function -> arg_info &&
3131- (reg_function -> fn_flags & (ZEND_ACC_HAS_RETURN_TYPE |ZEND_ACC_HAS_TYPE_HINTS ))) {
3132- /* convert "const char*" class type names into "zend_string*" */
3203+ /* Convert zend_internal_arg_info to zend_arg_info */
3204+ if (internal_arg_info ) {
31333205 uint32_t i ;
3134- zend_internal_arg_info * arg_info = reg_function -> arg_info - 1 ;
3135- zend_internal_arg_info * new_arg_info ;
3206+ const zend_internal_arg_info * arg_info = internal_arg_info - 1 ;
3207+ zend_arg_info * new_arg_info ;
31363208
31373209 /* Treat return type as an extra argument */
31383210 num_args ++ ;
3139- new_arg_info = malloc (sizeof (zend_internal_arg_info ) * num_args );
3140- memcpy (new_arg_info , arg_info , sizeof (zend_internal_arg_info ) * num_args );
3211+ new_arg_info = malloc (sizeof (zend_arg_info ) * num_args );
31413212 reg_function -> arg_info = new_arg_info + 1 ;
31423213 for (i = 0 ; i < num_args ; i ++ ) {
3143- if (ZEND_TYPE_HAS_LITERAL_NAME (new_arg_info [i ].type )) {
3144- // gen_stubs.php does not support codegen for DNF types in arg infos.
3145- // As a temporary workaround, we split the type name on `|` characters,
3146- // converting it to an union type if necessary.
3147- const char * class_name = ZEND_TYPE_LITERAL_NAME (new_arg_info [i ].type );
3148- new_arg_info [i ].type .type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT ;
3149-
3150- size_t num_types = 1 ;
3151- const char * p = class_name ;
3152- while ((p = strchr (p , '|' ))) {
3153- num_types ++ ;
3154- p ++ ;
3155- }
3156-
3157- if (num_types == 1 ) {
3158- /* Simple class type */
3159- zend_string * str = zend_string_init_interned (class_name , strlen (class_name ), 1 );
3160- zend_alloc_ce_cache (str );
3161- ZEND_TYPE_SET_PTR (new_arg_info [i ].type , str );
3162- new_arg_info [i ].type .type_mask |= _ZEND_TYPE_NAME_BIT ;
3163- } else {
3164- /* Union type */
3165- zend_type_list * list = malloc (ZEND_TYPE_LIST_SIZE (num_types ));
3166- list -> num_types = num_types ;
3167- ZEND_TYPE_SET_LIST (new_arg_info [i ].type , list );
3168- ZEND_TYPE_FULL_MASK (new_arg_info [i ].type ) |= _ZEND_TYPE_UNION_BIT ;
3169-
3170- const char * start = class_name ;
3171- uint32_t j = 0 ;
3172- while (true) {
3173- const char * end = strchr (start , '|' );
3174- zend_string * str = zend_string_init_interned (start , end ? end - start : strlen (start ), 1 );
3175- zend_alloc_ce_cache (str );
3176- list -> types [j ] = (zend_type ) ZEND_TYPE_INIT_CLASS (str , 0 , 0 );
3177- if (!end ) {
3178- break ;
3179- }
3180- start = end + 1 ;
3181- j ++ ;
3182- }
3183- }
3184- }
3185- if (ZEND_TYPE_IS_ITERABLE_FALLBACK (new_arg_info [i ].type )) {
3186- /* Warning generated an extension load warning which is emitted for every test
3187- zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable,"
3188- " regenerate the argument info via the php-src gen_stub build script");
3189- */
3190- zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK (
3191- ZSTR_KNOWN (ZEND_STR_TRAVERSABLE ),
3192- (new_arg_info [i ].type .type_mask | MAY_BE_ARRAY )
3193- );
3194- new_arg_info [i ].type = legacy_iterable ;
3195- }
3196-
3197- zend_normalize_internal_type (& new_arg_info [i ].type );
3214+ zend_convert_internal_arg_info (& new_arg_info [i ], & arg_info [i ],
3215+ i == 0 , true);
31983216 }
31993217 }
32003218
3219+ zend_set_function_arg_flags ((zend_function * )reg_function );
3220+
32013221 if (scope ) {
32023222 zend_check_magic_method_implementation (
32033223 scope , (zend_function * )reg_function , lowercase_name , E_CORE_ERROR );
@@ -5242,48 +5262,43 @@ static zend_string *try_parse_string(const char *str, size_t len, char quote) {
52425262}
52435263
52445264ZEND_API zend_result zend_get_default_from_internal_arg_info (
5245- zval * default_value_zval , const zend_internal_arg_info * arg_info )
5265+ zval * default_value_zval , const zend_arg_info * arg_info )
52465266{
5247- const char * default_value = arg_info -> default_value ;
5267+ const zend_string * default_value = arg_info -> default_value ;
52485268 if (!default_value ) {
52495269 return FAILURE ;
52505270 }
52515271
52525272 /* Avoid going through the full AST machinery for some simple and common cases. */
5253- size_t default_value_len = strlen (default_value );
52545273 zend_ulong lval ;
5255- if (default_value_len == sizeof ("null" )- 1
5256- && !memcmp (default_value , "null" , sizeof ("null" )- 1 )) {
5274+ if (zend_string_equals_literal (default_value , "null" )) {
52575275 ZVAL_NULL (default_value_zval );
52585276 return SUCCESS ;
5259- } else if (default_value_len == sizeof ("true" )- 1
5260- && !memcmp (default_value , "true" , sizeof ("true" )- 1 )) {
5277+ } else if (zend_string_equals_literal (default_value , "true" )) {
52615278 ZVAL_TRUE (default_value_zval );
52625279 return SUCCESS ;
5263- } else if (default_value_len == sizeof ("false" )- 1
5264- && !memcmp (default_value , "false" , sizeof ("false" )- 1 )) {
5280+ } else if (zend_string_equals_literal (default_value , "false" )) {
52655281 ZVAL_FALSE (default_value_zval );
52665282 return SUCCESS ;
5267- } else if (default_value_len >= 2
5268- && (default_value [0 ] == '\'' || default_value [0 ] == '"' )
5269- && default_value [ default_value_len - 1 ] == default_value [0 ]) {
5283+ } else if (ZSTR_LEN ( default_value ) >= 2
5284+ && (ZSTR_VAL ( default_value ) [0 ] == '\'' || ZSTR_VAL ( default_value ) [0 ] == '"' )
5285+ && ZSTR_VAL ( default_value )[ ZSTR_LEN ( default_value ) - 1 ] == ZSTR_VAL ( default_value ) [0 ]) {
52705286 zend_string * str = try_parse_string (
5271- default_value + 1 , default_value_len - 2 , default_value [0 ]);
5287+ ZSTR_VAL ( default_value ) + 1 , ZSTR_LEN ( default_value ) - 2 , ZSTR_VAL ( default_value ) [0 ]);
52725288 if (str ) {
52735289 ZVAL_STR (default_value_zval , str );
52745290 return SUCCESS ;
52755291 }
5276- } else if (default_value_len == sizeof ("[]" )- 1
5277- && !memcmp (default_value , "[]" , sizeof ("[]" )- 1 )) {
5292+ } else if (zend_string_equals_literal (default_value , "[]" )) {
52785293 ZVAL_EMPTY_ARRAY (default_value_zval );
52795294 return SUCCESS ;
5280- } else if (ZEND_HANDLE_NUMERIC_STR (default_value , default_value_len , lval )) {
5295+ } else if (ZEND_HANDLE_NUMERIC (default_value , lval )) {
52815296 ZVAL_LONG (default_value_zval , lval );
52825297 return SUCCESS ;
52835298 }
52845299
52855300#if 0
5286- fprintf (stderr , "Evaluating %s via AST\n" , default_value );
5301+ fprintf (stderr , "Evaluating %s via AST\n" , ZSTR_VAL ( default_value ) );
52875302#endif
5288- return get_default_via_ast (default_value_zval , default_value );
5303+ return get_default_via_ast (default_value_zval , ZSTR_VAL ( default_value ) );
52895304}
0 commit comments