From 1e184422749be0d8f90347a7976a3a2a8fa3eea0 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 14 Jan 2022 14:47:41 +0100 Subject: [PATCH 01/17] Add zend_ini_parse_quantity() and deprecate zend_atol(), zend_atoi() zend_atol() and zend_atoi() don't just do number parsing. They also check for a 'K', 'M', or 'G' at the end of the string, and multiply the parsed value out accordingly. Unfortunately, they ignore any other non-numerics between the numeric component and the last character in the string. This means that numbers such as the following are both valid and non-intuitive in their final output. * "123KMG" is interpreted as "123G" -> 132070244352 * "123G " is interpreted as "123 " -> 123 * "123GB" is interpreted as "123B" -> 123 * "123 I like tacos." is also interpreted as "123." -> 123 Currently, in php-src these functions are used only for parsing ini values. In this change we deprecate zend_atol(), zend_atoi(), and introduce a new function with the same behaviour, but with the ability to report invalid inputs to the caller. The function's name also makes the behaviour less unexpected: zend_ini_parse_quantity(). Co-authored-by: Sara Golemon --- Zend/tests/zend_ini_parse_quantity.phpt | 360 ++++++++++++++++++ Zend/tests/zend_ini_parse_quantity_error.phpt | 32 ++ Zend/zend_ini.c | 63 +++ Zend/zend_ini.h | 22 ++ Zend/zend_operators.h | 7 +- ext/zend_test/test.c | 17 + ext/zend_test/test.stub.php | 2 + ext/zend_test/test_arginfo.h | 8 +- 8 files changed, 508 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/zend_ini_parse_quantity.phpt create mode 100644 Zend/tests/zend_ini_parse_quantity_error.phpt diff --git a/Zend/tests/zend_ini_parse_quantity.phpt b/Zend/tests/zend_ini_parse_quantity.phpt new file mode 100644 index 0000000000000..c6c4c418f2039 --- /dev/null +++ b/Zend/tests/zend_ini_parse_quantity.phpt @@ -0,0 +1,360 @@ +--TEST-- +Test parsing of quantities (e.g. "16M") +--EXTENSIONS-- +zend_test +--FILE-- +no value" +#define ZEND_IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r') || ((c) == '\v') || ((c) == '\f')) + /* * hash_apply functions */ @@ -536,6 +538,67 @@ ZEND_API bool zend_ini_parse_bool(zend_string *str) } } +ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr) /* {{{ */ +{ + char *digits_end = NULL; + char *str = ZSTR_VAL(value); + size_t str_len = ZSTR_LEN(value); + + /* Ignore trailing whitespace */ + while (str_len && ZEND_IS_WHITESPACE(str[str_len-1])) --str_len; + if (!str_len) return 0; + + /* Perform following multiplications on unsigned to avoid overflow UB. + * For now overflow is silently ignored -- not clear what else can be + * done here, especially as the final result of this function may be + * used in an unsigned context (e.g. "memory_limit=3G", which overflows + * zend_long on 32-bit, but not size_t). */ + zend_ulong retval = (zend_ulong) ZEND_STRTOL(str, &digits_end, 0); + + if (digits_end == str) { + *errstr = zend_strpprintf(0, "Invalid numeric string '%.*s': no valid leading digits, interpreting as '0' for backwards compatibility", + (int)str_len, str); + return 0; + } + + /* Allow for whitespace between integer portion and any suffix character */ + while (ZEND_IS_WHITESPACE(*digits_end)) ++digits_end; + + /* No exponent suffix. */ + if (!*digits_end) return retval; + + if (str_len>0) { + switch (str[str_len-1]) { + case 'g': + case 'G': + retval *= 1024; + ZEND_FALLTHROUGH; + case 'm': + case 'M': + retval *= 1024; + ZEND_FALLTHROUGH; + case 'k': + case 'K': + retval *= 1024; + break; + default: + /* Unknown suffix */ + *errstr = zend_strpprintf(0, "Invalid numeric string '%.*s': unknown multipler '%c', interpreting as '%.*s' for backwards compatibility", + (int)str_len, str, str[str_len-1], (int)(digits_end - str), str); + return retval; + } + } + + if (digits_end < &str[str_len-1]) { + /* More than one character in suffix */ + *errstr = zend_strpprintf(0, "Invalid numeric string '%.*s', interpreting as '%.*s%c' for backwards compatibility", + (int)str_len, str, (int)(digits_end - str), str, str[str_len-1]); + } + + return (zend_long) retval; +} +/* }}} */ + ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ { int value; diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 23258ec0ca8b5..172ac5c8042a8 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -90,6 +90,28 @@ ZEND_API char *zend_ini_string_ex(const char *name, size_t name_length, int orig ZEND_API zend_string *zend_ini_get_value(zend_string *name); ZEND_API bool zend_ini_parse_bool(zend_string *str); +/** + * Parses a quantity + * + * value must be a string of digits optionally followed by a multiplier + * character K, M, or G (for 2**10, 2**20, and 2**30, respectively). + * + * The digits are parsed as decimal unless the first character is '0', in which + * case they are parsed as octal. + * + * Whitespaces before and after the digits portion are ignored. + * + * For backwards compatibility, invalid values are handled as follows: + * - No leading digits: value is treated as '0' + * - Invalid multiplier: multiplier is ignored + * - Invalid characters between digits and multiplier: invalid characters are + * ignored + * + * In all of these cases an error string is stored in *errstr (caller must + * release it). + */ +ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr); + ZEND_API zend_result zend_ini_register_displayer(const char *name, uint32_t name_length, void (*displayer)(zend_ini_entry *ini_entry, int type)); ZEND_API ZEND_INI_DISP(zend_ini_boolean_displayer_cb); diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 346706d22beae..de02a406d575e 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -468,8 +468,11 @@ ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2); ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2); -ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, size_t str_len); -ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len); +/** Deprecatd in favor of ZEND_STRTOL() */ +ZEND_ATTRIBUTE_DEPRECATED ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, size_t str_len); + +/** Deprecatd in favor of ZEND_STRTOL() */ +ZEND_ATTRIBUTE_DEPRECATED ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len); #define convert_to_null_ex(zv) convert_to_null(zv) #define convert_to_boolean_ex(zv) convert_to_boolean(zv) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 6adab9f255cbf..56af2c69e9cd7 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -380,6 +380,23 @@ static ZEND_FUNCTION(zend_get_unit_enum) RETURN_OBJ_COPY(zend_enum_get_case_cstr(zend_test_unit_enum, "Foo")); } +static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity) +{ + zend_string *str; + zend_string *errstr = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + RETVAL_LONG(zend_ini_parse_quantity(str, &errstr)); + + if (errstr) { + zend_error(E_WARNING, "%s", errstr); + zend_string_release(errstr); + } +} + static ZEND_FUNCTION(namespaced_func) { ZEND_PARSE_PARAMETERS_NONE(); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 08122b6c02581..dc9b70342d882 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -125,6 +125,8 @@ function zend_test_parameter_with_attribute(string $parameter): int {} function zend_get_current_func_name(): string {} function zend_call_method(object|string $obj_or_class, string $method, mixed $arg1 = UNKNOWN, mixed $arg2 = UNKNOWN): mixed {} + + function zend_test_zend_ini_parse_quantity(string $str): int {} } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 26ed9f72f78a3..e8598770675a1 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2d42ea64a5114eae618a6dfb642c2640f568f5db */ + * Stub hash: a2f8ee1cf97ba226439c025ba7257dd181644489 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -85,6 +85,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_call_method, 0, 2, IS_MIXED ZEND_ARG_TYPE_INFO(0, arg2, IS_MIXED, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_zend_ini_parse_quantity, 0, 1, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_ZendSubNS_namespaced_func, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -146,6 +150,7 @@ static ZEND_FUNCTION(zend_get_unit_enum); static ZEND_FUNCTION(zend_test_parameter_with_attribute); static ZEND_FUNCTION(zend_get_current_func_name); static ZEND_FUNCTION(zend_call_method); +static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity); static ZEND_FUNCTION(namespaced_func); static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); @@ -186,6 +191,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_parameter_with_attribute, arginfo_zend_test_parameter_with_attribute) ZEND_FE(zend_get_current_func_name, arginfo_zend_get_current_func_name) ZEND_FE(zend_call_method, arginfo_zend_call_method) + ZEND_FE(zend_test_zend_ini_parse_quantity, arginfo_zend_test_zend_ini_parse_quantity) ZEND_NS_FE("ZendTestNS2\\ZendSubNS", namespaced_func, arginfo_ZendTestNS2_ZendSubNS_namespaced_func) ZEND_FE_END }; From 6e4b86fdd043b60c77624b655e474ef82fdc67ba Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 14 Jan 2022 15:04:19 +0100 Subject: [PATCH 02/17] Migrate zend_atol() calls to ZEND_ATOL() or zend_ini_parse_quantity() --- Zend/zend.c | 14 ++++++- Zend/zend_ini.c | 26 +++++++++++-- Zend/zend_ini.h | 8 ++-- Zend/zend_operators.c | 11 ++++-- ext/bcmath/bcmath.c | 7 +++- ext/opcache/zend_accelerator_module.c | 39 ++++++++++++++++--- ext/standard/basic_functions.c | 2 +- .../parse_ini_numeric_entry_name.phpt | 23 +++++++++++ ext/zend_test/php_test.h | 1 + ext/zend_test/test.c | 10 +++-- ext/zlib/zlib.c | 7 +++- main/main.c | 7 +++- 12 files changed, 130 insertions(+), 25 deletions(-) create mode 100644 ext/standard/tests/general_functions/parse_ini_numeric_entry_name.phpt diff --git a/Zend/zend.c b/Zend/zend.c index 97d937db5a2ed..5ae49a9320a47 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -145,8 +145,13 @@ static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */ static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */ { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); + zend_string *errstr; - zend_long val = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_long val = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } if (stage != ZEND_INI_STAGE_STARTUP && stage != ZEND_INI_STAGE_SHUTDOWN && @@ -175,8 +180,13 @@ static ZEND_INI_MH(OnSetExceptionStringParamMaxLen) /* {{{ */ static ZEND_INI_MH(OnUpdateFiberStackSize) /* {{{ */ { + zend_string *errstr; if (new_value) { - EG(fiber_stack_size) = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + EG(fiber_stack_size) = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } } else { EG(fiber_stack_size) = ZEND_FIBER_DEFAULT_C_STACK_SIZE; } diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 20511a36ad9aa..3e5fed22bdc57 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -546,7 +546,10 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err /* Ignore trailing whitespace */ while (str_len && ZEND_IS_WHITESPACE(str[str_len-1])) --str_len; - if (!str_len) return 0; + if (!str_len) { + *errstr = NULL; + return 0; + } /* Perform following multiplications on unsigned to avoid overflow UB. * For now overflow is silently ignored -- not clear what else can be @@ -565,7 +568,10 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err while (ZEND_IS_WHITESPACE(*digits_end)) ++digits_end; /* No exponent suffix. */ - if (!*digits_end) return retval; + if (!*digits_end) { + *errstr = NULL; + return retval; + } if (str_len>0) { switch (str[str_len-1]) { @@ -593,8 +599,10 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err /* More than one character in suffix */ *errstr = zend_strpprintf(0, "Invalid numeric string '%.*s', interpreting as '%.*s%c' for backwards compatibility", (int)str_len, str, (int)(digits_end - str), str, str[str_len-1]); + return (zend_long) retval; } + *errstr = NULL; return (zend_long) retval; } /* }}} */ @@ -687,14 +695,24 @@ ZEND_API ZEND_INI_MH(OnUpdateBool) /* {{{ */ ZEND_API ZEND_INI_MH(OnUpdateLong) /* {{{ */ { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); - *p = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_string *errstr; + *p = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } return SUCCESS; } /* }}} */ ZEND_API ZEND_INI_MH(OnUpdateLongGEZero) /* {{{ */ { - zend_long tmp = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_string *errstr; + zend_long tmp = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } if (tmp < 0) { return FAILURE; } diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 172ac5c8042a8..0fa151af9d731 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -99,16 +99,16 @@ ZEND_API bool zend_ini_parse_bool(zend_string *str); * The digits are parsed as decimal unless the first character is '0', in which * case they are parsed as octal. * - * Whitespaces before and after the digits portion are ignored. + * Whitespaces before and after the multiplier are ignored. * - * For backwards compatibility, invalid values are handled as follows: + * For backwards compatibility, ill-formatted values are handled as follows: * - No leading digits: value is treated as '0' * - Invalid multiplier: multiplier is ignored * - Invalid characters between digits and multiplier: invalid characters are * ignored * - * In all of these cases an error string is stored in *errstr (caller must - * release it). + * In any of these cases an error string is stored in *errstr (caller must + * release it), otherwise *errstr is set to NULL. */ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index a35edc01501c0..3690162418fa3 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -118,7 +118,7 @@ ZEND_API const unsigned char zend_toupper_map[256] = { 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, -0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff +0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff }; @@ -136,7 +136,7 @@ ZEND_API const unsigned char zend_toupper_map[256] = { zend_binary_strncasecmp */ -ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* {{{ */ +static zend_long ZEND_FASTCALL zend_atol_internal(const char *str, size_t str_len) /* {{{ */ { if (!str_len) { str_len = strlen(str); @@ -168,9 +168,14 @@ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* { } /* }}} */ +ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) +{ + return zend_atol_internal(str, str_len); +} + ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, size_t str_len) { - return (int) zend_atol(str, str_len); + return (int) zend_atol_internal(str, str_len); } /* {{{ convert_object_to_type: dst will be either ctype or UNDEF */ diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index 1b50764b828aa..a35a58f5387c4 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -61,8 +61,13 @@ ZEND_INI_MH(OnUpdateScale) { int *p; zend_long tmp; + zend_string *errstr; - tmp = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + tmp = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } if (tmp < 0 || tmp > INT_MAX) { return FAILURE; } diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 5bdfe7a373a73..2067e04205602 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -165,7 +165,12 @@ static ZEND_INI_MH(OnUpdateJit) static ZEND_INI_MH(OnUpdateJitDebug) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); - zend_long val = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_string *errstr; + zend_long val = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } if (zend_jit_debug_config(*p, val, stage) == SUCCESS) { *p = val; @@ -176,7 +181,13 @@ static ZEND_INI_MH(OnUpdateJitDebug) static ZEND_INI_MH(OnUpdateCounter) { - zend_long val = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_string *errstr; + zend_long val = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } + if (val >= 0 && val < 256) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; @@ -188,7 +199,13 @@ static ZEND_INI_MH(OnUpdateCounter) static ZEND_INI_MH(OnUpdateUnrollC) { - zend_long val = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_string *errstr; + zend_long val = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } + if (val > 0 && val < ZEND_JIT_TRACE_MAX_CALL_DEPTH) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; @@ -201,7 +218,13 @@ static ZEND_INI_MH(OnUpdateUnrollC) static ZEND_INI_MH(OnUpdateUnrollR) { - zend_long val = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_string *errstr; + zend_long val = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } + if (val >= 0 && val < ZEND_JIT_TRACE_MAX_RET_DEPTH) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; @@ -214,7 +237,13 @@ static ZEND_INI_MH(OnUpdateUnrollR) static ZEND_INI_MH(OnUpdateUnrollL) { - zend_long val = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_string *errstr; + zend_long val = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } + if (val > 0 && val < ZEND_JIT_TRACE_MAX_LOOPS_UNROLL) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 91a5ae6519c5f..b50996f4e760e 100755 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -2507,7 +2507,7 @@ static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int cal } if (!(Z_STRLEN_P(arg1) > 1 && Z_STRVAL_P(arg1)[0] == '0') && is_numeric_string(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), NULL, NULL, 0) == IS_LONG) { - zend_ulong key = (zend_ulong) zend_atol(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1)); + zend_ulong key = (zend_ulong) ZEND_STRTOUL(Z_STRVAL_P(arg1), NULL, 0); if ((find_hash = zend_hash_index_find(Z_ARRVAL_P(arr), key)) == NULL) { array_init(&hash); find_hash = zend_hash_index_add_new(Z_ARRVAL_P(arr), key, &hash); diff --git a/ext/standard/tests/general_functions/parse_ini_numeric_entry_name.phpt b/ext/standard/tests/general_functions/parse_ini_numeric_entry_name.phpt new file mode 100644 index 0000000000000..a359a9f38285b --- /dev/null +++ b/ext/standard/tests/general_functions/parse_ini_numeric_entry_name.phpt @@ -0,0 +1,23 @@ +--TEST-- +parse_ini_string with numeric entry name +--FILE-- + + array(1) { + [0]=> + string(1) "1" + } + ["2M"]=> + array(1) { + [0]=> + string(1) "2" + } +} diff --git a/ext/zend_test/php_test.h b/ext/zend_test/php_test.h index a08c080ee3730..1c0b24f0d0849 100644 --- a/ext/zend_test/php_test.h +++ b/ext/zend_test/php_test.h @@ -53,6 +53,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test) int register_passes; bool print_stderr_mshutdown; zend_test_fiber *active_fiber; + zend_long quantity_value; ZEND_END_MODULE_GLOBALS(zend_test) extern ZEND_DECLARE_MODULE_GLOBALS(zend_test) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 56af2c69e9cd7..11b35b91590e5 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -383,7 +383,7 @@ static ZEND_FUNCTION(zend_get_unit_enum) static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity) { zend_string *str; - zend_string *errstr = NULL; + zend_string *errstr; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(str) @@ -392,7 +392,7 @@ static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity) RETVAL_LONG(zend_ini_parse_quantity(str, &errstr)); if (errstr) { - zend_error(E_WARNING, "%s", errstr); + zend_error(E_WARNING, "%s", ZSTR_VAL(errstr)); zend_string_release(errstr); } } @@ -588,6 +588,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.print_stderr_mshutdown", "0", PHP_INI_SYSTEM, OnUpdateBool, print_stderr_mshutdown, zend_zend_test_globals, zend_test_globals) + STD_PHP_INI_ENTRY("zend_test.quantity_value", "0", PHP_INI_ALL, OnUpdateLong, quantity_value, zend_zend_test_globals, zend_test_globals) PHP_INI_END() void (*old_zend_execute_ex)(zend_execute_data *execute_data); @@ -785,7 +786,10 @@ ZEND_GET_MODULE(zend_test) /* The important part here is the ZEND_FASTCALL. */ PHP_ZEND_TEST_API int ZEND_FASTCALL bug78270(const char *str, size_t str_len) { - return (int) zend_atol(str, str_len); + char * copy = zend_strndup(str, str_len); + int r = (int) ZEND_ATOL(copy); + free(copy); + return r; } PHP_ZEND_TEST_API struct bug79096 bug79096(void) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index a53fb2acc4593..a4caffc40f602 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1268,6 +1268,7 @@ static PHP_INI_MH(OnUpdate_zlib_output_compression) { int int_value; char *ini_value; + zend_string *errstr = NULL; if (new_value == NULL) { return FAILURE; } @@ -1277,7 +1278,11 @@ static PHP_INI_MH(OnUpdate_zlib_output_compression) } else if (zend_string_equals_literal_ci(new_value, "on")) { int_value = 1; } else { - int_value = zend_atoi(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + int_value = (int) zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } } ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0); diff --git a/main/main.c b/main/main.c index aa1763e5e5642..b79b419546839 100644 --- a/main/main.c +++ b/main/main.c @@ -262,8 +262,13 @@ static PHP_INI_MH(OnSetSerializePrecision) static PHP_INI_MH(OnChangeMemoryLimit) { size_t value; + zend_string *errstr; if (new_value) { - value = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + value = zend_ini_parse_quantity(new_value, &errstr); + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } } else { value = Z_L(1)<<30; /* effectively, no limit */ } From 2a37b1d3a0835d737d5ede3b51447c3d0ec2f08e Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sat, 4 Jun 2022 16:21:56 +0200 Subject: [PATCH 03/17] Improve wording --- Zend/tests/zend_ini_parse_quantity_error.phpt | 8 ++++---- Zend/zend_ini.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Zend/tests/zend_ini_parse_quantity_error.phpt b/Zend/tests/zend_ini_parse_quantity_error.phpt index becff57026a47..417c61cb64543 100644 --- a/Zend/tests/zend_ini_parse_quantity_error.phpt +++ b/Zend/tests/zend_ini_parse_quantity_error.phpt @@ -19,14 +19,14 @@ foreach ($tests as $setting) { } --EXPECTF-- -Warning: Invalid numeric string 'K': no valid leading digits, interpreting as '0' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity 'K': no valid leading digits, interpreting as '0' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(0) -Warning: Invalid numeric string '1KM', interpreting as '1M' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity '1KM', interpreting as '1M' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1048576) -Warning: Invalid numeric string '1X': unknown multipler 'X', interpreting as '1' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity '1X': unknown multipler 'X', interpreting as '1' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1) -Warning: Invalid numeric string '1.0K', interpreting as '1K' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity '1.0K', interpreting as '1K' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1024) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 3e5fed22bdc57..a6fc546204bbd 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -559,7 +559,7 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err zend_ulong retval = (zend_ulong) ZEND_STRTOL(str, &digits_end, 0); if (digits_end == str) { - *errstr = zend_strpprintf(0, "Invalid numeric string '%.*s': no valid leading digits, interpreting as '0' for backwards compatibility", + *errstr = zend_strpprintf(0, "Invalid quantity '%.*s': no valid leading digits, interpreting as '0' for backwards compatibility", (int)str_len, str); return 0; } @@ -589,7 +589,7 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err break; default: /* Unknown suffix */ - *errstr = zend_strpprintf(0, "Invalid numeric string '%.*s': unknown multipler '%c', interpreting as '%.*s' for backwards compatibility", + *errstr = zend_strpprintf(0, "Invalid quantity '%.*s': unknown multipler '%c', interpreting as '%.*s' for backwards compatibility", (int)str_len, str, str[str_len-1], (int)(digits_end - str), str); return retval; } @@ -597,7 +597,7 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err if (digits_end < &str[str_len-1]) { /* More than one character in suffix */ - *errstr = zend_strpprintf(0, "Invalid numeric string '%.*s', interpreting as '%.*s%c' for backwards compatibility", + *errstr = zend_strpprintf(0, "Invalid quantity '%.*s', interpreting as '%.*s%c' for backwards compatibility", (int)str_len, str, (int)(digits_end - str), str, str[str_len-1]); return (zend_long) retval; } From 1ea189343ef61f40693ee402c768c47abbb970b8 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sat, 4 Jun 2022 16:45:32 +0200 Subject: [PATCH 04/17] Add tests --- Zend/tests/zend_ini_parse_quantity.phpt | 344 +++++++++++++++++- Zend/tests/zend_ini_parse_quantity_error.phpt | 1 - ...zend_ini_parse_quantity_ini_set_error.phpt | 13 + 3 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt diff --git a/Zend/tests/zend_ini_parse_quantity.phpt b/Zend/tests/zend_ini_parse_quantity.phpt index c6c4c418f2039..e563e779065db 100644 --- a/Zend/tests/zend_ini_parse_quantity.phpt +++ b/Zend/tests/zend_ini_parse_quantity.phpt @@ -11,350 +11,692 @@ foreach (['', ' '] as $leadingWS) { foreach (['', ' '] as $midWS) { foreach (['', 'K', 'k', 'M', 'm', 'G', 'g'] as $exp) { foreach (['', ' '] as $trailingWS) { + // Decimal $setting = sprintf('%s%s1%s%s%s', $leadingWS, $sign, $midWS, $exp, $trailingWS); var_dump($setting); var_dump(zend_test_zend_ini_parse_quantity($setting)); + + // Octal + $setting = sprintf('%s%s0123%s%s%s', + $leadingWS, $sign, $midWS, $exp, $trailingWS); + var_dump($setting); + var_dump(zend_test_zend_ini_parse_quantity($setting)); } } } } } - --EXPECT-- string(1) "1" int(1) +string(4) "0123" +int(83) string(2) "1 " int(1) +string(5) "0123 " +int(83) string(2) "1K" int(1024) +string(5) "0123K" +int(84992) string(3) "1K " int(1024) +string(6) "0123K " +int(84992) string(2) "1k" int(1024) +string(5) "0123k" +int(84992) string(3) "1k " int(1024) +string(6) "0123k " +int(84992) string(2) "1M" int(1048576) +string(5) "0123M" +int(87031808) string(3) "1M " int(1048576) +string(6) "0123M " +int(87031808) string(2) "1m" int(1048576) +string(5) "0123m" +int(87031808) string(3) "1m " int(1048576) +string(6) "0123m " +int(87031808) string(2) "1G" int(1073741824) +string(5) "0123G" +int(89120571392) string(3) "1G " int(1073741824) +string(6) "0123G " +int(89120571392) string(2) "1g" int(1073741824) +string(5) "0123g" +int(89120571392) string(3) "1g " int(1073741824) +string(6) "0123g " +int(89120571392) string(2) "1 " int(1) +string(5) "0123 " +int(83) string(3) "1 " int(1) +string(6) "0123 " +int(83) string(3) "1 K" int(1024) +string(6) "0123 K" +int(84992) string(4) "1 K " int(1024) +string(7) "0123 K " +int(84992) string(3) "1 k" int(1024) +string(6) "0123 k" +int(84992) string(4) "1 k " int(1024) +string(7) "0123 k " +int(84992) string(3) "1 M" int(1048576) +string(6) "0123 M" +int(87031808) string(4) "1 M " int(1048576) +string(7) "0123 M " +int(87031808) string(3) "1 m" int(1048576) +string(6) "0123 m" +int(87031808) string(4) "1 m " int(1048576) +string(7) "0123 m " +int(87031808) string(3) "1 G" int(1073741824) +string(6) "0123 G" +int(89120571392) string(4) "1 G " int(1073741824) +string(7) "0123 G " +int(89120571392) string(3) "1 g" int(1073741824) +string(6) "0123 g" +int(89120571392) string(4) "1 g " int(1073741824) +string(7) "0123 g " +int(89120571392) string(2) "+1" int(1) +string(5) "+0123" +int(83) string(3) "+1 " int(1) +string(6) "+0123 " +int(83) string(3) "+1K" int(1024) +string(6) "+0123K" +int(84992) string(4) "+1K " int(1024) +string(7) "+0123K " +int(84992) string(3) "+1k" int(1024) +string(6) "+0123k" +int(84992) string(4) "+1k " int(1024) +string(7) "+0123k " +int(84992) string(3) "+1M" int(1048576) +string(6) "+0123M" +int(87031808) string(4) "+1M " int(1048576) +string(7) "+0123M " +int(87031808) string(3) "+1m" int(1048576) +string(6) "+0123m" +int(87031808) string(4) "+1m " int(1048576) +string(7) "+0123m " +int(87031808) string(3) "+1G" int(1073741824) +string(6) "+0123G" +int(89120571392) string(4) "+1G " int(1073741824) +string(7) "+0123G " +int(89120571392) string(3) "+1g" int(1073741824) +string(6) "+0123g" +int(89120571392) string(4) "+1g " int(1073741824) +string(7) "+0123g " +int(89120571392) string(3) "+1 " int(1) +string(6) "+0123 " +int(83) string(4) "+1 " int(1) +string(7) "+0123 " +int(83) string(4) "+1 K" int(1024) +string(7) "+0123 K" +int(84992) string(5) "+1 K " int(1024) +string(8) "+0123 K " +int(84992) string(4) "+1 k" int(1024) +string(7) "+0123 k" +int(84992) string(5) "+1 k " int(1024) +string(8) "+0123 k " +int(84992) string(4) "+1 M" int(1048576) +string(7) "+0123 M" +int(87031808) string(5) "+1 M " int(1048576) +string(8) "+0123 M " +int(87031808) string(4) "+1 m" int(1048576) +string(7) "+0123 m" +int(87031808) string(5) "+1 m " int(1048576) +string(8) "+0123 m " +int(87031808) string(4) "+1 G" int(1073741824) +string(7) "+0123 G" +int(89120571392) string(5) "+1 G " int(1073741824) +string(8) "+0123 G " +int(89120571392) string(4) "+1 g" int(1073741824) +string(7) "+0123 g" +int(89120571392) string(5) "+1 g " int(1073741824) +string(8) "+0123 g " +int(89120571392) string(2) "-1" int(-1) +string(5) "-0123" +int(-83) string(3) "-1 " int(-1) +string(6) "-0123 " +int(-83) string(3) "-1K" int(-1024) +string(6) "-0123K" +int(-84992) string(4) "-1K " int(-1024) +string(7) "-0123K " +int(-84992) string(3) "-1k" int(-1024) +string(6) "-0123k" +int(-84992) string(4) "-1k " int(-1024) +string(7) "-0123k " +int(-84992) string(3) "-1M" int(-1048576) +string(6) "-0123M" +int(-87031808) string(4) "-1M " int(-1048576) +string(7) "-0123M " +int(-87031808) string(3) "-1m" int(-1048576) +string(6) "-0123m" +int(-87031808) string(4) "-1m " int(-1048576) +string(7) "-0123m " +int(-87031808) string(3) "-1G" int(-1073741824) +string(6) "-0123G" +int(-89120571392) string(4) "-1G " int(-1073741824) +string(7) "-0123G " +int(-89120571392) string(3) "-1g" int(-1073741824) +string(6) "-0123g" +int(-89120571392) string(4) "-1g " int(-1073741824) +string(7) "-0123g " +int(-89120571392) string(3) "-1 " int(-1) +string(6) "-0123 " +int(-83) string(4) "-1 " int(-1) +string(7) "-0123 " +int(-83) string(4) "-1 K" int(-1024) +string(7) "-0123 K" +int(-84992) string(5) "-1 K " int(-1024) +string(8) "-0123 K " +int(-84992) string(4) "-1 k" int(-1024) +string(7) "-0123 k" +int(-84992) string(5) "-1 k " int(-1024) +string(8) "-0123 k " +int(-84992) string(4) "-1 M" int(-1048576) +string(7) "-0123 M" +int(-87031808) string(5) "-1 M " int(-1048576) +string(8) "-0123 M " +int(-87031808) string(4) "-1 m" int(-1048576) +string(7) "-0123 m" +int(-87031808) string(5) "-1 m " int(-1048576) +string(8) "-0123 m " +int(-87031808) string(4) "-1 G" int(-1073741824) +string(7) "-0123 G" +int(-89120571392) string(5) "-1 G " int(-1073741824) +string(8) "-0123 G " +int(-89120571392) string(4) "-1 g" int(-1073741824) +string(7) "-0123 g" +int(-89120571392) string(5) "-1 g " int(-1073741824) +string(8) "-0123 g " +int(-89120571392) string(2) " 1" int(1) +string(5) " 0123" +int(83) string(3) " 1 " int(1) +string(6) " 0123 " +int(83) string(3) " 1K" int(1024) +string(6) " 0123K" +int(84992) string(4) " 1K " int(1024) +string(7) " 0123K " +int(84992) string(3) " 1k" int(1024) +string(6) " 0123k" +int(84992) string(4) " 1k " int(1024) +string(7) " 0123k " +int(84992) string(3) " 1M" int(1048576) +string(6) " 0123M" +int(87031808) string(4) " 1M " int(1048576) +string(7) " 0123M " +int(87031808) string(3) " 1m" int(1048576) +string(6) " 0123m" +int(87031808) string(4) " 1m " int(1048576) +string(7) " 0123m " +int(87031808) string(3) " 1G" int(1073741824) +string(6) " 0123G" +int(89120571392) string(4) " 1G " int(1073741824) +string(7) " 0123G " +int(89120571392) string(3) " 1g" int(1073741824) +string(6) " 0123g" +int(89120571392) string(4) " 1g " int(1073741824) +string(7) " 0123g " +int(89120571392) string(3) " 1 " int(1) +string(6) " 0123 " +int(83) string(4) " 1 " int(1) +string(7) " 0123 " +int(83) string(4) " 1 K" int(1024) +string(7) " 0123 K" +int(84992) string(5) " 1 K " int(1024) +string(8) " 0123 K " +int(84992) string(4) " 1 k" int(1024) +string(7) " 0123 k" +int(84992) string(5) " 1 k " int(1024) +string(8) " 0123 k " +int(84992) string(4) " 1 M" int(1048576) +string(7) " 0123 M" +int(87031808) string(5) " 1 M " int(1048576) +string(8) " 0123 M " +int(87031808) string(4) " 1 m" int(1048576) +string(7) " 0123 m" +int(87031808) string(5) " 1 m " int(1048576) +string(8) " 0123 m " +int(87031808) string(4) " 1 G" int(1073741824) +string(7) " 0123 G" +int(89120571392) string(5) " 1 G " int(1073741824) +string(8) " 0123 G " +int(89120571392) string(4) " 1 g" int(1073741824) +string(7) " 0123 g" +int(89120571392) string(5) " 1 g " int(1073741824) +string(8) " 0123 g " +int(89120571392) string(3) " +1" int(1) +string(6) " +0123" +int(83) string(4) " +1 " int(1) +string(7) " +0123 " +int(83) string(4) " +1K" int(1024) +string(7) " +0123K" +int(84992) string(5) " +1K " int(1024) +string(8) " +0123K " +int(84992) string(4) " +1k" int(1024) +string(7) " +0123k" +int(84992) string(5) " +1k " int(1024) +string(8) " +0123k " +int(84992) string(4) " +1M" int(1048576) +string(7) " +0123M" +int(87031808) string(5) " +1M " int(1048576) +string(8) " +0123M " +int(87031808) string(4) " +1m" int(1048576) +string(7) " +0123m" +int(87031808) string(5) " +1m " int(1048576) +string(8) " +0123m " +int(87031808) string(4) " +1G" int(1073741824) +string(7) " +0123G" +int(89120571392) string(5) " +1G " int(1073741824) +string(8) " +0123G " +int(89120571392) string(4) " +1g" int(1073741824) +string(7) " +0123g" +int(89120571392) string(5) " +1g " int(1073741824) +string(8) " +0123g " +int(89120571392) string(4) " +1 " int(1) +string(7) " +0123 " +int(83) string(5) " +1 " int(1) +string(8) " +0123 " +int(83) string(5) " +1 K" int(1024) +string(8) " +0123 K" +int(84992) string(6) " +1 K " int(1024) +string(9) " +0123 K " +int(84992) string(5) " +1 k" int(1024) +string(8) " +0123 k" +int(84992) string(6) " +1 k " int(1024) +string(9) " +0123 k " +int(84992) string(5) " +1 M" int(1048576) +string(8) " +0123 M" +int(87031808) string(6) " +1 M " int(1048576) +string(9) " +0123 M " +int(87031808) string(5) " +1 m" int(1048576) +string(8) " +0123 m" +int(87031808) string(6) " +1 m " int(1048576) +string(9) " +0123 m " +int(87031808) string(5) " +1 G" int(1073741824) +string(8) " +0123 G" +int(89120571392) string(6) " +1 G " int(1073741824) +string(9) " +0123 G " +int(89120571392) string(5) " +1 g" int(1073741824) +string(8) " +0123 g" +int(89120571392) string(6) " +1 g " int(1073741824) +string(9) " +0123 g " +int(89120571392) string(3) " -1" int(-1) +string(6) " -0123" +int(-83) string(4) " -1 " int(-1) +string(7) " -0123 " +int(-83) string(4) " -1K" int(-1024) +string(7) " -0123K" +int(-84992) string(5) " -1K " int(-1024) +string(8) " -0123K " +int(-84992) string(4) " -1k" int(-1024) +string(7) " -0123k" +int(-84992) string(5) " -1k " int(-1024) +string(8) " -0123k " +int(-84992) string(4) " -1M" int(-1048576) +string(7) " -0123M" +int(-87031808) string(5) " -1M " int(-1048576) +string(8) " -0123M " +int(-87031808) string(4) " -1m" int(-1048576) +string(7) " -0123m" +int(-87031808) string(5) " -1m " int(-1048576) +string(8) " -0123m " +int(-87031808) string(4) " -1G" int(-1073741824) +string(7) " -0123G" +int(-89120571392) string(5) " -1G " int(-1073741824) +string(8) " -0123G " +int(-89120571392) string(4) " -1g" int(-1073741824) +string(7) " -0123g" +int(-89120571392) string(5) " -1g " int(-1073741824) +string(8) " -0123g " +int(-89120571392) string(4) " -1 " int(-1) +string(7) " -0123 " +int(-83) string(5) " -1 " int(-1) +string(8) " -0123 " +int(-83) string(5) " -1 K" int(-1024) +string(8) " -0123 K" +int(-84992) string(6) " -1 K " int(-1024) +string(9) " -0123 K " +int(-84992) string(5) " -1 k" int(-1024) +string(8) " -0123 k" +int(-84992) string(6) " -1 k " int(-1024) +string(9) " -0123 k " +int(-84992) string(5) " -1 M" int(-1048576) +string(8) " -0123 M" +int(-87031808) string(6) " -1 M " int(-1048576) +string(9) " -0123 M " +int(-87031808) string(5) " -1 m" int(-1048576) +string(8) " -0123 m" +int(-87031808) string(6) " -1 m " int(-1048576) +string(9) " -0123 m " +int(-87031808) string(5) " -1 G" int(-1073741824) +string(8) " -0123 G" +int(-89120571392) string(6) " -1 G " int(-1073741824) +string(9) " -0123 G " +int(-89120571392) string(5) " -1 g" int(-1073741824) +string(8) " -0123 g" +int(-89120571392) string(6) " -1 g " int(-1073741824) +string(9) " -0123 g " +int(-89120571392) diff --git a/Zend/tests/zend_ini_parse_quantity_error.phpt b/Zend/tests/zend_ini_parse_quantity_error.phpt index 417c61cb64543..9e23001f884e9 100644 --- a/Zend/tests/zend_ini_parse_quantity_error.phpt +++ b/Zend/tests/zend_ini_parse_quantity_error.phpt @@ -17,7 +17,6 @@ $tests = [ foreach ($tests as $setting) { var_dump(zend_test_zend_ini_parse_quantity($setting)); } - --EXPECTF-- Warning: Invalid quantity 'K': no valid leading digits, interpreting as '0' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(0) diff --git a/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt b/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt new file mode 100644 index 0000000000000..0ee274aee747b --- /dev/null +++ b/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test ini_set() with invalid quantity syntax +--EXTENSIONS-- +zend_test +--FILE-- + Date: Sat, 4 Jun 2022 18:00:46 +0200 Subject: [PATCH 05/17] zend_is_whitespace as a function --- Zend/zend_ini.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index a6fc546204bbd..796bdbff95af2 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -30,7 +30,9 @@ static HashTable *registered_zend_ini_directives; #define NO_VALUE_PLAINTEXT "no value" #define NO_VALUE_HTML "no value" -#define ZEND_IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r') || ((c) == '\v') || ((c) == '\f')) +static inline bool zend_is_whitespace(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f'; +} /* * hash_apply functions @@ -545,7 +547,8 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err size_t str_len = ZSTR_LEN(value); /* Ignore trailing whitespace */ - while (str_len && ZEND_IS_WHITESPACE(str[str_len-1])) --str_len; + while (str_len && zend_is_whitespace(str[str_len-1])) --str_len; + if (!str_len) { *errstr = NULL; return 0; @@ -565,7 +568,7 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err } /* Allow for whitespace between integer portion and any suffix character */ - while (ZEND_IS_WHITESPACE(*digits_end)) ++digits_end; + while (zend_is_whitespace(*digits_end)) ++digits_end; /* No exponent suffix. */ if (!*digits_end) { From a779737a2ed4cf392a15e6e5a5dde4cf9d73e81e Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sat, 4 Jun 2022 18:13:34 +0200 Subject: [PATCH 06/17] Null safety --- Zend/tests/zend_ini_parse_quantity_null.phpt | 30 +++++++++++ Zend/zend_ini.c | 55 ++++++++++++++++---- 2 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 Zend/tests/zend_ini_parse_quantity_null.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_null.phpt b/Zend/tests/zend_ini_parse_quantity_null.phpt new file mode 100644 index 0000000000000..b88e7b54525ec --- /dev/null +++ b/Zend/tests/zend_ini_parse_quantity_null.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test parsing of quantities with null byte +--FILE-- + Date: Sun, 5 Jun 2022 19:37:08 +0200 Subject: [PATCH 07/17] Handle overflows --- Zend/tests/zend_ini_parse_quantity_error.phpt | 8 +- ...zend_ini_parse_quantity_ini_set_error.phpt | 4 +- Zend/tests/zend_ini_parse_quantity_null.phpt | 12 +- Zend/zend_ini.c | 174 ++++++++++++------ Zend/zend_ini.h | 32 +++- ext/zend_test/test.c | 17 ++ ext/zend_test/test.stub.php | 1 + ext/zend_test/test_arginfo.h | 6 +- main/main.c | 2 +- 9 files changed, 182 insertions(+), 74 deletions(-) diff --git a/Zend/tests/zend_ini_parse_quantity_error.phpt b/Zend/tests/zend_ini_parse_quantity_error.phpt index 9e23001f884e9..06b732ce315e4 100644 --- a/Zend/tests/zend_ini_parse_quantity_error.phpt +++ b/Zend/tests/zend_ini_parse_quantity_error.phpt @@ -18,14 +18,14 @@ foreach ($tests as $setting) { var_dump(zend_test_zend_ini_parse_quantity($setting)); } --EXPECTF-- -Warning: Invalid quantity 'K': no valid leading digits, interpreting as '0' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity "K": no valid leading digits, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(0) -Warning: Invalid quantity '1KM', interpreting as '1M' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity "1KM", interpreting as "1M" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1048576) -Warning: Invalid quantity '1X': unknown multipler 'X', interpreting as '1' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity "1X": unknown multipler "X", interpreting as "1" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1) -Warning: Invalid quantity '1.0K', interpreting as '1K' for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity "1.0K", interpreting as "1K" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1024) diff --git a/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt b/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt index 0ee274aee747b..98e059e306135 100644 --- a/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt +++ b/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt @@ -1,5 +1,5 @@ --TEST-- -Test ini_set() with invalid quantity syntax +Test ini_set() with invalid quantity --EXTENSIONS-- zend_test --FILE-- @@ -8,6 +8,6 @@ zend_test var_dump(ini_set("zend_test.quantity_value", "1MB")); var_dump(ini_get("zend_test.quantity_value")); --EXPECTF-- -Warning: Invalid "zend_test.quantity_value" setting: Invalid quantity '1MB': unknown multipler 'B', interpreting as '1' for backwards compatibility in %s on line %d +Warning: Invalid "zend_test.quantity_value" setting: Invalid quantity "1MB": unknown multipler "B", interpreting as "1" for backwards compatibility in %s on line %d string(1) "0" string(3) "1MB" diff --git a/Zend/tests/zend_ini_parse_quantity_null.phpt b/Zend/tests/zend_ini_parse_quantity_null.phpt index b88e7b54525ec..7be19da6138c0 100644 --- a/Zend/tests/zend_ini_parse_quantity_null.phpt +++ b/Zend/tests/zend_ini_parse_quantity_null.phpt @@ -11,20 +11,20 @@ var_dump(zend_test_zend_ini_parse_quantity(" 123K\x00")); var_dump(zend_test_zend_ini_parse_quantity(" 123\x00")); --EXPECTF-- -Warning: Invalid quantity ' 123\x00K', interpreting as ' 123K' for backwards compatibility in %s on line %d +Warning: Invalid quantity " 123\x00K", interpreting as " 123K" for backwards compatibility in %s on line %d int(125952) -Warning: Invalid quantity '\x00 123K': no valid leading digits, interpreting as '0' for backwards compatibility in %s on line %d +Warning: Invalid quantity "\x00 123K": no valid leading digits, interpreting as "0" for backwards compatibility in %s on line %d int(0) -Warning: Invalid quantity ' \x00123K': no valid leading digits, interpreting as '0' for backwards compatibility in %s on line %d +Warning: Invalid quantity " \x00123K": no valid leading digits, interpreting as "0" for backwards compatibility in %s on line %d int(0) -Warning: Invalid quantity ' 123\x00K', interpreting as ' 123K' for backwards compatibility in %s on line %d +Warning: Invalid quantity " 123\x00K", interpreting as " 123K" for backwards compatibility in %s on line %d int(125952) -Warning: Invalid quantity ' 123K\x00': unknown multipler '\x00', interpreting as ' 123' for backwards compatibility in %s on line %d +Warning: Invalid quantity " 123K\x00": unknown multipler "\x00", interpreting as " 123" for backwards compatibility in %s on line %d int(123) -Warning: Invalid quantity ' 123\x00': unknown multipler '\x00', interpreting as ' 123' for backwards compatibility in %s on line %d +Warning: Invalid quantity " 123\x00": unknown multipler "\x00", interpreting as " 123" for backwards compatibility in %s on line %d int(123) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index a832bbb19dc55..55673e602733f 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -541,35 +541,59 @@ ZEND_API bool zend_ini_parse_bool(zend_string *str) } } -ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr) /* {{{ */ +static zend_long zend_ini_parse_quantity_internal(zend_string *value, bool signed_result, zend_string **errstr) /* {{{ */ { char *digits_end = NULL; char *str = ZSTR_VAL(value); - size_t str_len = ZSTR_LEN(value); + char *str_end = &str[ZSTR_LEN(value)]; + char *digits = str; + bool overflow = false; + zend_ulong factor; smart_str invalid = {0}; smart_str interpreted = {0}; smart_str chr = {0}; + /* Ignore leading whitespace. ZEND_STRTOL() also skips leading whitespaces, + * but we need the position of the first non-whitespace later. */ + while (digits < str_end && zend_is_whitespace(*digits)) ++digits; + /* Ignore trailing whitespace */ - while (str_len && zend_is_whitespace(str[str_len-1])) --str_len; + while (digits < str_end && zend_is_whitespace(*(str_end-1))) --str_end; - if (!str_len) { + if (digits == str_end) { *errstr = NULL; return 0; } - /* Perform following multiplications on unsigned to avoid overflow UB. - * For now overflow is silently ignored -- not clear what else can be - * done here, especially as the final result of this function may be - * used in an unsigned context (e.g. "memory_limit=3G", which overflows - * zend_long on 32-bit, but not size_t). */ - zend_ulong retval = (zend_ulong) ZEND_STRTOL(str, &digits_end, 0); + zend_ulong retval; + errno = 0; + + if (signed_result) { + retval = (zend_ulong) ZEND_STRTOL(digits, &digits_end, 0); + } else { + retval = ZEND_STRTOUL(digits, &digits_end, 0); + } + + if (errno == ERANGE) { + overflow = true; + } else if (!signed_result) { + /* ZEND_STRTOUL() does not report a range error when the subject starts + * with a minus sign, so we check this here. Ignore "-1" as it is + * commonly used as max value, for instance in memory_limit=-1. */ + if (digits[0] == '-' && !(digits_end - digits == 2 && digits_end == str_end && digits[1] == '1')) { + overflow = true; + } + } + + if (UNEXPECTED(digits_end == digits)) { + /* No leading digits */ - if (digits_end == str) { - smart_str_append_escaped(&invalid, str, str_len); + /* Escape the string to avoid null bytes and to make non-printable chars + * visible */ + smart_str_append_escaped(&invalid, ZSTR_VAL(value), ZSTR_LEN(value)); smart_str_0(&invalid); - *errstr = zend_strpprintf(0, "Invalid quantity '%s': no valid leading digits, interpreting as '0' for backwards compatibility", + *errstr = zend_strpprintf(0, "Invalid quantity \"%s\": no valid leading digits, interpreting as \"0\" for backwards compatibility", ZSTR_VAL(invalid.s)); smart_str_free(&invalid); @@ -577,58 +601,70 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err } /* Allow for whitespace between integer portion and any suffix character */ - while (digits_end < &str[str_len] && zend_is_whitespace(*digits_end)) ++digits_end; + while (digits_end < str_end && zend_is_whitespace(*digits_end)) ++digits_end; /* No exponent suffix. */ - if (digits_end == &str[str_len]) { - *errstr = NULL; - return retval; - } - - if (str_len>0) { - switch (str[str_len-1]) { - case 'g': - case 'G': - retval *= 1024; - ZEND_FALLTHROUGH; - case 'm': - case 'M': - retval *= 1024; - ZEND_FALLTHROUGH; - case 'k': - case 'K': - retval *= 1024; - break; - default: - /* Unknown suffix */ - smart_str_append_escaped(&invalid, str, str_len); - smart_str_0(&invalid); - smart_str_append_escaped(&interpreted, str, digits_end - str); - smart_str_0(&interpreted); - smart_str_append_escaped(&chr, &str[str_len-1], 1); - smart_str_0(&chr); - - *errstr = zend_strpprintf(0, "Invalid quantity '%s': unknown multipler '%s', interpreting as '%s' for backwards compatibility", - ZSTR_VAL(invalid.s), ZSTR_VAL(chr.s), ZSTR_VAL(interpreted.s)); - - smart_str_free(&invalid); - smart_str_free(&interpreted); - smart_str_free(&chr); - - return retval; + if (digits_end == str_end) { + goto end; + } + + switch (*(str_end-1)) { + case 'g': + case 'G': + factor = 1<<30; + break; + case 'm': + case 'M': + factor = 1<<20; + break; + case 'k': + case 'K': + factor = 1<<10; + break; + default: + /* Unknown suffix */ + smart_str_append_escaped(&invalid, ZSTR_VAL(value), ZSTR_LEN(value)); + smart_str_0(&invalid); + smart_str_append_escaped(&interpreted, str, digits_end - str); + smart_str_0(&interpreted); + smart_str_append_escaped(&chr, str_end-1, 1); + smart_str_0(&chr); + + *errstr = zend_strpprintf(0, "Invalid quantity \"%s\": unknown multipler \"%s\", interpreting as \"%s\" for backwards compatibility", + ZSTR_VAL(invalid.s), ZSTR_VAL(chr.s), ZSTR_VAL(interpreted.s)); + + smart_str_free(&invalid); + smart_str_free(&interpreted); + smart_str_free(&chr); + + return retval; + } + + if (!overflow) { + if (signed_result) { + zend_long sretval = (zend_long)retval; + if (sretval > 0) { + overflow = (zend_long)retval > ZEND_LONG_MAX / (zend_long)factor; + } else { + overflow = (zend_long)retval < ZEND_LONG_MIN / (zend_long)factor; + } + } else { + overflow = retval > ZEND_ULONG_MAX / factor; } } - if (digits_end < &str[str_len-1]) { + retval *= factor; + + if (UNEXPECTED(digits_end != str_end-1)) { /* More than one character in suffix */ - smart_str_append_escaped(&invalid, str, str_len); + smart_str_append_escaped(&invalid, ZSTR_VAL(value), ZSTR_LEN(value)); smart_str_0(&invalid); smart_str_append_escaped(&interpreted, str, digits_end - str); smart_str_0(&interpreted); - smart_str_append_escaped(&chr, &str[str_len-1], 1); + smart_str_append_escaped(&chr, str_end-1, 1); smart_str_0(&chr); - *errstr = zend_strpprintf(0, "Invalid quantity '%s', interpreting as '%s%s' for backwards compatibility", + *errstr = zend_strpprintf(0, "Invalid quantity \"%s\", interpreting as \"%s%s\" for backwards compatibility", ZSTR_VAL(invalid.s), ZSTR_VAL(interpreted.s), ZSTR_VAL(chr.s)); smart_str_free(&invalid); @@ -638,11 +674,41 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err return (zend_long) retval; } +end: + if (UNEXPECTED(overflow)) { + smart_str_append_escaped(&invalid, ZSTR_VAL(value), ZSTR_LEN(value)); + smart_str_0(&invalid); + + /* Not specifying the resulting value here because the caller may make + * additional conversions. Not specifying the allowed range + * because the caller may do narrower range checks. */ + *errstr = zend_strpprintf(0, "Invalid quantity \"%s\": value is out of range, using overflow result for backwards compatibility", + ZSTR_VAL(invalid.s)); + + smart_str_free(&invalid); + smart_str_free(&interpreted); + smart_str_free(&chr); + + return (zend_long) retval; + } + *errstr = NULL; return (zend_long) retval; } /* }}} */ +ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr) /* {{{ */ +{ + return zend_ini_parse_quantity_internal(value, true, errstr); +} +/* }}} */ + +zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr) /* {{{ */ +{ + return (zend_ulong) zend_ini_parse_quantity_internal(value, false, errstr); +} +/* }}} */ + ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ { int value; diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 0fa151af9d731..9bb119ac0fc51 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -91,27 +91,47 @@ ZEND_API zend_string *zend_ini_get_value(zend_string *name); ZEND_API bool zend_ini_parse_bool(zend_string *str); /** - * Parses a quantity + * Parses an ini quantity * - * value must be a string of digits optionally followed by a multiplier - * character K, M, or G (for 2**10, 2**20, and 2**30, respectively). + * The value parameter must be a string in the form * - * The digits are parsed as decimal unless the first character is '0', in which - * case they are parsed as octal. + * sign? digits ws* multipler? * - * Whitespaces before and after the multiplier are ignored. + * with + * + * sign: [+-] + * digit: [0-9] + * digits: digit+ + * ws: [ \t\n\r\v\f] + * multipler: [KMG] + * + * Leading and trailing whitespaces are ignored. + * + * If the string is empty or consists only of only whitespaces, 0 is returned. + * + * Digits is parsed as decimal unless the first digit is '0', in which case + * digits is parsed as octal. + * + * The multiplier is case-insensitive. K, M, and G multiply the quantity by + * 2**10, 2**20, and 2**30, respectively. * * For backwards compatibility, ill-formatted values are handled as follows: * - No leading digits: value is treated as '0' * - Invalid multiplier: multiplier is ignored * - Invalid characters between digits and multiplier: invalid characters are * ignored + * - Integer overflow: The result of the overflow is returned * * In any of these cases an error string is stored in *errstr (caller must * release it), otherwise *errstr is set to NULL. */ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr); +/** + * Unsigned variant of zend_ini_parse_quantity + */ +ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr); + ZEND_API zend_result zend_ini_register_displayer(const char *name, uint32_t name_length, void (*displayer)(zend_ini_entry *ini_entry, int type)); ZEND_API ZEND_INI_DISP(zend_ini_boolean_displayer_cb); diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 11b35b91590e5..33a0e62e505dc 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -397,6 +397,23 @@ static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity) } } +static ZEND_FUNCTION(zend_test_zend_ini_parse_uquantity) +{ + zend_string *str; + zend_string *errstr; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + RETVAL_LONG((zend_long)zend_ini_parse_uquantity(str, &errstr)); + + if (errstr) { + zend_error(E_WARNING, "%s", ZSTR_VAL(errstr)); + zend_string_release(errstr); + } +} + static ZEND_FUNCTION(namespaced_func) { ZEND_PARSE_PARAMETERS_NONE(); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index dc9b70342d882..13b2fd346e7b1 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -127,6 +127,7 @@ function zend_get_current_func_name(): string {} function zend_call_method(object|string $obj_or_class, string $method, mixed $arg1 = UNKNOWN, mixed $arg2 = UNKNOWN): mixed {} function zend_test_zend_ini_parse_quantity(string $str): int {} + function zend_test_zend_ini_parse_uquantity(string $str): int {} } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index e8598770675a1..8c8e67d26954a 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a2f8ee1cf97ba226439c025ba7257dd181644489 */ + * Stub hash: 1a23b7473e5b4525352445545c6b3ab374c4e949 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -89,6 +89,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_zend_ini_parse_quantit ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_END_ARG_INFO() +#define arginfo_zend_test_zend_ini_parse_uquantity arginfo_zend_test_zend_ini_parse_quantity + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_ZendSubNS_namespaced_func, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -151,6 +153,7 @@ static ZEND_FUNCTION(zend_test_parameter_with_attribute); static ZEND_FUNCTION(zend_get_current_func_name); static ZEND_FUNCTION(zend_call_method); static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity); +static ZEND_FUNCTION(zend_test_zend_ini_parse_uquantity); static ZEND_FUNCTION(namespaced_func); static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); @@ -192,6 +195,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_get_current_func_name, arginfo_zend_get_current_func_name) ZEND_FE(zend_call_method, arginfo_zend_call_method) ZEND_FE(zend_test_zend_ini_parse_quantity, arginfo_zend_test_zend_ini_parse_quantity) + ZEND_FE(zend_test_zend_ini_parse_uquantity, arginfo_zend_test_zend_ini_parse_uquantity) ZEND_NS_FE("ZendTestNS2\\ZendSubNS", namespaced_func, arginfo_ZendTestNS2_ZendSubNS_namespaced_func) ZEND_FE_END }; diff --git a/main/main.c b/main/main.c index b79b419546839..ebb97a3542161 100644 --- a/main/main.c +++ b/main/main.c @@ -264,7 +264,7 @@ static PHP_INI_MH(OnChangeMemoryLimit) size_t value; zend_string *errstr; if (new_value) { - value = zend_ini_parse_quantity(new_value, &errstr); + value = zend_ini_parse_uquantity(new_value, &errstr); if (errstr) { zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); zend_string_release(errstr); From 5ee34a5c563bf0781c9d58a84329198391f6e372 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sun, 5 Jun 2022 21:33:03 +0200 Subject: [PATCH 08/17] Symbol visibility --- Zend/zend_ini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 55673e602733f..3214e01a62065 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -703,7 +703,7 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err } /* }}} */ -zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr) /* {{{ */ +ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr) /* {{{ */ { return (zend_ulong) zend_ini_parse_quantity_internal(value, false, errstr); } From cc1b7f096e41c27dc1e0da63b33f83d82f70442b Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 10 Jun 2022 13:31:23 +0200 Subject: [PATCH 09/17] Tests --- Zend/tests/zend_ini_parse_quantity.phpt | 977 +++++++++++------- Zend/tests/zend_ini_parse_quantity_error.phpt | 60 +- Zend/tests/zend_ini_parse_quantity_null.phpt | 30 - .../zend_ini_parse_quantity_overflow.phpt | 85 ++ .../zend_ini_parse_uquantity_overflow.phpt | 113 ++ 5 files changed, 838 insertions(+), 427 deletions(-) delete mode 100644 Zend/tests/zend_ini_parse_quantity_null.phpt create mode 100644 Zend/tests/zend_ini_parse_quantity_overflow.phpt create mode 100644 Zend/tests/zend_ini_parse_uquantity_overflow.phpt diff --git a/Zend/tests/zend_ini_parse_quantity.phpt b/Zend/tests/zend_ini_parse_quantity.phpt index e563e779065db..09f0a731452b8 100644 --- a/Zend/tests/zend_ini_parse_quantity.phpt +++ b/Zend/tests/zend_ini_parse_quantity.phpt @@ -1,5 +1,5 @@ --TEST-- -Test parsing of quantities (e.g. "16M") +Test parsing of quantities --EXTENSIONS-- zend_test --FILE-- @@ -14,689 +14,884 @@ foreach (['', ' '] as $leadingWS) { // Decimal $setting = sprintf('%s%s1%s%s%s', $leadingWS, $sign, $midWS, $exp, $trailingWS); - var_dump($setting); + printf("# \"%s\"\n", $setting); var_dump(zend_test_zend_ini_parse_quantity($setting)); + print "\n"; - // Octal - $setting = sprintf('%s%s0123%s%s%s', - $leadingWS, $sign, $midWS, $exp, $trailingWS); - var_dump($setting); - var_dump(zend_test_zend_ini_parse_quantity($setting)); + if ($exp !== 'g' && $exp !== 'G') { // Would overflow + // Octal + $setting = sprintf('%s%s0123%s%s%s', + $leadingWS, $sign, $midWS, $exp, $trailingWS); + printf("# \"%s\"\n", $setting); + var_dump(zend_test_zend_ini_parse_quantity($setting)); + print "\n"; + } } } } } } --EXPECT-- -string(1) "1" +# "1" int(1) -string(4) "0123" + +# "0123" int(83) -string(2) "1 " + +# "1 " int(1) -string(5) "0123 " + +# "0123 " int(83) -string(2) "1K" + +# "1K" int(1024) -string(5) "0123K" + +# "0123K" int(84992) -string(3) "1K " + +# "1K " int(1024) -string(6) "0123K " + +# "0123K " int(84992) -string(2) "1k" + +# "1k" int(1024) -string(5) "0123k" + +# "0123k" int(84992) -string(3) "1k " + +# "1k " int(1024) -string(6) "0123k " + +# "0123k " int(84992) -string(2) "1M" + +# "1M" int(1048576) -string(5) "0123M" + +# "0123M" int(87031808) -string(3) "1M " + +# "1M " int(1048576) -string(6) "0123M " + +# "0123M " int(87031808) -string(2) "1m" + +# "1m" int(1048576) -string(5) "0123m" + +# "0123m" int(87031808) -string(3) "1m " + +# "1m " int(1048576) -string(6) "0123m " + +# "0123m " int(87031808) -string(2) "1G" + +# "1G" int(1073741824) -string(5) "0123G" -int(89120571392) -string(3) "1G " + +# "1G " int(1073741824) -string(6) "0123G " -int(89120571392) -string(2) "1g" + +# "1g" int(1073741824) -string(5) "0123g" -int(89120571392) -string(3) "1g " + +# "1g " int(1073741824) -string(6) "0123g " -int(89120571392) -string(2) "1 " + +# "1 " int(1) -string(5) "0123 " + +# "0123 " int(83) -string(3) "1 " + +# "1 " int(1) -string(6) "0123 " + +# "0123 " int(83) -string(3) "1 K" + +# "1 K" int(1024) -string(6) "0123 K" + +# "0123 K" int(84992) -string(4) "1 K " + +# "1 K " int(1024) -string(7) "0123 K " + +# "0123 K " int(84992) -string(3) "1 k" + +# "1 k" int(1024) -string(6) "0123 k" + +# "0123 k" int(84992) -string(4) "1 k " + +# "1 k " int(1024) -string(7) "0123 k " + +# "0123 k " int(84992) -string(3) "1 M" + +# "1 M" int(1048576) -string(6) "0123 M" + +# "0123 M" int(87031808) -string(4) "1 M " + +# "1 M " int(1048576) -string(7) "0123 M " + +# "0123 M " int(87031808) -string(3) "1 m" + +# "1 m" int(1048576) -string(6) "0123 m" + +# "0123 m" int(87031808) -string(4) "1 m " + +# "1 m " int(1048576) -string(7) "0123 m " + +# "0123 m " int(87031808) -string(3) "1 G" + +# "1 G" int(1073741824) -string(6) "0123 G" -int(89120571392) -string(4) "1 G " + +# "1 G " int(1073741824) -string(7) "0123 G " -int(89120571392) -string(3) "1 g" + +# "1 g" int(1073741824) -string(6) "0123 g" -int(89120571392) -string(4) "1 g " + +# "1 g " int(1073741824) -string(7) "0123 g " -int(89120571392) -string(2) "+1" + +# "+1" int(1) -string(5) "+0123" + +# "+0123" int(83) -string(3) "+1 " + +# "+1 " int(1) -string(6) "+0123 " + +# "+0123 " int(83) -string(3) "+1K" + +# "+1K" int(1024) -string(6) "+0123K" + +# "+0123K" int(84992) -string(4) "+1K " + +# "+1K " int(1024) -string(7) "+0123K " + +# "+0123K " int(84992) -string(3) "+1k" + +# "+1k" int(1024) -string(6) "+0123k" + +# "+0123k" int(84992) -string(4) "+1k " + +# "+1k " int(1024) -string(7) "+0123k " + +# "+0123k " int(84992) -string(3) "+1M" + +# "+1M" int(1048576) -string(6) "+0123M" + +# "+0123M" int(87031808) -string(4) "+1M " + +# "+1M " int(1048576) -string(7) "+0123M " + +# "+0123M " int(87031808) -string(3) "+1m" + +# "+1m" int(1048576) -string(6) "+0123m" + +# "+0123m" int(87031808) -string(4) "+1m " + +# "+1m " int(1048576) -string(7) "+0123m " + +# "+0123m " int(87031808) -string(3) "+1G" + +# "+1G" int(1073741824) -string(6) "+0123G" -int(89120571392) -string(4) "+1G " + +# "+1G " int(1073741824) -string(7) "+0123G " -int(89120571392) -string(3) "+1g" + +# "+1g" int(1073741824) -string(6) "+0123g" -int(89120571392) -string(4) "+1g " + +# "+1g " int(1073741824) -string(7) "+0123g " -int(89120571392) -string(3) "+1 " + +# "+1 " int(1) -string(6) "+0123 " + +# "+0123 " int(83) -string(4) "+1 " + +# "+1 " int(1) -string(7) "+0123 " + +# "+0123 " int(83) -string(4) "+1 K" + +# "+1 K" int(1024) -string(7) "+0123 K" + +# "+0123 K" int(84992) -string(5) "+1 K " + +# "+1 K " int(1024) -string(8) "+0123 K " + +# "+0123 K " int(84992) -string(4) "+1 k" + +# "+1 k" int(1024) -string(7) "+0123 k" + +# "+0123 k" int(84992) -string(5) "+1 k " + +# "+1 k " int(1024) -string(8) "+0123 k " + +# "+0123 k " int(84992) -string(4) "+1 M" + +# "+1 M" int(1048576) -string(7) "+0123 M" + +# "+0123 M" int(87031808) -string(5) "+1 M " + +# "+1 M " int(1048576) -string(8) "+0123 M " + +# "+0123 M " int(87031808) -string(4) "+1 m" + +# "+1 m" int(1048576) -string(7) "+0123 m" + +# "+0123 m" int(87031808) -string(5) "+1 m " + +# "+1 m " int(1048576) -string(8) "+0123 m " + +# "+0123 m " int(87031808) -string(4) "+1 G" + +# "+1 G" int(1073741824) -string(7) "+0123 G" -int(89120571392) -string(5) "+1 G " + +# "+1 G " int(1073741824) -string(8) "+0123 G " -int(89120571392) -string(4) "+1 g" + +# "+1 g" int(1073741824) -string(7) "+0123 g" -int(89120571392) -string(5) "+1 g " + +# "+1 g " int(1073741824) -string(8) "+0123 g " -int(89120571392) -string(2) "-1" + +# "-1" int(-1) -string(5) "-0123" + +# "-0123" int(-83) -string(3) "-1 " + +# "-1 " int(-1) -string(6) "-0123 " + +# "-0123 " int(-83) -string(3) "-1K" + +# "-1K" int(-1024) -string(6) "-0123K" + +# "-0123K" int(-84992) -string(4) "-1K " + +# "-1K " int(-1024) -string(7) "-0123K " + +# "-0123K " int(-84992) -string(3) "-1k" + +# "-1k" int(-1024) -string(6) "-0123k" + +# "-0123k" int(-84992) -string(4) "-1k " + +# "-1k " int(-1024) -string(7) "-0123k " + +# "-0123k " int(-84992) -string(3) "-1M" + +# "-1M" int(-1048576) -string(6) "-0123M" + +# "-0123M" int(-87031808) -string(4) "-1M " + +# "-1M " int(-1048576) -string(7) "-0123M " + +# "-0123M " int(-87031808) -string(3) "-1m" + +# "-1m" int(-1048576) -string(6) "-0123m" + +# "-0123m" int(-87031808) -string(4) "-1m " + +# "-1m " int(-1048576) -string(7) "-0123m " + +# "-0123m " int(-87031808) -string(3) "-1G" + +# "-1G" int(-1073741824) -string(6) "-0123G" -int(-89120571392) -string(4) "-1G " + +# "-1G " int(-1073741824) -string(7) "-0123G " -int(-89120571392) -string(3) "-1g" + +# "-1g" int(-1073741824) -string(6) "-0123g" -int(-89120571392) -string(4) "-1g " + +# "-1g " int(-1073741824) -string(7) "-0123g " -int(-89120571392) -string(3) "-1 " + +# "-1 " int(-1) -string(6) "-0123 " + +# "-0123 " int(-83) -string(4) "-1 " + +# "-1 " int(-1) -string(7) "-0123 " + +# "-0123 " int(-83) -string(4) "-1 K" + +# "-1 K" int(-1024) -string(7) "-0123 K" + +# "-0123 K" int(-84992) -string(5) "-1 K " + +# "-1 K " int(-1024) -string(8) "-0123 K " + +# "-0123 K " int(-84992) -string(4) "-1 k" + +# "-1 k" int(-1024) -string(7) "-0123 k" + +# "-0123 k" int(-84992) -string(5) "-1 k " + +# "-1 k " int(-1024) -string(8) "-0123 k " + +# "-0123 k " int(-84992) -string(4) "-1 M" + +# "-1 M" int(-1048576) -string(7) "-0123 M" + +# "-0123 M" int(-87031808) -string(5) "-1 M " + +# "-1 M " int(-1048576) -string(8) "-0123 M " + +# "-0123 M " int(-87031808) -string(4) "-1 m" + +# "-1 m" int(-1048576) -string(7) "-0123 m" + +# "-0123 m" int(-87031808) -string(5) "-1 m " + +# "-1 m " int(-1048576) -string(8) "-0123 m " + +# "-0123 m " int(-87031808) -string(4) "-1 G" + +# "-1 G" int(-1073741824) -string(7) "-0123 G" -int(-89120571392) -string(5) "-1 G " + +# "-1 G " int(-1073741824) -string(8) "-0123 G " -int(-89120571392) -string(4) "-1 g" + +# "-1 g" int(-1073741824) -string(7) "-0123 g" -int(-89120571392) -string(5) "-1 g " + +# "-1 g " int(-1073741824) -string(8) "-0123 g " -int(-89120571392) -string(2) " 1" + +# " 1" int(1) -string(5) " 0123" + +# " 0123" int(83) -string(3) " 1 " + +# " 1 " int(1) -string(6) " 0123 " + +# " 0123 " int(83) -string(3) " 1K" + +# " 1K" int(1024) -string(6) " 0123K" + +# " 0123K" int(84992) -string(4) " 1K " + +# " 1K " int(1024) -string(7) " 0123K " + +# " 0123K " int(84992) -string(3) " 1k" + +# " 1k" int(1024) -string(6) " 0123k" + +# " 0123k" int(84992) -string(4) " 1k " + +# " 1k " int(1024) -string(7) " 0123k " + +# " 0123k " int(84992) -string(3) " 1M" + +# " 1M" int(1048576) -string(6) " 0123M" + +# " 0123M" int(87031808) -string(4) " 1M " + +# " 1M " int(1048576) -string(7) " 0123M " + +# " 0123M " int(87031808) -string(3) " 1m" + +# " 1m" int(1048576) -string(6) " 0123m" + +# " 0123m" int(87031808) -string(4) " 1m " + +# " 1m " int(1048576) -string(7) " 0123m " + +# " 0123m " int(87031808) -string(3) " 1G" + +# " 1G" int(1073741824) -string(6) " 0123G" -int(89120571392) -string(4) " 1G " + +# " 1G " int(1073741824) -string(7) " 0123G " -int(89120571392) -string(3) " 1g" + +# " 1g" int(1073741824) -string(6) " 0123g" -int(89120571392) -string(4) " 1g " + +# " 1g " int(1073741824) -string(7) " 0123g " -int(89120571392) -string(3) " 1 " + +# " 1 " int(1) -string(6) " 0123 " + +# " 0123 " int(83) -string(4) " 1 " + +# " 1 " int(1) -string(7) " 0123 " + +# " 0123 " int(83) -string(4) " 1 K" + +# " 1 K" int(1024) -string(7) " 0123 K" + +# " 0123 K" int(84992) -string(5) " 1 K " + +# " 1 K " int(1024) -string(8) " 0123 K " + +# " 0123 K " int(84992) -string(4) " 1 k" + +# " 1 k" int(1024) -string(7) " 0123 k" + +# " 0123 k" int(84992) -string(5) " 1 k " + +# " 1 k " int(1024) -string(8) " 0123 k " + +# " 0123 k " int(84992) -string(4) " 1 M" + +# " 1 M" int(1048576) -string(7) " 0123 M" + +# " 0123 M" int(87031808) -string(5) " 1 M " + +# " 1 M " int(1048576) -string(8) " 0123 M " + +# " 0123 M " int(87031808) -string(4) " 1 m" + +# " 1 m" int(1048576) -string(7) " 0123 m" + +# " 0123 m" int(87031808) -string(5) " 1 m " + +# " 1 m " int(1048576) -string(8) " 0123 m " + +# " 0123 m " int(87031808) -string(4) " 1 G" + +# " 1 G" int(1073741824) -string(7) " 0123 G" -int(89120571392) -string(5) " 1 G " + +# " 1 G " int(1073741824) -string(8) " 0123 G " -int(89120571392) -string(4) " 1 g" + +# " 1 g" int(1073741824) -string(7) " 0123 g" -int(89120571392) -string(5) " 1 g " + +# " 1 g " int(1073741824) -string(8) " 0123 g " -int(89120571392) -string(3) " +1" + +# " +1" int(1) -string(6) " +0123" + +# " +0123" int(83) -string(4) " +1 " + +# " +1 " int(1) -string(7) " +0123 " + +# " +0123 " int(83) -string(4) " +1K" + +# " +1K" int(1024) -string(7) " +0123K" + +# " +0123K" int(84992) -string(5) " +1K " + +# " +1K " int(1024) -string(8) " +0123K " + +# " +0123K " int(84992) -string(4) " +1k" + +# " +1k" int(1024) -string(7) " +0123k" + +# " +0123k" int(84992) -string(5) " +1k " + +# " +1k " int(1024) -string(8) " +0123k " + +# " +0123k " int(84992) -string(4) " +1M" + +# " +1M" int(1048576) -string(7) " +0123M" + +# " +0123M" int(87031808) -string(5) " +1M " + +# " +1M " int(1048576) -string(8) " +0123M " + +# " +0123M " int(87031808) -string(4) " +1m" + +# " +1m" int(1048576) -string(7) " +0123m" + +# " +0123m" int(87031808) -string(5) " +1m " + +# " +1m " int(1048576) -string(8) " +0123m " + +# " +0123m " int(87031808) -string(4) " +1G" + +# " +1G" int(1073741824) -string(7) " +0123G" -int(89120571392) -string(5) " +1G " + +# " +1G " int(1073741824) -string(8) " +0123G " -int(89120571392) -string(4) " +1g" + +# " +1g" int(1073741824) -string(7) " +0123g" -int(89120571392) -string(5) " +1g " + +# " +1g " int(1073741824) -string(8) " +0123g " -int(89120571392) -string(4) " +1 " + +# " +1 " int(1) -string(7) " +0123 " + +# " +0123 " int(83) -string(5) " +1 " + +# " +1 " int(1) -string(8) " +0123 " + +# " +0123 " int(83) -string(5) " +1 K" + +# " +1 K" int(1024) -string(8) " +0123 K" + +# " +0123 K" int(84992) -string(6) " +1 K " + +# " +1 K " int(1024) -string(9) " +0123 K " + +# " +0123 K " int(84992) -string(5) " +1 k" + +# " +1 k" int(1024) -string(8) " +0123 k" + +# " +0123 k" int(84992) -string(6) " +1 k " + +# " +1 k " int(1024) -string(9) " +0123 k " + +# " +0123 k " int(84992) -string(5) " +1 M" + +# " +1 M" int(1048576) -string(8) " +0123 M" + +# " +0123 M" int(87031808) -string(6) " +1 M " + +# " +1 M " int(1048576) -string(9) " +0123 M " + +# " +0123 M " int(87031808) -string(5) " +1 m" + +# " +1 m" int(1048576) -string(8) " +0123 m" + +# " +0123 m" int(87031808) -string(6) " +1 m " + +# " +1 m " int(1048576) -string(9) " +0123 m " + +# " +0123 m " int(87031808) -string(5) " +1 G" + +# " +1 G" int(1073741824) -string(8) " +0123 G" -int(89120571392) -string(6) " +1 G " + +# " +1 G " int(1073741824) -string(9) " +0123 G " -int(89120571392) -string(5) " +1 g" + +# " +1 g" int(1073741824) -string(8) " +0123 g" -int(89120571392) -string(6) " +1 g " + +# " +1 g " int(1073741824) -string(9) " +0123 g " -int(89120571392) -string(3) " -1" + +# " -1" int(-1) -string(6) " -0123" + +# " -0123" int(-83) -string(4) " -1 " + +# " -1 " int(-1) -string(7) " -0123 " + +# " -0123 " int(-83) -string(4) " -1K" + +# " -1K" int(-1024) -string(7) " -0123K" + +# " -0123K" int(-84992) -string(5) " -1K " + +# " -1K " int(-1024) -string(8) " -0123K " + +# " -0123K " int(-84992) -string(4) " -1k" + +# " -1k" int(-1024) -string(7) " -0123k" + +# " -0123k" int(-84992) -string(5) " -1k " + +# " -1k " int(-1024) -string(8) " -0123k " + +# " -0123k " int(-84992) -string(4) " -1M" + +# " -1M" int(-1048576) -string(7) " -0123M" + +# " -0123M" int(-87031808) -string(5) " -1M " + +# " -1M " int(-1048576) -string(8) " -0123M " + +# " -0123M " int(-87031808) -string(4) " -1m" + +# " -1m" int(-1048576) -string(7) " -0123m" + +# " -0123m" int(-87031808) -string(5) " -1m " + +# " -1m " int(-1048576) -string(8) " -0123m " + +# " -0123m " int(-87031808) -string(4) " -1G" + +# " -1G" int(-1073741824) -string(7) " -0123G" -int(-89120571392) -string(5) " -1G " + +# " -1G " int(-1073741824) -string(8) " -0123G " -int(-89120571392) -string(4) " -1g" + +# " -1g" int(-1073741824) -string(7) " -0123g" -int(-89120571392) -string(5) " -1g " + +# " -1g " int(-1073741824) -string(8) " -0123g " -int(-89120571392) -string(4) " -1 " + +# " -1 " int(-1) -string(7) " -0123 " + +# " -0123 " int(-83) -string(5) " -1 " + +# " -1 " int(-1) -string(8) " -0123 " + +# " -0123 " int(-83) -string(5) " -1 K" + +# " -1 K" int(-1024) -string(8) " -0123 K" + +# " -0123 K" int(-84992) -string(6) " -1 K " + +# " -1 K " int(-1024) -string(9) " -0123 K " + +# " -0123 K " int(-84992) -string(5) " -1 k" + +# " -1 k" int(-1024) -string(8) " -0123 k" + +# " -0123 k" int(-84992) -string(6) " -1 k " + +# " -1 k " int(-1024) -string(9) " -0123 k " + +# " -0123 k " int(-84992) -string(5) " -1 M" + +# " -1 M" int(-1048576) -string(8) " -0123 M" + +# " -0123 M" int(-87031808) -string(6) " -1 M " + +# " -1 M " int(-1048576) -string(9) " -0123 M " + +# " -0123 M " int(-87031808) -string(5) " -1 m" + +# " -1 m" int(-1048576) -string(8) " -0123 m" + +# " -0123 m" int(-87031808) -string(6) " -1 m " + +# " -1 m " int(-1048576) -string(9) " -0123 m " + +# " -0123 m " int(-87031808) -string(5) " -1 G" + +# " -1 G" int(-1073741824) -string(8) " -0123 G" -int(-89120571392) -string(6) " -1 G " + +# " -1 G " int(-1073741824) -string(9) " -0123 G " -int(-89120571392) -string(5) " -1 g" + +# " -1 g" int(-1073741824) -string(8) " -0123 g" -int(-89120571392) -string(6) " -1 g " + +# " -1 g " int(-1073741824) -string(9) " -0123 g " -int(-89120571392) diff --git a/Zend/tests/zend_ini_parse_quantity_error.phpt b/Zend/tests/zend_ini_parse_quantity_error.phpt index 06b732ce315e4..2fc1ad76f0d23 100644 --- a/Zend/tests/zend_ini_parse_quantity_error.phpt +++ b/Zend/tests/zend_ini_parse_quantity_error.phpt @@ -1,5 +1,5 @@ --TEST-- -Test parsing of quantities (e.g. "16M"): errors +Test parsing of quantities: errors --EXTENSIONS-- zend_test --FILE-- @@ -8,24 +8,72 @@ zend_test // This test checks invalid formats do throw warnings. $tests = [ - 'K', # No digits - '1KM', # Multiple multipliers. - '1X', # Unknown multiplier. - '1.0K', # Non integral digits. + 'K', # No digits + '1KM', # Multiple multipliers. + '1X', # Unknown multiplier. + '1.0K', # Non integral digits. + + # Null bytes + " 123\x00K", + "\x00 123K", + " \x00123K", + " 123\x00K", + " 123K\x00", + " 123\x00", ]; foreach ($tests as $setting) { - var_dump(zend_test_zend_ini_parse_quantity($setting)); + printf("# \"%s\"\n", addcslashes($setting, "\0..\37!@\177..\377")); + var_dump(zend_test_zend_ini_parse_quantity($setting)); + print "\n"; } --EXPECTF-- +# "K" + Warning: Invalid quantity "K": no valid leading digits, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(0) +# "1KM" + Warning: Invalid quantity "1KM", interpreting as "1M" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1048576) +# "1X" + Warning: Invalid quantity "1X": unknown multipler "X", interpreting as "1" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1) +# "1.0K" + Warning: Invalid quantity "1.0K", interpreting as "1K" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1024) + +# " 123\000K" + +Warning: Invalid quantity " 123\x00K", interpreting as " 123K" for backwards compatibility in %s on line %d +int(125952) + +# "\000 123K" + +Warning: Invalid quantity "\x00 123K": no valid leading digits, interpreting as "0" for backwards compatibility in %s on line %d +int(0) + +# " \000123K" + +Warning: Invalid quantity " \x00123K": no valid leading digits, interpreting as "0" for backwards compatibility in %s on line %d +int(0) + +# " 123\000K" + +Warning: Invalid quantity " 123\x00K", interpreting as " 123K" for backwards compatibility in %s on line %d +int(125952) + +# " 123K\000" + +Warning: Invalid quantity " 123K\x00": unknown multipler "\x00", interpreting as " 123" for backwards compatibility in %s on line %d +int(123) + +# " 123\000" + +Warning: Invalid quantity " 123\x00": unknown multipler "\x00", interpreting as " 123" for backwards compatibility in %s on line %d +int(123) diff --git a/Zend/tests/zend_ini_parse_quantity_null.phpt b/Zend/tests/zend_ini_parse_quantity_null.phpt deleted file mode 100644 index 7be19da6138c0..0000000000000 --- a/Zend/tests/zend_ini_parse_quantity_null.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -Test parsing of quantities with null byte ---FILE-- - '0', + 'No overflow 002' => '1', + 'No overflow 002' => '100', + 'No overflow 003' => strval(PHP_INT_MAX), + 'No overflow 004' => strval(PHP_INT_MIN), + 'No overflow 005' => '2K', + 'No overflow 006' => '-2K', + 'Subject overflow 001' => increment(strval(PHP_INT_MAX)), + 'Subject overflow 002' => decrement(strval(PHP_INT_MIN)), + 'Multiplier overflow 001' => strval(PHP_INT_MAX).'K', + 'Multiplier overflow 002' => strval(PHP_INT_MIN).'K', +]; + +foreach ($tests as $name => $value) { + printf("# %s: \"%s\"\n", $name, $value); + printf("%u\n", zend_test_zend_ini_parse_quantity($value)); + print "\n"; +} + +--EXPECTF-- +# No overflow 001: "0" +0 + +# No overflow 002: "100" +100 + +# No overflow 003: "%d" +%d + +# No overflow 004: "-%d" +%d + +# No overflow 005: "2K" +2048 + +# No overflow 006: "-2K" +%d + +# Subject overflow 001: "%d" + +Warning: Invalid quantity "%d": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +# Subject overflow 002: "-%d" + +Warning: Invalid quantity "-%d": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +# Multiplier overflow 001: "%dK" + +Warning: Invalid quantity "%dK": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +# Multiplier overflow 002: "-%dK" + +Warning: Invalid quantity "-%dK": value is out of range, using overflow result for backwards compatibility in %s on line %d +0 diff --git a/Zend/tests/zend_ini_parse_uquantity_overflow.phpt b/Zend/tests/zend_ini_parse_uquantity_overflow.phpt new file mode 100644 index 0000000000000..d50e667c9ebe8 --- /dev/null +++ b/Zend/tests/zend_ini_parse_uquantity_overflow.phpt @@ -0,0 +1,113 @@ +--TEST-- +Test zend_ini_parse_uquantity() overflow handling +--EXTENSIONS-- +zend_test +--FILE-- + '0', + 'No overflow 002' => '1', + 'No overflow 002' => '100', + 'No overflow 003' => strval(PHP_INT_MAX), + 'No overflow 004' => '2K', + 'No overflow 005' => '-1', + 'No overflow 006' => ' -1', + 'No overflow 007' => '-1 ', + 'No overflow 008' => ' -1 ', + 'Subject overflow 001' => base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10), + 'Subject overflow 002' => '-'.base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10), + 'Subject overflow 003' => strval(PHP_INT_MIN), + 'Subject overflow 004' => '-2', + 'Subject overflow 005' => '-1K', + 'Subject overflow 006' => '-1 K', + 'Multiplier overflow 001' => strval(PHP_INT_MAX).'K', +]; + +foreach ($tests as $name => $value) { + printf("# %s: \"%s\"\n", $name, $value); + printf("%u\n", zend_test_zend_ini_parse_uquantity($value)); + echo "\n"; + echo "----------\n"; +} + +printf("# zend_test_zend_ini_parse_uquantity(\"-1\") === -1\n"); +var_dump(zend_test_zend_ini_parse_uquantity("-1") === -1); + +--EXPECTF-- +# No overflow 001: "0" +0 + +---------- +# No overflow 002: "100" +100 + +---------- +# No overflow 003: "%d" +%d + +---------- +# No overflow 004: "2K" +2048 + +---------- +# No overflow 005: "-1" +%d + +---------- +# No overflow 006: " -1" +%d + +---------- +# No overflow 007: "-1 " +%d + +---------- +# No overflow 008: " -1 " +%d + +---------- +# Subject overflow 001: "%d" + +Warning: Invalid quantity "%d": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +---------- +# Subject overflow 002: "-%d" + +Warning: Invalid quantity "-%d": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +---------- +# Subject overflow 003: "-%d" + +Warning: Invalid quantity "-%d": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +---------- +# Subject overflow 004: "-2" + +Warning: Invalid quantity "-2": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +---------- +# Subject overflow 005: "-1K" + +Warning: Invalid quantity "-1K": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +---------- +# Subject overflow 006: "-1 K" + +Warning: Invalid quantity "-1 K": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +---------- +# Multiplier overflow 001: "%dK" + +Warning: Invalid quantity "%dK": value is out of range, using overflow result for backwards compatibility in %s on line %d +%d + +---------- +# zend_test_zend_ini_parse_uquantity("-1") === -1 +bool(true) From a2a87faff8a90e50a23f86a631cc9f1122e09a15 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 10 Jun 2022 14:09:10 +0200 Subject: [PATCH 10/17] Add comment --- ext/standard/basic_functions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index b50996f4e760e..5123174569fa3 100755 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -2506,6 +2506,7 @@ static void php_simple_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int cal break; } + /* entry in the form x[a]=b where x might need to be an array index */ if (!(Z_STRLEN_P(arg1) > 1 && Z_STRVAL_P(arg1)[0] == '0') && is_numeric_string(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), NULL, NULL, 0) == IS_LONG) { zend_ulong key = (zend_ulong) ZEND_STRTOUL(Z_STRVAL_P(arg1), NULL, 0); if ((find_hash = zend_hash_index_find(Z_ARRVAL_P(arr), key)) == NULL) { From 54b1952909c5b21e699dc20b1fc7c4605b174de0 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 10 Jun 2022 15:10:12 +0200 Subject: [PATCH 11/17] Deduplicate warnings --- ...zend_ini_parse_quantity_ini_set_error.phpt | 2 +- Zend/zend.c | 14 +------ Zend/zend_ini.c | 42 +++++++++++++------ Zend/zend_ini.h | 4 ++ ext/bcmath/bcmath.c | 7 +--- ext/opcache/zend_accelerator_module.c | 35 +++------------- ext/zlib/zlib.c | 7 +--- main/main.c | 7 +--- 8 files changed, 45 insertions(+), 73 deletions(-) diff --git a/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt b/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt index 98e059e306135..1e0f5f9e8a29f 100644 --- a/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt +++ b/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt @@ -8,6 +8,6 @@ zend_test var_dump(ini_set("zend_test.quantity_value", "1MB")); var_dump(ini_get("zend_test.quantity_value")); --EXPECTF-- -Warning: Invalid "zend_test.quantity_value" setting: Invalid quantity "1MB": unknown multipler "B", interpreting as "1" for backwards compatibility in %s on line %d +Warning: Invalid "zend_test.quantity_value" setting. Invalid quantity "1MB": unknown multipler "B", interpreting as "1" for backwards compatibility in %s on line %d string(1) "0" string(3) "1MB" diff --git a/Zend/zend.c b/Zend/zend.c index 5ae49a9320a47..7d0eacda58c65 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -145,13 +145,8 @@ static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */ static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */ { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); - zend_string *errstr; - zend_long val = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); if (stage != ZEND_INI_STAGE_STARTUP && stage != ZEND_INI_STAGE_SHUTDOWN && @@ -180,13 +175,8 @@ static ZEND_INI_MH(OnSetExceptionStringParamMaxLen) /* {{{ */ static ZEND_INI_MH(OnUpdateFiberStackSize) /* {{{ */ { - zend_string *errstr; if (new_value) { - EG(fiber_stack_size) = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + EG(fiber_stack_size) = zend_ini_parse_quantity_warn(new_value, entry->name); } else { EG(fiber_stack_size) = ZEND_FIBER_DEFAULT_C_STACK_SIZE; } diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 3214e01a62065..7ce85b209f117 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -709,6 +709,34 @@ ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **e } /* }}} */ +ZEND_API zend_long zend_ini_parse_quantity_warn(zend_string *value, zend_string *setting) /* {{{ */ +{ + zend_string *errstr; + zend_long retval = zend_ini_parse_quantity(value, &errstr); + + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting. %s", ZSTR_VAL(setting), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } + + return retval; +} +/* }}} */ + +ZEND_API zend_long zend_ini_parse_uquantity_warn(zend_string *value, zend_string *setting) /* {{{ */ +{ + zend_string *errstr; + zend_long retval = zend_ini_parse_uquantity(value, &errstr); + + if (errstr) { + zend_error(E_WARNING, "Invalid \"%s\" setting. %s", ZSTR_VAL(setting), ZSTR_VAL(errstr)); + zend_string_release(errstr); + } + + return retval; +} +/* }}} */ + ZEND_INI_DISP(zend_ini_boolean_displayer_cb) /* {{{ */ { int value; @@ -797,24 +825,14 @@ ZEND_API ZEND_INI_MH(OnUpdateBool) /* {{{ */ ZEND_API ZEND_INI_MH(OnUpdateLong) /* {{{ */ { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); - zend_string *errstr; - *p = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + *p = zend_ini_parse_quantity_warn(new_value, entry->name); return SUCCESS; } /* }}} */ ZEND_API ZEND_INI_MH(OnUpdateLongGEZero) /* {{{ */ { - zend_string *errstr; - zend_long tmp = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + zend_long tmp = zend_ini_parse_quantity_warn(new_value, entry->name); if (tmp < 0) { return FAILURE; } diff --git a/Zend/zend_ini.h b/Zend/zend_ini.h index 9bb119ac0fc51..5f6847f11a132 100644 --- a/Zend/zend_ini.h +++ b/Zend/zend_ini.h @@ -132,6 +132,10 @@ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **err */ ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr); +ZEND_API zend_long zend_ini_parse_quantity_warn(zend_string *value, zend_string *setting); + +ZEND_API zend_long zend_ini_parse_uquantity_warn(zend_string *value, zend_string *setting); + ZEND_API zend_result zend_ini_register_displayer(const char *name, uint32_t name_length, void (*displayer)(zend_ini_entry *ini_entry, int type)); ZEND_API ZEND_INI_DISP(zend_ini_boolean_displayer_cb); diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index a35a58f5387c4..d6147269b0ebb 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -61,13 +61,8 @@ ZEND_INI_MH(OnUpdateScale) { int *p; zend_long tmp; - zend_string *errstr; - tmp = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + tmp = zend_ini_parse_quantity_warn(new_value, entry->name); if (tmp < 0 || tmp > INT_MAX) { return FAILURE; } diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 2067e04205602..564373964aa0f 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -165,12 +165,7 @@ static ZEND_INI_MH(OnUpdateJit) static ZEND_INI_MH(OnUpdateJitDebug) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); - zend_string *errstr; - zend_long val = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); if (zend_jit_debug_config(*p, val, stage) == SUCCESS) { *p = val; @@ -181,12 +176,7 @@ static ZEND_INI_MH(OnUpdateJitDebug) static ZEND_INI_MH(OnUpdateCounter) { - zend_string *errstr; - zend_long val = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); if (val >= 0 && val < 256) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); @@ -199,12 +189,7 @@ static ZEND_INI_MH(OnUpdateCounter) static ZEND_INI_MH(OnUpdateUnrollC) { - zend_string *errstr; - zend_long val = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); if (val > 0 && val < ZEND_JIT_TRACE_MAX_CALL_DEPTH) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); @@ -218,12 +203,7 @@ static ZEND_INI_MH(OnUpdateUnrollC) static ZEND_INI_MH(OnUpdateUnrollR) { - zend_string *errstr; - zend_long val = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); if (val >= 0 && val < ZEND_JIT_TRACE_MAX_RET_DEPTH) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); @@ -237,12 +217,7 @@ static ZEND_INI_MH(OnUpdateUnrollR) static ZEND_INI_MH(OnUpdateUnrollL) { - zend_string *errstr; - zend_long val = zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); if (val > 0 && val < ZEND_JIT_TRACE_MAX_LOOPS_UNROLL) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index a4caffc40f602..37e35eb8c277c 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1268,7 +1268,6 @@ static PHP_INI_MH(OnUpdate_zlib_output_compression) { int int_value; char *ini_value; - zend_string *errstr = NULL; if (new_value == NULL) { return FAILURE; } @@ -1278,11 +1277,7 @@ static PHP_INI_MH(OnUpdate_zlib_output_compression) } else if (zend_string_equals_literal_ci(new_value, "on")) { int_value = 1; } else { - int_value = (int) zend_ini_parse_quantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + int_value = (int) zend_ini_parse_quantity_warn(new_value, entry->name); } ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0); diff --git a/main/main.c b/main/main.c index ebb97a3542161..5c8a079e87de0 100644 --- a/main/main.c +++ b/main/main.c @@ -262,13 +262,8 @@ static PHP_INI_MH(OnSetSerializePrecision) static PHP_INI_MH(OnChangeMemoryLimit) { size_t value; - zend_string *errstr; if (new_value) { - value = zend_ini_parse_uquantity(new_value, &errstr); - if (errstr) { - zend_error(E_WARNING, "Invalid \"%s\" setting: %s", ZSTR_VAL(entry->name), ZSTR_VAL(errstr)); - zend_string_release(errstr); - } + value = zend_ini_parse_uquantity_warn(new_value, entry->name); } else { value = Z_L(1)<<30; /* effectively, no limit */ } From deaeded3080835ab99994f9e997d17161b1e7109 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 10 Jun 2022 15:14:56 +0200 Subject: [PATCH 12/17] [ci skip] UPGRADING --- UPGRADING | 85 +++++++++++++++++++++++++++++++++++++++++++++ UPGRADING.INTERNALS | 3 ++ 2 files changed, 88 insertions(+) diff --git a/UPGRADING b/UPGRADING index e28498efe9a80..7ae56581edad4 100644 --- a/UPGRADING +++ b/UPGRADING @@ -342,6 +342,91 @@ PHP 8.2 UPGRADE NOTES 11. Changes to INI File Handling ======================================== +- Parsing of some ill-formatted values will now trigger a warning when this was + silently ignored before. Interpretation of these values is not changed, for + backwards compatibility. This affects the following settings: + . bcmath.scale + . com.code_page + . default_socket_timeout + . fiber.stack_size + . hard_timeout + . intl.error_level + . ldap.max_links + . max_input_nesting_level + . max_input_vars + . mbstring.regex_retry_limit + . mbstring.regex_stack_limit + . mysqli.allow_local_infile + . mysqli.allow_persistent + . mysqli.default_port + . mysqli.max_links + . mysqli.max_persistent + . mysqli.reconnect + . mysqli.rollback_on_cached_plink + . mysqlnd.log_mask + . mysqlnd.mempool_default_size + . mysqlnd.net_read_buffer_size + . mysqlnd.net_read_timeout + . oci8.default_prefetch + . oci8.max_persistent + . oci8.persistent_timeout + . oci8.ping_interval + . oci8.prefetch_lob_size + . oci8.privileged_connect + . oci8.statement_cache_size + . odbc.allow_persistent + . odbc.check_persistent + . odbc.defaultbinmode + . odbc.default_cursortype + . odbc.defaultlrl + . odbc.max_links + . odbc.max_persistent + . opcache.consistency_checks + . opcache.file_update_protection + . opcache.force_restart_timeout + . opcache.interned_strings_buffer + . opcache.jit_bisect_limit + . opcache.jit_blacklist_root_trace + . opcache.jit_blacklist_side_trace + . opcache.jit_debug + . opcache.jit_hot_func + . opcache.jit_hot_loop + . opcache.jit_hot_return + . opcache.jit_hot_side_exit + . opcache.jit_max_exit_counters + . opcache.jit_max_loop_unrolls + . opcache.jit_max_polymorphic_calls + . opcache.jit_max_recursive_calls + . opcache.jit_max_recursive_returns + . opcache.jit_max_root_traces + . opcache.jit_max_side_traces + . opcache.log_verbosity_level + . opcache.max_file_size + . opcache.opt_debug_level + . opcache.optimization_level + . opcache.revalidate_freq + . output_buffering + . pcre.backtrack_limit + . pcre.recursion_limit + . pgsql.max_links + . pgsql.max_persistent + . post_max_size + . realpath_cache_size + . realpath_cache_ttl + . session.cache_expire + . session.cookie_lifetime + . session.gc_divisor + . session.gc_maxlifetime + . session.gc_probability + . soap.wsdl_cache_limit + . soap.wsdl_cache_ttl + . unserialize_max_depth + . upload_max_filesize + . user_ini.cache_ttl + . xmlrpc_error_number + . zend.assertions + . zlib.output_compression_level + ======================================== 12. Windows Support ======================================== diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 64cfbee3cf11b..e411bdba99031 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -29,6 +29,9 @@ PHP 8.2 INTERNALS UPGRADE NOTES * A new ZEND_THREEWAY_COMPARE() macro has been introduced which does a three-way comparison of two integers and returns -1, 0 or 1 if the LHS is smaller, equal or larger than the RHS +* Deprecated zend_atoi() and zend_atol(). Use ZEND_STRTOL() for general purpose + string to long conversion, or a variant of zend_ini_parse_quantity() for + parsing ini quantities. ======================== 2. Build system changes From c356791c89dccca476ecb49383c5d992291f331f Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 10 Jun 2022 15:46:51 +0200 Subject: [PATCH 13/17] WS --- ext/opcache/zend_accelerator_module.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 564373964aa0f..2271920b302c7 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -177,7 +177,6 @@ static ZEND_INI_MH(OnUpdateJitDebug) static ZEND_INI_MH(OnUpdateCounter) { zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); - if (val >= 0 && val < 256) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; @@ -190,7 +189,6 @@ static ZEND_INI_MH(OnUpdateCounter) static ZEND_INI_MH(OnUpdateUnrollC) { zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); - if (val > 0 && val < ZEND_JIT_TRACE_MAX_CALL_DEPTH) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; @@ -204,7 +202,6 @@ static ZEND_INI_MH(OnUpdateUnrollC) static ZEND_INI_MH(OnUpdateUnrollR) { zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); - if (val >= 0 && val < ZEND_JIT_TRACE_MAX_RET_DEPTH) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; @@ -218,7 +215,6 @@ static ZEND_INI_MH(OnUpdateUnrollR) static ZEND_INI_MH(OnUpdateUnrollL) { zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name); - if (val > 0 && val < ZEND_JIT_TRACE_MAX_LOOPS_UNROLL) { zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); *p = val; From 8f6c1b62359a841de7dcc29842fa458842821157 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 10 Jun 2022 16:52:03 +0200 Subject: [PATCH 14/17] Fix tests --- .../zend_ini_parse_quantity_overflow.phpt | 50 ++++++++++++------- .../zend_ini_parse_uquantity_overflow.phpt | 36 +++++++------ ext/opcache/tests/bug71843.phpt | 2 +- ext/opcache/tests/bug74431.phpt | 2 +- 4 files changed, 55 insertions(+), 35 deletions(-) diff --git a/Zend/tests/zend_ini_parse_quantity_overflow.phpt b/Zend/tests/zend_ini_parse_quantity_overflow.phpt index 2a065411cdb22..f50f67f94a95c 100644 --- a/Zend/tests/zend_ini_parse_quantity_overflow.phpt +++ b/Zend/tests/zend_ini_parse_quantity_overflow.phpt @@ -28,11 +28,11 @@ function decrement(string $s): string { $tests = [ 'No overflow 001' => '0', 'No overflow 002' => '1', - 'No overflow 002' => '100', - 'No overflow 003' => strval(PHP_INT_MAX), - 'No overflow 004' => strval(PHP_INT_MIN), - 'No overflow 005' => '2K', - 'No overflow 006' => '-2K', + 'No overflow 003' => '100', + 'No overflow 004' => strval(PHP_INT_MAX), + 'No overflow 005' => strval(PHP_INT_MIN), + 'No overflow 006' => '2K', + 'No overflow 007' => '-2K', 'Subject overflow 001' => increment(strval(PHP_INT_MAX)), 'Subject overflow 002' => decrement(strval(PHP_INT_MIN)), 'Multiplier overflow 001' => strval(PHP_INT_MAX).'K', @@ -41,45 +41,61 @@ $tests = [ foreach ($tests as $name => $value) { printf("# %s: \"%s\"\n", $name, $value); - printf("%u\n", zend_test_zend_ini_parse_quantity($value)); + printf("%d\n", zend_test_zend_ini_parse_quantity($value)); print "\n"; + print "----------\n"; } --EXPECTF-- # No overflow 001: "0" 0 -# No overflow 002: "100" +---------- +# No overflow 002: "1" +1 + +---------- +# No overflow 003: "100" 100 -# No overflow 003: "%d" +---------- +# No overflow 004: "%d" %d -# No overflow 004: "-%d" -%d +---------- +# No overflow 005: "-%d" +-%d -# No overflow 005: "2K" +---------- +# No overflow 006: "2K" 2048 -# No overflow 006: "-2K" -%d +---------- +# No overflow 007: "-2K" +-2048 +---------- # Subject overflow 001: "%d" Warning: Invalid quantity "%d": value is out of range, using overflow result for backwards compatibility in %s on line %d -%d +%s +---------- # Subject overflow 002: "-%d" Warning: Invalid quantity "-%d": value is out of range, using overflow result for backwards compatibility in %s on line %d -%d +%s +---------- # Multiplier overflow 001: "%dK" Warning: Invalid quantity "%dK": value is out of range, using overflow result for backwards compatibility in %s on line %d -%d +%s +---------- # Multiplier overflow 002: "-%dK" Warning: Invalid quantity "-%dK": value is out of range, using overflow result for backwards compatibility in %s on line %d -0 +%s + +---------- diff --git a/Zend/tests/zend_ini_parse_uquantity_overflow.phpt b/Zend/tests/zend_ini_parse_uquantity_overflow.phpt index d50e667c9ebe8..6dd3ed05076be 100644 --- a/Zend/tests/zend_ini_parse_uquantity_overflow.phpt +++ b/Zend/tests/zend_ini_parse_uquantity_overflow.phpt @@ -8,13 +8,13 @@ zend_test $tests = [ 'No overflow 001' => '0', 'No overflow 002' => '1', - 'No overflow 002' => '100', - 'No overflow 003' => strval(PHP_INT_MAX), - 'No overflow 004' => '2K', - 'No overflow 005' => '-1', - 'No overflow 006' => ' -1', - 'No overflow 007' => '-1 ', - 'No overflow 008' => ' -1 ', + 'No overflow 003' => '100', + 'No overflow 004' => strval(PHP_INT_MAX), + 'No overflow 005' => '2K', + 'No overflow 006' => '-1', + 'No overflow 007' => ' -1', + 'No overflow 008' => '-1 ', + 'No overflow 009' => ' -1 ', 'Subject overflow 001' => base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10), 'Subject overflow 002' => '-'.base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10), 'Subject overflow 003' => strval(PHP_INT_MIN), @@ -27,8 +27,8 @@ $tests = [ foreach ($tests as $name => $value) { printf("# %s: \"%s\"\n", $name, $value); printf("%u\n", zend_test_zend_ini_parse_uquantity($value)); - echo "\n"; - echo "----------\n"; + print "\n"; + print "----------\n"; } printf("# zend_test_zend_ini_parse_uquantity(\"-1\") === -1\n"); @@ -39,31 +39,35 @@ var_dump(zend_test_zend_ini_parse_uquantity("-1") === -1); 0 ---------- -# No overflow 002: "100" +# No overflow 002: "1" +1 + +---------- +# No overflow 003: "100" 100 ---------- -# No overflow 003: "%d" +# No overflow 004: "%d" %d ---------- -# No overflow 004: "2K" +# No overflow 005: "2K" 2048 ---------- -# No overflow 005: "-1" +# No overflow 006: "-1" %d ---------- -# No overflow 006: " -1" +# No overflow 007: " -1" %d ---------- -# No overflow 007: "-1 " +# No overflow 008: "-1 " %d ---------- -# No overflow 008: " -1 " +# No overflow 009: " -1 " %d ---------- diff --git a/ext/opcache/tests/bug71843.phpt b/ext/opcache/tests/bug71843.phpt index 66ccd823627f4..71756d3b7e87a 100644 --- a/ext/opcache/tests/bug71843.phpt +++ b/ext/opcache/tests/bug71843.phpt @@ -3,7 +3,7 @@ Bug #71843 (null ptr deref ZEND_RETURN_SPEC_CONST_HANDLER (zend_vm_execute.h:347 --INI-- opcache.enable=1 opcache.enable_cli=1 -opcache.optimization_level=0xFFFFBFFF +opcache.optimization_level=0x7FFFBFFF --EXTENSIONS-- opcache --FILE-- diff --git a/ext/opcache/tests/bug74431.phpt b/ext/opcache/tests/bug74431.phpt index bbfe0b9d6a551..87233ea02197a 100644 --- a/ext/opcache/tests/bug74431.phpt +++ b/ext/opcache/tests/bug74431.phpt @@ -3,7 +3,7 @@ Bug #74431 - foreach infinite loop --INI-- opcache.enable=1 opcache.enable_cli=1 -opcache.optimization_level=0xffffffff +opcache.optimization_level=0x7fffffff --EXTENSIONS-- opcache --FILE-- From 69e6ff46a120a2eeb602e8f22b628ee3d1e64db0 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 17 Jun 2022 11:38:31 +0200 Subject: [PATCH 15/17] Add test --- .../zend_ini_parse_quantity_ini_setting_error.phpt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Zend/tests/zend_ini_parse_quantity_ini_setting_error.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_ini_setting_error.phpt b/Zend/tests/zend_ini_parse_quantity_ini_setting_error.phpt new file mode 100644 index 0000000000000..4e939f09ddd23 --- /dev/null +++ b/Zend/tests/zend_ini_parse_quantity_ini_setting_error.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test ini setting with invalid quantity +--EXTENSIONS-- +zend_test +--INI-- +zend_test.quantity_value=1MB +--FILE-- + Date: Fri, 17 Jun 2022 12:02:41 +0200 Subject: [PATCH 16/17] Avoid boolean arg for clarity --- Zend/zend_ini.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 7ce85b209f117..7ff397c58c3da 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -541,7 +541,12 @@ ZEND_API bool zend_ini_parse_bool(zend_string *str) } } -static zend_long zend_ini_parse_quantity_internal(zend_string *value, bool signed_result, zend_string **errstr) /* {{{ */ +typedef enum { + ZEND_INI_PARSE_QUANTITY_SIGNED, + ZEND_INI_PARSE_QUANTITY_UNSIGNED, +} zend_ini_parse_quantity_signed_result_t; + +static zend_long zend_ini_parse_quantity_internal(zend_string *value, zend_ini_parse_quantity_signed_result_t signed_result, zend_string **errstr) /* {{{ */ { char *digits_end = NULL; char *str = ZSTR_VAL(value); @@ -568,7 +573,7 @@ static zend_long zend_ini_parse_quantity_internal(zend_string *value, bool signe zend_ulong retval; errno = 0; - if (signed_result) { + if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { retval = (zend_ulong) ZEND_STRTOL(digits, &digits_end, 0); } else { retval = ZEND_STRTOUL(digits, &digits_end, 0); @@ -576,7 +581,7 @@ static zend_long zend_ini_parse_quantity_internal(zend_string *value, bool signe if (errno == ERANGE) { overflow = true; - } else if (!signed_result) { + } else if (signed_result == ZEND_INI_PARSE_QUANTITY_UNSIGNED) { /* ZEND_STRTOUL() does not report a range error when the subject starts * with a minus sign, so we check this here. Ignore "-1" as it is * commonly used as max value, for instance in memory_limit=-1. */ @@ -641,7 +646,7 @@ static zend_long zend_ini_parse_quantity_internal(zend_string *value, bool signe } if (!overflow) { - if (signed_result) { + if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { zend_long sretval = (zend_long)retval; if (sretval > 0) { overflow = (zend_long)retval > ZEND_LONG_MAX / (zend_long)factor; @@ -689,23 +694,23 @@ static zend_long zend_ini_parse_quantity_internal(zend_string *value, bool signe smart_str_free(&interpreted); smart_str_free(&chr); - return (zend_long) retval; + return retval; } *errstr = NULL; - return (zend_long) retval; + return retval; } /* }}} */ ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr) /* {{{ */ { - return zend_ini_parse_quantity_internal(value, true, errstr); + return zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_SIGNED, errstr); } /* }}} */ ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr) /* {{{ */ { - return (zend_ulong) zend_ini_parse_quantity_internal(value, false, errstr); + return (zend_ulong) zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_UNSIGNED, errstr); } /* }}} */ From 1d4dfa5a9ec1bbe1a7d5d44e1be9e65ab2e4c026 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 17 Jun 2022 12:02:55 +0200 Subject: [PATCH 17/17] Avoid UB --- Zend/zend_ini.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 7ff397c58c3da..406de810e2b5c 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -546,7 +546,7 @@ typedef enum { ZEND_INI_PARSE_QUANTITY_UNSIGNED, } zend_ini_parse_quantity_signed_result_t; -static zend_long zend_ini_parse_quantity_internal(zend_string *value, zend_ini_parse_quantity_signed_result_t signed_result, zend_string **errstr) /* {{{ */ +static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_parse_quantity_signed_result_t signed_result, zend_string **errstr) /* {{{ */ { char *digits_end = NULL; char *str = ZSTR_VAL(value); @@ -676,7 +676,7 @@ static zend_long zend_ini_parse_quantity_internal(zend_string *value, zend_ini_p smart_str_free(&interpreted); smart_str_free(&chr); - return (zend_long) retval; + return retval; } end: @@ -704,13 +704,13 @@ static zend_long zend_ini_parse_quantity_internal(zend_string *value, zend_ini_p ZEND_API zend_long zend_ini_parse_quantity(zend_string *value, zend_string **errstr) /* {{{ */ { - return zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_SIGNED, errstr); + return (zend_long) zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_SIGNED, errstr); } /* }}} */ ZEND_API zend_ulong zend_ini_parse_uquantity(zend_string *value, zend_string **errstr) /* {{{ */ { - return (zend_ulong) zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_UNSIGNED, errstr); + return zend_ini_parse_quantity_internal(value, ZEND_INI_PARSE_QUANTITY_UNSIGNED, errstr); } /* }}} */