summaryrefslogtreecommitdiff
path: root/Zend/zend_API.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-30 16:45:48 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-02-11 21:46:13 +0100
commitb10416a652d26577a22fe0b183b2258b20c8bb86 (patch)
tree3b79102286b2307575f487bf97d572ffc292631d /Zend/zend_API.c
parentf06895488a5fabd27ac4c2e66a9d311f14d8594e (diff)
downloadphp-git-b10416a652d26577a22fe0b183b2258b20c8bb86.tar.gz
Deprecate passing null to non-nullable arg of internal function
This deprecates passing null to non-nullable scale arguments of internal functions, with the eventual goal of making the behavior consistent with userland functions, where null is never accepted for non-nullable arguments. This change is expected to cause quite a lot of fallout. In most cases, calling code should be adjusted to avoid passing null. In some cases, PHP should be adjusted to make some function arguments nullable. I have already fixed a number of functions before landing this, but feel free to file a bug if you encounter a function that doesn't accept null, but probably should. (The rule of thumb for this to be applicable is that the function must have special behavior for 0 or "", which is distinct from the natural behavior of the parameter.) RFC: https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_arg Closes GH-6475.
Diffstat (limited to 'Zend/zend_API.c')
-rw-r--r--Zend/zend_API.c96
1 files changed, 70 insertions, 26 deletions
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index abfbb411a5..6aa9a043ff 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -426,9 +426,41 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **p
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest) /* {{{ */
+static ZEND_COLD bool zend_null_arg_deprecated(const char *fallback_type, uint32_t arg_num) {
+ zend_function *func = EG(current_execute_data)->func;
+ ZEND_ASSERT(arg_num > 0);
+ uint32_t arg_offset = arg_num - 1;
+ if (arg_offset >= func->common.num_args) {
+ ZEND_ASSERT(func->common.fn_flags & ZEND_ACC_VARIADIC);
+ arg_offset = func->common.num_args;
+ }
+
+ zend_arg_info *arg_info = &func->common.arg_info[arg_offset];
+ zend_string *func_name = get_active_function_or_method_name();
+ const char *arg_name = get_active_function_arg_name(arg_num);
+
+ /* If no type is specified in arginfo, use the specified fallback_type determined through
+ * zend_parse_parameters instead. */
+ zend_string *type_str = zend_type_to_string(arg_info->type);
+ const char *type = type_str ? ZSTR_VAL(type_str) : fallback_type;
+ zend_error(E_DEPRECATED,
+ "%s(): Passing null to parameter #%" PRIu32 "%s%s%s of type %s is deprecated",
+ ZSTR_VAL(func_name), arg_num,
+ arg_name ? " ($" : "", arg_name ? arg_name : "", arg_name ? ")" : "",
+ type);
+ zend_string_release(func_name);
+ if (type_str) {
+ zend_string_release(type_str);
+ }
+ return !EG(exception);
+}
+
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest, uint32_t arg_num) /* {{{ */
{
if (EXPECTED(Z_TYPE_P(arg) <= IS_STRING)) {
+ if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("bool", arg_num)) {
+ return 0;
+ }
*dest = zend_is_true(arg);
} else {
return 0;
@@ -437,16 +469,16 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, bool *dest) /* {
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, bool *dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, bool *dest, uint32_t arg_num) /* {{{ */
{
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
return 0;
}
- return zend_parse_arg_bool_weak(arg, dest);
+ return zend_parse_arg_bool_weak(arg, dest, arg_num);
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */
{
if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) {
@@ -479,6 +511,9 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest)
return 0;
}
} else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
+ if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int", arg_num)) {
+ return 0;
+ }
*dest = 0;
} else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
*dest = 1;
@@ -489,16 +524,16 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest)
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */
{
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
return 0;
}
- return zend_parse_arg_long_weak(arg, dest);
+ return zend_parse_arg_long_weak(arg, dest, arg_num);
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest, uint32_t arg_num) /* {{{ */
{
if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
*dest = (double)Z_LVAL_P(arg);
@@ -517,6 +552,9 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest)
return 0;
}
} else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
+ if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("float", arg_num)) {
+ return 0;
+ }
*dest = 0.0;
} else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
*dest = 1.0;
@@ -527,7 +565,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest)
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest, uint32_t arg_num) /* {{{ */
{
if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
/* SSTH Exception: IS_LONG may be accepted instead as IS_DOUBLE */
@@ -535,11 +573,11 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest)
} else if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
return 0;
}
- return zend_parse_arg_double_weak(arg, dest);
+ return zend_parse_arg_double_weak(arg, dest, arg_num);
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest, uint32_t arg_num) /* {{{ */
{
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
return 0;
@@ -558,6 +596,9 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest) /
}
zend_string_release(str);
} else if (Z_TYPE_P(arg) < IS_TRUE) {
+ if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int|float", arg_num)) {
+ return 0;
+ }
ZVAL_LONG(arg, 0);
} else if (Z_TYPE_P(arg) == IS_TRUE) {
ZVAL_LONG(arg, 1);
@@ -569,9 +610,12 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest) /
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest, uint32_t arg_num) /* {{{ */
{
if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) {
+ if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("string", arg_num)) {
+ return 0;
+ }
convert_to_string(arg);
*dest = Z_STR_P(arg);
} else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
@@ -591,24 +635,24 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **des
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest, uint32_t arg_num) /* {{{ */
{
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
return 0;
}
- return zend_parse_arg_str_weak(arg, dest);
+ return zend_parse_arg_str_weak(arg, dest, arg_num);
}
/* }}} */
-ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long) /* {{{ */
+ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long, uint32_t arg_num) /* {{{ */
{
if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
return 0;
}
- if (zend_parse_arg_long_weak(arg, dest_long)) {
+ if (zend_parse_arg_long_weak(arg, dest_long, arg_num)) {
*dest_str = NULL;
return 1;
- } else if (zend_parse_arg_str_weak(arg, dest_str)) {
+ } else if (zend_parse_arg_str_weak(arg, dest_str, arg_num)) {
*dest_long = 0;
return 1;
} else {
@@ -617,7 +661,7 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_stri
}
/* }}} */
-static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec, char **error) /* {{{ */
+static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec, char **error, uint32_t arg_num) /* {{{ */
{
const char *spec_walk = *spec;
char c = *spec_walk++;
@@ -650,7 +694,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
is_null = va_arg(*va, bool *);
}
- if (!zend_parse_arg_long(arg, p, is_null, check_null)) {
+ if (!zend_parse_arg_long(arg, p, is_null, check_null, arg_num)) {
return check_null ? "?int" : "int";
}
}
@@ -665,7 +709,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
is_null = va_arg(*va, bool *);
}
- if (!zend_parse_arg_double(arg, p, is_null, check_null)) {
+ if (!zend_parse_arg_double(arg, p, is_null, check_null, arg_num)) {
return check_null ? "?float" : "float";
}
}
@@ -675,7 +719,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
{
zval **p = va_arg(*va, zval **);
- if (!zend_parse_arg_number(arg, p, check_null)) {
+ if (!zend_parse_arg_number(arg, p, check_null, arg_num)) {
return check_null ? "int|float|null" : "int|float";
}
}
@@ -685,7 +729,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
{
char **p = va_arg(*va, char **);
size_t *pl = va_arg(*va, size_t *);
- if (!zend_parse_arg_string(arg, p, pl, check_null)) {
+ if (!zend_parse_arg_string(arg, p, pl, check_null, arg_num)) {
return check_null ? "?string" : "string";
}
}
@@ -695,7 +739,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
{
char **p = va_arg(*va, char **);
size_t *pl = va_arg(*va, size_t *);
- if (!zend_parse_arg_path(arg, p, pl, check_null)) {
+ if (!zend_parse_arg_path(arg, p, pl, check_null, arg_num)) {
if (Z_TYPE_P(arg) == IS_STRING) {
zend_spprintf(error, 0, "must not contain any null bytes");
return "";
@@ -709,7 +753,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
case 'P':
{
zend_string **str = va_arg(*va, zend_string **);
- if (!zend_parse_arg_path_str(arg, str, check_null)) {
+ if (!zend_parse_arg_path_str(arg, str, check_null, arg_num)) {
if (Z_TYPE_P(arg) == IS_STRING) {
zend_spprintf(error, 0, "must not contain any null bytes");
return "";
@@ -723,7 +767,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
case 'S':
{
zend_string **str = va_arg(*va, zend_string **);
- if (!zend_parse_arg_str(arg, str, check_null)) {
+ if (!zend_parse_arg_str(arg, str, check_null, arg_num)) {
return check_null ? "?string" : "string";
}
}
@@ -738,7 +782,7 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
is_null = va_arg(*va, bool *);
}
- if (!zend_parse_arg_bool(arg, p, is_null, check_null)) {
+ if (!zend_parse_arg_bool(arg, p, is_null, check_null, arg_num)) {
return check_null ? "?bool" : "bool";
}
}
@@ -899,7 +943,7 @@ static zend_result zend_parse_arg(uint32_t arg_num, zval *arg, va_list *va, cons
const char *expected_type = NULL;
char *error = NULL;
- expected_type = zend_parse_arg_impl(arg, va, spec, &error);
+ expected_type = zend_parse_arg_impl(arg, va, spec, &error, arg_num);
if (expected_type) {
if (EG(exception)) {
return FAILURE;