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"
@@ -2933,6 +2934,80 @@ static zend_always_inline void zend_normalize_internal_type(zend_type *type) {
29332934 } ZEND_TYPE_FOREACH_END ();
29342935}
29352936
2937+ void zend_convert_internal_arg_info_type (zend_type * type )
2938+ {
2939+ if (ZEND_TYPE_HAS_LITERAL_NAME (* type )) {
2940+ // gen_stubs.php does not support codegen for DNF types in arg infos.
2941+ // As a temporary workaround, we split the type name on `|` characters,
2942+ // converting it to an union type if necessary.
2943+ const char * class_name = ZEND_TYPE_LITERAL_NAME (* type );
2944+ type -> type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT ;
2945+
2946+ size_t num_types = 1 ;
2947+ const char * p = class_name ;
2948+ while ((p = strchr (p , '|' ))) {
2949+ num_types ++ ;
2950+ p ++ ;
2951+ }
2952+
2953+ if (num_types == 1 ) {
2954+ /* Simple class type */
2955+ zend_string * str = zend_string_init_interned (class_name , strlen (class_name ), 1 );
2956+ zend_alloc_ce_cache (str );
2957+ ZEND_TYPE_SET_PTR (* type , str );
2958+ type -> type_mask |= _ZEND_TYPE_NAME_BIT ;
2959+ } else {
2960+ /* Union type */
2961+ zend_type_list * list = malloc (ZEND_TYPE_LIST_SIZE (num_types ));
2962+ list -> num_types = num_types ;
2963+ ZEND_TYPE_SET_LIST (* type , list );
2964+ ZEND_TYPE_FULL_MASK (* type ) |= _ZEND_TYPE_UNION_BIT ;
2965+
2966+ const char * start = class_name ;
2967+ uint32_t j = 0 ;
2968+ while (true) {
2969+ const char * end = strchr (start , '|' );
2970+ zend_string * str = zend_string_init_interned (start , end ? end - start : strlen (start ), 1 );
2971+ zend_alloc_ce_cache (str );
2972+ list -> types [j ] = (zend_type ) ZEND_TYPE_INIT_CLASS (str , 0 , 0 );
2973+ if (!end ) {
2974+ break ;
2975+ }
2976+ start = end + 1 ;
2977+ j ++ ;
2978+ }
2979+ }
2980+ }
2981+ if (ZEND_TYPE_IS_ITERABLE_FALLBACK (* type )) {
2982+ /* Warning generated an extension load warning which is emitted for every test
2983+ zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable,"
2984+ " regenerate the argument info via the php-src gen_stub build script");
2985+ */
2986+ zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK (
2987+ ZSTR_KNOWN (ZEND_STR_TRAVERSABLE ),
2988+ (type -> type_mask | MAY_BE_ARRAY )
2989+ );
2990+ * type = legacy_iterable ;
2991+ }
2992+ }
2993+
2994+ void zend_convert_internal_arg_info (zend_arg_info * new_arg_info , const zend_internal_arg_info * arg_info , bool is_return_info )
2995+ {
2996+ if (!is_return_info ) {
2997+ new_arg_info -> name = zend_string_init_interned (arg_info -> name , strlen (arg_info -> name ), 1 );
2998+ if (arg_info -> default_value ) {
2999+ new_arg_info -> default_value = zend_string_init_interned (arg_info -> default_value , strlen (arg_info -> default_value ), 1 );
3000+ } else {
3001+ new_arg_info -> default_value = NULL ;
3002+ }
3003+ } else {
3004+ new_arg_info -> name = NULL ;
3005+ new_arg_info -> default_value = NULL ;
3006+ }
3007+ new_arg_info -> type = arg_info -> type ;
3008+ zend_convert_internal_arg_info_type (& new_arg_info -> type );
3009+ }
3010+
29363011/* registers all functions in *library_functions in the function hash */
29373012ZEND_API zend_result zend_register_functions (zend_class_entry * scope , const zend_function_entry * functions , HashTable * function_table , int type ) /* {{{ */
29383013{
@@ -2944,6 +3019,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
29443019 int error_type ;
29453020 zend_string * lowercase_name ;
29463021 size_t fname_len ;
3022+ const zend_internal_arg_info * internal_arg_info ;
29473023
29483024 if (type == MODULE_PERSISTENT ) {
29493025 error_type = E_CORE_WARNING ;
@@ -3000,7 +3076,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
30003076
30013077 if (ptr -> arg_info ) {
30023078 zend_internal_function_info * info = (zend_internal_function_info * )ptr -> arg_info ;
3003- internal_function -> arg_info = ( zend_internal_arg_info * ) ptr -> arg_info + 1 ;
3079+ internal_arg_info = ptr -> arg_info + 1 ;
30043080 internal_function -> num_args = ptr -> num_args ;
30053081 /* Currently you cannot denote that the function can accept less arguments than num_args */
30063082 if (info -> required_num_args == (uintptr_t )-1 ) {
@@ -3030,7 +3106,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
30303106 zend_error (E_CORE_WARNING , "Missing arginfo for %s%s%s()" ,
30313107 scope ? ZSTR_VAL (scope -> name ) : "" , scope ? "::" : "" , ptr -> fname );
30323108
3033- internal_function -> arg_info = NULL ;
3109+ internal_arg_info = NULL ;
30343110 internal_function -> num_args = 0 ;
30353111 internal_function -> required_num_args = 0 ;
30363112 }
@@ -3041,13 +3117,11 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
30413117 !(internal_function -> fn_flags & ZEND_ACC_HAS_RETURN_TYPE )) {
30423118 zend_error (E_CORE_WARNING , "%s::__toString() implemented without string return type" ,
30433119 ZSTR_VAL (scope -> name ));
3044- internal_function -> arg_info = (zend_internal_arg_info * ) arg_info_toString + 1 ;
3120+ internal_arg_info = (zend_internal_arg_info * ) arg_info_toString + 1 ;
30453121 internal_function -> fn_flags |= ZEND_ACC_HAS_RETURN_TYPE ;
30463122 internal_function -> num_args = internal_function -> required_num_args = 0 ;
30473123 }
30483124
3049-
3050- zend_set_function_arg_flags ((zend_function * )internal_function );
30513125 if (ptr -> flags & ZEND_ACC_ABSTRACT ) {
30523126 if (scope ) {
30533127 /* This is a class that must be abstract itself. Here we set the check info. */
@@ -3112,17 +3186,17 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
31123186 }
31133187
31143188 /* If types of arguments have to be checked */
3115- if (reg_function -> arg_info && num_args ) {
3189+ if (internal_arg_info && num_args ) {
31163190 uint32_t i ;
31173191 for (i = 0 ; i < num_args ; i ++ ) {
3118- zend_internal_arg_info * arg_info = & reg_function -> arg_info [i ];
3192+ const zend_internal_arg_info * arg_info = & internal_arg_info [i ];
31193193 ZEND_ASSERT (arg_info -> name && "Parameter must have a name" );
31203194 if (ZEND_TYPE_IS_SET (arg_info -> type )) {
31213195 reg_function -> fn_flags |= ZEND_ACC_HAS_TYPE_HINTS ;
31223196 }
31233197#if ZEND_DEBUG
31243198 for (uint32_t j = 0 ; j < i ; j ++ ) {
3125- if (!strcmp (arg_info -> name , reg_function -> arg_info [j ].name )) {
3199+ if (!strcmp (arg_info -> name , internal_arg_info [j ].name )) {
31263200 zend_error_noreturn (E_CORE_ERROR ,
31273201 "Duplicate parameter name $%s for function %s%s%s()" , arg_info -> name ,
31283202 scope ? ZSTR_VAL (scope -> name ) : "" , scope ? "::" : "" , ptr -> fname );
@@ -3132,78 +3206,24 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
31323206 }
31333207 }
31343208
3135- /* Rebuild arginfos if parameter/property types and/or a return type are used */
3136- if (reg_function -> arg_info &&
3137- (reg_function -> fn_flags & (ZEND_ACC_HAS_RETURN_TYPE |ZEND_ACC_HAS_TYPE_HINTS ))) {
3138- /* convert "const char*" class type names into "zend_string*" */
3209+ /* Convert zend_internal_arg_info to zend_arg_info */
3210+ if (internal_arg_info ) {
31393211 uint32_t i ;
3140- zend_internal_arg_info * arg_info = reg_function -> arg_info - 1 ;
3141- zend_internal_arg_info * new_arg_info ;
3212+ const zend_internal_arg_info * arg_info = internal_arg_info - 1 ;
3213+ zend_arg_info * new_arg_info ;
31423214
31433215 /* Treat return type as an extra argument */
31443216 num_args ++ ;
3145- new_arg_info = malloc (sizeof (zend_internal_arg_info ) * num_args );
3146- memcpy (new_arg_info , arg_info , sizeof (zend_internal_arg_info ) * num_args );
3217+ new_arg_info = malloc (sizeof (zend_arg_info ) * num_args );
3218+ memcpy (new_arg_info , arg_info , sizeof (zend_arg_info ) * num_args );
31473219 reg_function -> arg_info = new_arg_info + 1 ;
31483220 for (i = 0 ; i < num_args ; i ++ ) {
3149- if (ZEND_TYPE_HAS_LITERAL_NAME (new_arg_info [i ].type )) {
3150- // gen_stubs.php does not support codegen for DNF types in arg infos.
3151- // As a temporary workaround, we split the type name on `|` characters,
3152- // converting it to an union type if necessary.
3153- const char * class_name = ZEND_TYPE_LITERAL_NAME (new_arg_info [i ].type );
3154- new_arg_info [i ].type .type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT ;
3155-
3156- size_t num_types = 1 ;
3157- const char * p = class_name ;
3158- while ((p = strchr (p , '|' ))) {
3159- num_types ++ ;
3160- p ++ ;
3161- }
3162-
3163- if (num_types == 1 ) {
3164- /* Simple class type */
3165- zend_string * str = zend_string_init_interned (class_name , strlen (class_name ), 1 );
3166- zend_alloc_ce_cache (str );
3167- ZEND_TYPE_SET_PTR (new_arg_info [i ].type , str );
3168- new_arg_info [i ].type .type_mask |= _ZEND_TYPE_NAME_BIT ;
3169- } else {
3170- /* Union type */
3171- zend_type_list * list = malloc (ZEND_TYPE_LIST_SIZE (num_types ));
3172- list -> num_types = num_types ;
3173- ZEND_TYPE_SET_LIST (new_arg_info [i ].type , list );
3174- ZEND_TYPE_FULL_MASK (new_arg_info [i ].type ) |= _ZEND_TYPE_UNION_BIT ;
3175-
3176- const char * start = class_name ;
3177- uint32_t j = 0 ;
3178- while (true) {
3179- const char * end = strchr (start , '|' );
3180- zend_string * str = zend_string_init_interned (start , end ? end - start : strlen (start ), 1 );
3181- zend_alloc_ce_cache (str );
3182- list -> types [j ] = (zend_type ) ZEND_TYPE_INIT_CLASS (str , 0 , 0 );
3183- if (!end ) {
3184- break ;
3185- }
3186- start = end + 1 ;
3187- j ++ ;
3188- }
3189- }
3190- }
3191- if (ZEND_TYPE_IS_ITERABLE_FALLBACK (new_arg_info [i ].type )) {
3192- /* Warning generated an extension load warning which is emitted for every test
3193- zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable,"
3194- " regenerate the argument info via the php-src gen_stub build script");
3195- */
3196- zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK (
3197- ZSTR_KNOWN (ZEND_STR_TRAVERSABLE ),
3198- (new_arg_info [i ].type .type_mask | MAY_BE_ARRAY )
3199- );
3200- new_arg_info [i ].type = legacy_iterable ;
3201- }
3202-
3203- zend_normalize_internal_type (& new_arg_info [i ].type );
3221+ zend_convert_internal_arg_info (& new_arg_info [i ], & arg_info [i ], i == 0 );
32043222 }
32053223 }
32063224
3225+ zend_set_function_arg_flags ((zend_function * )reg_function );
3226+
32073227 if (scope ) {
32083228 zend_check_magic_method_implementation (
32093229 scope , (zend_function * )reg_function , lowercase_name , E_CORE_ERROR );
@@ -5371,49 +5391,44 @@ static zend_string *try_parse_string(const char *str, size_t len, char quote) {
53715391 return zend_string_init (str , len , 0 );
53725392}
53735393
5374- ZEND_API zend_result zend_get_default_from_internal_arg_info (
5375- zval * default_value_zval , zend_internal_arg_info * arg_info )
5394+ ZEND_API zend_result zend_get_default_from_arg_info (
5395+ zval * default_value_zval , zend_arg_info * arg_info )
53765396{
5377- const char * default_value = arg_info -> default_value ;
5397+ zend_string * default_value = arg_info -> default_value ;
53785398 if (!default_value ) {
53795399 return FAILURE ;
53805400 }
53815401
53825402 /* Avoid going through the full AST machinery for some simple and common cases. */
5383- size_t default_value_len = strlen (default_value );
53845403 zend_ulong lval ;
5385- if (default_value_len == sizeof ("null" )- 1
5386- && !memcmp (default_value , "null" , sizeof ("null" )- 1 )) {
5404+ if (zend_string_equals_cstr (default_value , "null" , strlen ("null" ))) {
53875405 ZVAL_NULL (default_value_zval );
53885406 return SUCCESS ;
5389- } else if (default_value_len == sizeof ("true" )- 1
5390- && !memcmp (default_value , "true" , sizeof ("true" )- 1 )) {
5407+ } else if (zend_string_equals_cstr (default_value , "true" , strlen ("true" ))) {
53915408 ZVAL_TRUE (default_value_zval );
53925409 return SUCCESS ;
5393- } else if (default_value_len == sizeof ("false" )- 1
5394- && !memcmp (default_value , "false" , sizeof ("false" )- 1 )) {
5410+ } else if (zend_string_equals_cstr (default_value , "false" , strlen ("false" ))) {
53955411 ZVAL_FALSE (default_value_zval );
53965412 return SUCCESS ;
5397- } else if (default_value_len >= 2
5398- && (default_value [0 ] == '\'' || default_value [0 ] == '"' )
5399- && default_value [ default_value_len - 1 ] == default_value [0 ]) {
5413+ } else if (ZSTR_LEN ( default_value ) >= 2
5414+ && (ZSTR_VAL ( default_value ) [0 ] == '\'' || ZSTR_VAL ( default_value ) [0 ] == '"' )
5415+ && ZSTR_VAL ( default_value )[ ZSTR_LEN ( default_value ) - 1 ] == ZSTR_VAL ( default_value ) [0 ]) {
54005416 zend_string * str = try_parse_string (
5401- default_value + 1 , default_value_len - 2 , default_value [0 ]);
5417+ ZSTR_VAL ( default_value ) + 1 , ZSTR_LEN ( default_value ) - 2 , ZSTR_VAL ( default_value ) [0 ]);
54025418 if (str ) {
54035419 ZVAL_STR (default_value_zval , str );
54045420 return SUCCESS ;
54055421 }
5406- } else if (default_value_len == sizeof ("[]" )- 1
5407- && !memcmp (default_value , "[]" , sizeof ("[]" )- 1 )) {
5422+ } else if (zend_string_equals_cstr (default_value , "[]" , strlen ("[]" ))) {
54085423 ZVAL_EMPTY_ARRAY (default_value_zval );
54095424 return SUCCESS ;
5410- } else if (ZEND_HANDLE_NUMERIC_STR (default_value , default_value_len , lval )) {
5425+ } else if (ZEND_HANDLE_NUMERIC (default_value , lval )) {
54115426 ZVAL_LONG (default_value_zval , lval );
54125427 return SUCCESS ;
54135428 }
54145429
54155430#if 0
5416- fprintf (stderr , "Evaluating %s via AST\n" , default_value );
5431+ fprintf (stderr , "Evaluating %s via AST\n" , ZSTR_VAL ( default_value ) );
54175432#endif
5418- return get_default_via_ast (default_value_zval , default_value );
5433+ return get_default_via_ast (default_value_zval , ZSTR_VAL ( default_value ) );
54195434}
0 commit comments