20
20
*/
21
21
22
22
#include "zend.h"
23
+ #include "zend_compile.h"
23
24
#include "zend_execute.h"
24
25
#include "zend_API.h"
25
26
#include "zend_hash.h"
@@ -2952,6 +2953,80 @@ static zend_always_inline void zend_normalize_internal_type(zend_type *type) {
2952
2953
} ZEND_TYPE_FOREACH_END ();
2953
2954
}
2954
2955
2956
+ void zend_convert_internal_arg_info_type (zend_type * type )
2957
+ {
2958
+ if (ZEND_TYPE_HAS_LITERAL_NAME (* type )) {
2959
+ // gen_stubs.php does not support codegen for DNF types in arg infos.
2960
+ // As a temporary workaround, we split the type name on `|` characters,
2961
+ // converting it to an union type if necessary.
2962
+ const char * class_name = ZEND_TYPE_LITERAL_NAME (* type );
2963
+ type -> type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT ;
2964
+
2965
+ size_t num_types = 1 ;
2966
+ const char * p = class_name ;
2967
+ while ((p = strchr (p , '|' ))) {
2968
+ num_types ++ ;
2969
+ p ++ ;
2970
+ }
2971
+
2972
+ if (num_types == 1 ) {
2973
+ /* Simple class type */
2974
+ zend_string * str = zend_string_init_interned (class_name , strlen (class_name ), true);
2975
+ zend_alloc_ce_cache (str );
2976
+ ZEND_TYPE_SET_PTR (* type , str );
2977
+ type -> type_mask |= _ZEND_TYPE_NAME_BIT ;
2978
+ } else {
2979
+ /* Union type */
2980
+ zend_type_list * list = malloc (ZEND_TYPE_LIST_SIZE (num_types ));
2981
+ list -> num_types = num_types ;
2982
+ ZEND_TYPE_SET_LIST (* type , list );
2983
+ ZEND_TYPE_FULL_MASK (* type ) |= _ZEND_TYPE_UNION_BIT ;
2984
+
2985
+ const char * start = class_name ;
2986
+ uint32_t j = 0 ;
2987
+ while (true) {
2988
+ const char * end = strchr (start , '|' );
2989
+ zend_string * str = zend_string_init_interned (start , end ? end - start : strlen (start ), true);
2990
+ zend_alloc_ce_cache (str );
2991
+ list -> types [j ] = (zend_type ) ZEND_TYPE_INIT_CLASS (str , 0 , 0 );
2992
+ if (!end ) {
2993
+ break ;
2994
+ }
2995
+ start = end + 1 ;
2996
+ j ++ ;
2997
+ }
2998
+ }
2999
+ }
3000
+ if (ZEND_TYPE_IS_ITERABLE_FALLBACK (* type )) {
3001
+ /* Warning generated an extension load warning which is emitted for every test
3002
+ zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable,"
3003
+ " regenerate the argument info via the php-src gen_stub build script");
3004
+ */
3005
+ zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK (
3006
+ ZSTR_KNOWN (ZEND_STR_TRAVERSABLE ),
3007
+ (type -> type_mask | MAY_BE_ARRAY )
3008
+ );
3009
+ * type = legacy_iterable ;
3010
+ }
3011
+ }
3012
+
3013
+ void zend_convert_internal_arg_info (zend_arg_info * new_arg_info , const zend_internal_arg_info * arg_info , bool is_return_info )
3014
+ {
3015
+ if (!is_return_info ) {
3016
+ new_arg_info -> name = zend_string_init_interned (arg_info -> name , strlen (arg_info -> name ), true);
3017
+ if (arg_info -> default_value ) {
3018
+ new_arg_info -> default_value = zend_string_init_interned (arg_info -> default_value , strlen (arg_info -> default_value ), true);
3019
+ } else {
3020
+ new_arg_info -> default_value = NULL ;
3021
+ }
3022
+ } else {
3023
+ new_arg_info -> name = NULL ;
3024
+ new_arg_info -> default_value = NULL ;
3025
+ }
3026
+ new_arg_info -> type = arg_info -> type ;
3027
+ zend_convert_internal_arg_info_type (& new_arg_info -> type );
3028
+ }
3029
+
2955
3030
/* registers all functions in *library_functions in the function hash */
2956
3031
ZEND_API zend_result zend_register_functions (zend_class_entry * scope , const zend_function_entry * functions , HashTable * function_table , int type ) /* {{{ */
2957
3032
{
@@ -2963,6 +3038,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
2963
3038
int error_type ;
2964
3039
zend_string * lowercase_name ;
2965
3040
size_t fname_len ;
3041
+ const zend_internal_arg_info * internal_arg_info ;
2966
3042
2967
3043
if (type == MODULE_PERSISTENT ) {
2968
3044
error_type = E_CORE_WARNING ;
@@ -3019,7 +3095,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
3019
3095
3020
3096
if (ptr -> arg_info ) {
3021
3097
zend_internal_function_info * info = (zend_internal_function_info * )ptr -> arg_info ;
3022
- internal_function -> arg_info = ( zend_internal_arg_info * ) ptr -> arg_info + 1 ;
3098
+ internal_arg_info = ptr -> arg_info + 1 ;
3023
3099
internal_function -> num_args = ptr -> num_args ;
3024
3100
/* Currently you cannot denote that the function can accept less arguments than num_args */
3025
3101
if (info -> required_num_args == (uintptr_t )-1 ) {
@@ -3049,7 +3125,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
3049
3125
zend_error (E_CORE_WARNING , "Missing arginfo for %s%s%s()" ,
3050
3126
scope ? ZSTR_VAL (scope -> name ) : "" , scope ? "::" : "" , ptr -> fname );
3051
3127
3052
- internal_function -> arg_info = NULL ;
3128
+ internal_arg_info = NULL ;
3053
3129
internal_function -> num_args = 0 ;
3054
3130
internal_function -> required_num_args = 0 ;
3055
3131
}
@@ -3060,13 +3136,11 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
3060
3136
!(internal_function -> fn_flags & ZEND_ACC_HAS_RETURN_TYPE )) {
3061
3137
zend_error (E_CORE_WARNING , "%s::__toString() implemented without string return type" ,
3062
3138
ZSTR_VAL (scope -> name ));
3063
- internal_function -> arg_info = (zend_internal_arg_info * ) arg_info_toString + 1 ;
3139
+ internal_arg_info = (zend_internal_arg_info * ) arg_info_toString + 1 ;
3064
3140
internal_function -> fn_flags |= ZEND_ACC_HAS_RETURN_TYPE ;
3065
3141
internal_function -> num_args = internal_function -> required_num_args = 0 ;
3066
3142
}
3067
3143
3068
-
3069
- zend_set_function_arg_flags ((zend_function * )internal_function );
3070
3144
if (ptr -> flags & ZEND_ACC_ABSTRACT ) {
3071
3145
if (scope ) {
3072
3146
/* This is a class that must be abstract itself. Here we set the check info. */
@@ -3131,17 +3205,17 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
3131
3205
}
3132
3206
3133
3207
/* If types of arguments have to be checked */
3134
- if (reg_function -> arg_info && num_args ) {
3208
+ if (internal_arg_info && num_args ) {
3135
3209
uint32_t i ;
3136
3210
for (i = 0 ; i < num_args ; i ++ ) {
3137
- zend_internal_arg_info * arg_info = & reg_function -> arg_info [i ];
3211
+ const zend_internal_arg_info * arg_info = & internal_arg_info [i ];
3138
3212
ZEND_ASSERT (arg_info -> name && "Parameter must have a name" );
3139
3213
if (ZEND_TYPE_IS_SET (arg_info -> type )) {
3140
3214
reg_function -> fn_flags |= ZEND_ACC_HAS_TYPE_HINTS ;
3141
3215
}
3142
3216
#if ZEND_DEBUG
3143
3217
for (uint32_t j = 0 ; j < i ; j ++ ) {
3144
- if (!strcmp (arg_info -> name , reg_function -> arg_info [j ].name )) {
3218
+ if (!strcmp (arg_info -> name , internal_arg_info [j ].name )) {
3145
3219
zend_error_noreturn (E_CORE_ERROR ,
3146
3220
"Duplicate parameter name $%s for function %s%s%s()" , arg_info -> name ,
3147
3221
scope ? ZSTR_VAL (scope -> name ) : "" , scope ? "::" : "" , ptr -> fname );
@@ -3151,78 +3225,23 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
3151
3225
}
3152
3226
}
3153
3227
3154
- /* Rebuild arginfos if parameter/property types and/or a return type are used */
3155
- if (reg_function -> arg_info &&
3156
- (reg_function -> fn_flags & (ZEND_ACC_HAS_RETURN_TYPE |ZEND_ACC_HAS_TYPE_HINTS ))) {
3157
- /* convert "const char*" class type names into "zend_string*" */
3228
+ /* Convert zend_internal_arg_info to zend_arg_info */
3229
+ if (internal_arg_info ) {
3158
3230
uint32_t i ;
3159
- zend_internal_arg_info * arg_info = reg_function -> arg_info - 1 ;
3160
- zend_internal_arg_info * new_arg_info ;
3231
+ const zend_internal_arg_info * arg_info = internal_arg_info - 1 ;
3232
+ zend_arg_info * new_arg_info ;
3161
3233
3162
3234
/* Treat return type as an extra argument */
3163
3235
num_args ++ ;
3164
- new_arg_info = malloc (sizeof (zend_internal_arg_info ) * num_args );
3165
- memcpy (new_arg_info , arg_info , sizeof (zend_internal_arg_info ) * num_args );
3236
+ new_arg_info = malloc (sizeof (zend_arg_info ) * num_args );
3166
3237
reg_function -> arg_info = new_arg_info + 1 ;
3167
3238
for (i = 0 ; i < num_args ; i ++ ) {
3168
- if (ZEND_TYPE_HAS_LITERAL_NAME (new_arg_info [i ].type )) {
3169
- // gen_stubs.php does not support codegen for DNF types in arg infos.
3170
- // As a temporary workaround, we split the type name on `|` characters,
3171
- // converting it to an union type if necessary.
3172
- const char * class_name = ZEND_TYPE_LITERAL_NAME (new_arg_info [i ].type );
3173
- new_arg_info [i ].type .type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT ;
3174
-
3175
- size_t num_types = 1 ;
3176
- const char * p = class_name ;
3177
- while ((p = strchr (p , '|' ))) {
3178
- num_types ++ ;
3179
- p ++ ;
3180
- }
3181
-
3182
- if (num_types == 1 ) {
3183
- /* Simple class type */
3184
- zend_string * str = zend_string_init_interned (class_name , strlen (class_name ), 1 );
3185
- zend_alloc_ce_cache (str );
3186
- ZEND_TYPE_SET_PTR (new_arg_info [i ].type , str );
3187
- new_arg_info [i ].type .type_mask |= _ZEND_TYPE_NAME_BIT ;
3188
- } else {
3189
- /* Union type */
3190
- zend_type_list * list = malloc (ZEND_TYPE_LIST_SIZE (num_types ));
3191
- list -> num_types = num_types ;
3192
- ZEND_TYPE_SET_LIST (new_arg_info [i ].type , list );
3193
- ZEND_TYPE_FULL_MASK (new_arg_info [i ].type ) |= _ZEND_TYPE_UNION_BIT ;
3194
-
3195
- const char * start = class_name ;
3196
- uint32_t j = 0 ;
3197
- while (true) {
3198
- const char * end = strchr (start , '|' );
3199
- zend_string * str = zend_string_init_interned (start , end ? end - start : strlen (start ), 1 );
3200
- zend_alloc_ce_cache (str );
3201
- list -> types [j ] = (zend_type ) ZEND_TYPE_INIT_CLASS (str , 0 , 0 );
3202
- if (!end ) {
3203
- break ;
3204
- }
3205
- start = end + 1 ;
3206
- j ++ ;
3207
- }
3208
- }
3209
- }
3210
- if (ZEND_TYPE_IS_ITERABLE_FALLBACK (new_arg_info [i ].type )) {
3211
- /* Warning generated an extension load warning which is emitted for every test
3212
- zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable,"
3213
- " regenerate the argument info via the php-src gen_stub build script");
3214
- */
3215
- zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK (
3216
- ZSTR_KNOWN (ZEND_STR_TRAVERSABLE ),
3217
- (new_arg_info [i ].type .type_mask | MAY_BE_ARRAY )
3218
- );
3219
- new_arg_info [i ].type = legacy_iterable ;
3220
- }
3221
-
3222
- zend_normalize_internal_type (& new_arg_info [i ].type );
3239
+ zend_convert_internal_arg_info (& new_arg_info [i ], & arg_info [i ], i == 0 );
3223
3240
}
3224
3241
}
3225
3242
3243
+ zend_set_function_arg_flags ((zend_function * )reg_function );
3244
+
3226
3245
if (scope ) {
3227
3246
zend_check_magic_method_implementation (
3228
3247
scope , (zend_function * )reg_function , lowercase_name , E_CORE_ERROR );
@@ -5313,49 +5332,44 @@ static zend_string *try_parse_string(const char *str, size_t len, char quote) {
5313
5332
return zend_string_init (str , len , 0 );
5314
5333
}
5315
5334
5316
- ZEND_API zend_result zend_get_default_from_internal_arg_info (
5317
- zval * default_value_zval , zend_internal_arg_info * arg_info )
5335
+ ZEND_API zend_result zend_get_default_from_arg_info (
5336
+ zval * default_value_zval , const zend_arg_info * arg_info )
5318
5337
{
5319
- const char * default_value = arg_info -> default_value ;
5338
+ zend_string * default_value = arg_info -> default_value ;
5320
5339
if (!default_value ) {
5321
5340
return FAILURE ;
5322
5341
}
5323
5342
5324
5343
/* Avoid going through the full AST machinery for some simple and common cases. */
5325
- size_t default_value_len = strlen (default_value );
5326
5344
zend_ulong lval ;
5327
- if (default_value_len == sizeof ("null" )- 1
5328
- && !memcmp (default_value , "null" , sizeof ("null" )- 1 )) {
5345
+ if (zend_string_equals_literal (default_value , "null" )) {
5329
5346
ZVAL_NULL (default_value_zval );
5330
5347
return SUCCESS ;
5331
- } else if (default_value_len == sizeof ("true" )- 1
5332
- && !memcmp (default_value , "true" , sizeof ("true" )- 1 )) {
5348
+ } else if (zend_string_equals_literal (default_value , "true" )) {
5333
5349
ZVAL_TRUE (default_value_zval );
5334
5350
return SUCCESS ;
5335
- } else if (default_value_len == sizeof ("false" )- 1
5336
- && !memcmp (default_value , "false" , sizeof ("false" )- 1 )) {
5351
+ } else if (zend_string_equals_literal (default_value , "false" )) {
5337
5352
ZVAL_FALSE (default_value_zval );
5338
5353
return SUCCESS ;
5339
- } else if (default_value_len >= 2
5340
- && (default_value [0 ] == '\'' || default_value [0 ] == '"' )
5341
- && default_value [ default_value_len - 1 ] == default_value [0 ]) {
5354
+ } else if (ZSTR_LEN ( default_value ) >= 2
5355
+ && (ZSTR_VAL ( default_value ) [0 ] == '\'' || ZSTR_VAL ( default_value ) [0 ] == '"' )
5356
+ && ZSTR_VAL ( default_value )[ ZSTR_LEN ( default_value ) - 1 ] == ZSTR_VAL ( default_value ) [0 ]) {
5342
5357
zend_string * str = try_parse_string (
5343
- default_value + 1 , default_value_len - 2 , default_value [0 ]);
5358
+ ZSTR_VAL ( default_value ) + 1 , ZSTR_LEN ( default_value ) - 2 , ZSTR_VAL ( default_value ) [0 ]);
5344
5359
if (str ) {
5345
5360
ZVAL_STR (default_value_zval , str );
5346
5361
return SUCCESS ;
5347
5362
}
5348
- } else if (default_value_len == sizeof ("[]" )- 1
5349
- && !memcmp (default_value , "[]" , sizeof ("[]" )- 1 )) {
5363
+ } else if (zend_string_equals_literal (default_value , "[]" )) {
5350
5364
ZVAL_EMPTY_ARRAY (default_value_zval );
5351
5365
return SUCCESS ;
5352
- } else if (ZEND_HANDLE_NUMERIC_STR (default_value , default_value_len , lval )) {
5366
+ } else if (ZEND_HANDLE_NUMERIC (default_value , lval )) {
5353
5367
ZVAL_LONG (default_value_zval , lval );
5354
5368
return SUCCESS ;
5355
5369
}
5356
5370
5357
5371
#if 0
5358
- fprintf (stderr , "Evaluating %s via AST\n" , default_value );
5372
+ fprintf (stderr , "Evaluating %s via AST\n" , ZSTR_VAL ( default_value ) );
5359
5373
#endif
5360
- return get_default_via_ast (default_value_zval , default_value );
5374
+ return get_default_via_ast (default_value_zval , ZSTR_VAL ( default_value ) );
5361
5375
}
0 commit comments