diff options
author | George Peter Banyard <girgias@php.net> | 2020-07-29 02:51:09 +0100 |
---|---|---|
committer | George Peter Banyard <girgias@php.net> | 2020-07-29 02:51:09 +0100 |
commit | b2248789ed21300aaf356336bf43b6b065183fcb (patch) | |
tree | c61dba0a43f72d27904e956318f911c7dc719dda /Zend/zend_execute.c | |
parent | f759936591c08d9bff6ab707f2f8c192f61b5bf1 (diff) | |
download | php-git-b2248789ed21300aaf356336bf43b6b065183fcb.tar.gz |
Implement 'Saner Numeric Strings' RFC:
RFC: https://wiki.php.net/rfc/saner-numeric-strings
This removes the -1 allow_error mode from is_numeric_string functions and replaces it by
a trailing boolean out argument to preserve BC in a couple of places.
Most of the changes can be resumed to "numeric" strings which emitted a E_NOTICE now emit
a E_WARNING and "numeric" strings which emitted a E_WARNING now throw a TypeError.
This mostly affects:
- String offsets
- Arithmetic operations
- Bitwise operations
Closes GH-5762
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r-- | Zend/zend_execute.c | 75 |
1 files changed, 35 insertions, 40 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index efb2d008a8..51d4a0d003 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -728,7 +728,7 @@ static zend_bool zend_verify_weak_scalar_type_hint(uint32_t type_mask, zval *arg /* For an int|float union type and string value, * determine chosen type by is_numeric_string() semantics. */ if ((type_mask & MAY_BE_DOUBLE) && Z_TYPE_P(arg) == IS_STRING) { - zend_uchar type = is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), &lval, &dval, -1); + zend_uchar type = is_numeric_str_function(Z_STR_P(arg), &lval, &dval); if (type == IS_LONG) { zend_string_release(Z_STR_P(arg)); ZVAL_LONG(arg, lval); @@ -770,35 +770,11 @@ static zend_bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_m double dval; zend_bool bval; - if (type_mask & MAY_BE_LONG) { - if (Z_TYPE_P(arg) == IS_STRING) { - /* Handle this case separately to avoid the "non well-formed" warning */ - zend_uchar type = is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), NULL, &dval, 1); - if (type == IS_LONG) { - return 1; - } - if (type == IS_DOUBLE) { - if ((type_mask & MAY_BE_DOUBLE) - || (!zend_isnan(dval) && ZEND_DOUBLE_FITS_LONG(dval))) { - return 1; - } - - } - } - if (zend_parse_arg_long_weak(arg, &lval)) { - return 1; - } + if ((type_mask & MAY_BE_LONG) && zend_parse_arg_long_weak(arg, &lval)) { + return 1; } - if (type_mask & MAY_BE_DOUBLE) { - if (Z_TYPE_P(arg) == IS_STRING) { - /* Handle this case separately to avoid the "non well-formed" warning */ - if (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), NULL, NULL, 1) != 0) { - return 1; - } - } - if (zend_parse_arg_double_weak(arg, &dval)) { - return 1; - } + if ((type_mask & MAY_BE_DOUBLE) && zend_parse_arg_double_weak(arg, &dval)) { + return 1; } /* We don't call cast_object here, because this check must be side-effect free. As this * is only used for a sanity check of arginfo/zpp consistency, it's okay if we accept @@ -1271,6 +1247,11 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_offset(void) zend_type_error("Illegal offset type"); } +static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_string_offset(const zval *offset) +{ + zend_type_error("Cannot access offset of type %s on string", zend_zval_type_name(offset)); +} + static zend_never_inline void zend_assign_to_object_dim(zval *object, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC) { Z_OBJ_HT_P(object)->write_dimension(Z_OBJ_P(object), dim, value); @@ -1364,13 +1345,19 @@ try_again: if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) { switch(Z_TYPE_P(dim)) { case IS_STRING: - if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) { - break; - } - if (type != BP_VAR_UNSET) { - zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim)); + { + bool trailing_data = false; + /* For BC reasons we allow errors so that we can warn on leading numeric string */ + if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, + /* allow errors */ true, NULL, &trailing_data)) { + if (UNEXPECTED(trailing_data) && type != BP_VAR_UNSET) { + zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim)); + } + return offset; } + zend_illegal_string_offset(dim); break; + } case IS_UNDEF: ZVAL_UNDEFINED_OP2(); case IS_DOUBLE: @@ -1383,7 +1370,7 @@ try_again: dim = Z_REFVAL_P(dim); goto try_again; default: - zend_illegal_offset(); + zend_illegal_string_offset(dim); break; } @@ -2349,17 +2336,24 @@ try_array: try_string_offset: if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) { switch (Z_TYPE_P(dim)) { - /* case IS_LONG: */ case IS_STRING: - if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) { - break; + { + bool trailing_data = false; + /* For BC reasons we allow errors so that we can warn on leading numeric string */ + if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, + NULL, /* allow errors */ true, NULL, &trailing_data)) { + if (UNEXPECTED(trailing_data)) { + zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim)); + } + goto out; } if (type == BP_VAR_IS) { ZVAL_NULL(result); return; } - zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim)); + zend_illegal_string_offset(dim); break; + } case IS_UNDEF: ZVAL_UNDEFINED_OP2(); case IS_DOUBLE: @@ -2374,7 +2368,7 @@ try_string_offset: dim = Z_REFVAL_P(dim); goto try_string_offset; default: - zend_illegal_offset(); + zend_illegal_string_offset(dim); break; } @@ -2382,6 +2376,7 @@ try_string_offset: } else { offset = Z_LVAL_P(dim); } + out: if (UNEXPECTED(Z_STRLEN_P(container) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) { if (type != BP_VAR_IS) { |