From addfbf62e1ddfed0b4a74db838301d9459ce4654 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Fri, 16 Sep 2022 16:53:43 +0100 Subject: [PATCH 1/5] Add support for binary, and octal number prefixes for INI settings This drops support for PHP_MIN_VALUE as we now need to manually change the sign of the result. Therefore the lowest possible value without overflow is PHP_MIN_VALUE+1. --- ...nd_ini_parse_quantity_binary_prefixes.phpt | 1037 +++++++++++++++++ .../zend_ini_parse_quantity_hex_prefixes.phpt | 1037 +++++++++++++++++ ...end_ini_parse_quantity_octal_prefixes.phpt | 1037 +++++++++++++++++ .../zend_ini_parse_quantity_overflow.phpt | 6 +- Zend/zend_ini.c | 62 +- 5 files changed, 3170 insertions(+), 9 deletions(-) create mode 100644 Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt create mode 100644 Zend/tests/zend_ini_parse_quantity_hex_prefixes.phpt create mode 100644 Zend/tests/zend_ini_parse_quantity_octal_prefixes.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt b/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt new file mode 100644 index 0000000000000..d81f89173df64 --- /dev/null +++ b/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt @@ -0,0 +1,1037 @@ +--TEST-- +Test parsing of binary quantities +--EXTENSIONS-- +zend_test +--FILE-- + '1', 'No overflow 003' => '100', 'No overflow 004' => strval(PHP_INT_MAX), - 'No overflow 005' => strval(PHP_INT_MIN), + 'No overflow 005' => strval(-PHP_INT_MAX), 'No overflow 006' => '2K', 'No overflow 007' => '-2K', 'Subject overflow 001' => increment(strval(PHP_INT_MAX)), - 'Subject overflow 002' => decrement(strval(PHP_INT_MIN)), + 'Subject overflow 002' => decrement(strval(-PHP_INT_MAX)), 'Multiplier overflow 001' => strval(PHP_INT_MAX).'K', - 'Multiplier overflow 002' => strval(PHP_INT_MIN).'K', + 'Multiplier overflow 002' => strval(-PHP_INT_MAX).'K', ]; foreach ($tests as $name => $value) { diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 2086665e04fb3..947b6531dbe08 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -552,6 +552,7 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ char *str = ZSTR_VAL(value); char *str_end = &str[ZSTR_LEN(value)]; char *digits = str; + size_t digits_len = ZSTR_LEN(value); bool overflow = false; zend_ulong factor; smart_str invalid = {0}; @@ -560,23 +561,62 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ /* 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; + while (digits < str_end && zend_is_whitespace(*digits)) {++digits; --digits_len;} /* Ignore trailing whitespace */ - while (digits < str_end && zend_is_whitespace(*(str_end-1))) --str_end; + while (digits < str_end && zend_is_whitespace(*(str_end-1))) {--str_end; --digits_len;} if (digits == str_end) { *errstr = NULL; return 0; } + bool is_negative = false; + if (digits[0] == '+') { + ++digits; + --digits_len; + } else if (digits[0] == '-') { + is_negative = true; + ++digits; + --digits_len; + } + + int base = 0; + if (digits_len >= 2 && digits[0] == '0') { + switch (digits[1]) { + case 'x': + case 'X': + base = 16; + digits += 2; + digits_len -= 2; + break; + case 'o': + case 'O': + base = 8; + digits += 2; + digits_len -= 2; + break; + case 'b': + case 'B': + base = 2; + digits += 2; + digits_len -= 2; + break; + } + /* TODO Error for invalid prefix? */ + if (digits == str_end) { + *errstr = NULL; + return 0; + } + } + zend_ulong retval; errno = 0; if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { - retval = (zend_ulong) ZEND_STRTOL(digits, &digits_end, 0); + retval = (zend_ulong) ZEND_STRTOL(digits, &digits_end, base); } else { - retval = ZEND_STRTOUL(digits, &digits_end, 0); + retval = ZEND_STRTOUL(digits, &digits_end, base); } if (errno == ERANGE) { @@ -585,8 +625,18 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ /* 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 (is_negative) { + if (digits_end - digits == 1 && digits_end == str_end && digits[0] == '1') { + retval = -1; + } else { + overflow = true; + } + } + } + + if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { + if (is_negative) { + retval = (zend_ulong) (-1 * (zend_long) retval); } } From f019895da96bf079d3fa9e62eac07db1b651b118 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Tue, 20 Sep 2022 11:31:08 +0100 Subject: [PATCH 2/5] Drop G modifier in test due to 32bit overflow --- ...nd_ini_parse_quantity_binary_prefixes.phpt | 291 +----------------- .../zend_ini_parse_quantity_hex_prefixes.phpt | 291 +----------------- ...end_ini_parse_quantity_octal_prefixes.phpt | 291 +----------------- 3 files changed, 6 insertions(+), 867 deletions(-) diff --git a/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt b/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt index d81f89173df64..750a377bb142f 100644 --- a/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt +++ b/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt @@ -9,7 +9,8 @@ zend_test foreach (['', ' '] as $leadingWS) { foreach (['', '+', '-'] as $sign) { foreach (['', ' '] as $midWS) { - foreach (['', 'K', 'k', 'M', 'm', 'G', 'g'] as $exp) { + // Ignore G due to overflow on 32bits + foreach (['', 'K', 'k', 'M', 'm'] as $exp) { foreach (['', ' '] as $trailingWS) { $setting = sprintf('%s%s0b11%s%s%s', $leadingWS, $sign, $midWS, $exp, $trailingWS); @@ -88,30 +89,6 @@ int(3145728) # "0B11m " int(3145728) -# "0b11G" -int(3221225472) - -# "0B11G" -int(3221225472) - -# "0b11G " -int(3221225472) - -# "0B11G " -int(3221225472) - -# "0b11g" -int(3221225472) - -# "0B11g" -int(3221225472) - -# "0b11g " -int(3221225472) - -# "0B11g " -int(3221225472) - # "0b11 " int(3) @@ -172,30 +149,6 @@ int(3145728) # "0B11 m " int(3145728) -# "0b11 G" -int(3221225472) - -# "0B11 G" -int(3221225472) - -# "0b11 G " -int(3221225472) - -# "0B11 G " -int(3221225472) - -# "0b11 g" -int(3221225472) - -# "0B11 g" -int(3221225472) - -# "0b11 g " -int(3221225472) - -# "0B11 g " -int(3221225472) - # "+0b11" int(3) @@ -256,30 +209,6 @@ int(3145728) # "+0B11m " int(3145728) -# "+0b11G" -int(3221225472) - -# "+0B11G" -int(3221225472) - -# "+0b11G " -int(3221225472) - -# "+0B11G " -int(3221225472) - -# "+0b11g" -int(3221225472) - -# "+0B11g" -int(3221225472) - -# "+0b11g " -int(3221225472) - -# "+0B11g " -int(3221225472) - # "+0b11 " int(3) @@ -340,30 +269,6 @@ int(3145728) # "+0B11 m " int(3145728) -# "+0b11 G" -int(3221225472) - -# "+0B11 G" -int(3221225472) - -# "+0b11 G " -int(3221225472) - -# "+0B11 G " -int(3221225472) - -# "+0b11 g" -int(3221225472) - -# "+0B11 g" -int(3221225472) - -# "+0b11 g " -int(3221225472) - -# "+0B11 g " -int(3221225472) - # "-0b11" int(-3) @@ -424,30 +329,6 @@ int(-3145728) # "-0B11m " int(-3145728) -# "-0b11G" -int(-3221225472) - -# "-0B11G" -int(-3221225472) - -# "-0b11G " -int(-3221225472) - -# "-0B11G " -int(-3221225472) - -# "-0b11g" -int(-3221225472) - -# "-0B11g" -int(-3221225472) - -# "-0b11g " -int(-3221225472) - -# "-0B11g " -int(-3221225472) - # "-0b11 " int(-3) @@ -508,30 +389,6 @@ int(-3145728) # "-0B11 m " int(-3145728) -# "-0b11 G" -int(-3221225472) - -# "-0B11 G" -int(-3221225472) - -# "-0b11 G " -int(-3221225472) - -# "-0B11 G " -int(-3221225472) - -# "-0b11 g" -int(-3221225472) - -# "-0B11 g" -int(-3221225472) - -# "-0b11 g " -int(-3221225472) - -# "-0B11 g " -int(-3221225472) - # " 0b11" int(3) @@ -592,30 +449,6 @@ int(3145728) # " 0B11m " int(3145728) -# " 0b11G" -int(3221225472) - -# " 0B11G" -int(3221225472) - -# " 0b11G " -int(3221225472) - -# " 0B11G " -int(3221225472) - -# " 0b11g" -int(3221225472) - -# " 0B11g" -int(3221225472) - -# " 0b11g " -int(3221225472) - -# " 0B11g " -int(3221225472) - # " 0b11 " int(3) @@ -676,30 +509,6 @@ int(3145728) # " 0B11 m " int(3145728) -# " 0b11 G" -int(3221225472) - -# " 0B11 G" -int(3221225472) - -# " 0b11 G " -int(3221225472) - -# " 0B11 G " -int(3221225472) - -# " 0b11 g" -int(3221225472) - -# " 0B11 g" -int(3221225472) - -# " 0b11 g " -int(3221225472) - -# " 0B11 g " -int(3221225472) - # " +0b11" int(3) @@ -760,30 +569,6 @@ int(3145728) # " +0B11m " int(3145728) -# " +0b11G" -int(3221225472) - -# " +0B11G" -int(3221225472) - -# " +0b11G " -int(3221225472) - -# " +0B11G " -int(3221225472) - -# " +0b11g" -int(3221225472) - -# " +0B11g" -int(3221225472) - -# " +0b11g " -int(3221225472) - -# " +0B11g " -int(3221225472) - # " +0b11 " int(3) @@ -844,30 +629,6 @@ int(3145728) # " +0B11 m " int(3145728) -# " +0b11 G" -int(3221225472) - -# " +0B11 G" -int(3221225472) - -# " +0b11 G " -int(3221225472) - -# " +0B11 G " -int(3221225472) - -# " +0b11 g" -int(3221225472) - -# " +0B11 g" -int(3221225472) - -# " +0b11 g " -int(3221225472) - -# " +0B11 g " -int(3221225472) - # " -0b11" int(-3) @@ -928,30 +689,6 @@ int(-3145728) # " -0B11m " int(-3145728) -# " -0b11G" -int(-3221225472) - -# " -0B11G" -int(-3221225472) - -# " -0b11G " -int(-3221225472) - -# " -0B11G " -int(-3221225472) - -# " -0b11g" -int(-3221225472) - -# " -0B11g" -int(-3221225472) - -# " -0b11g " -int(-3221225472) - -# " -0B11g " -int(-3221225472) - # " -0b11 " int(-3) @@ -1011,27 +748,3 @@ int(-3145728) # " -0B11 m " int(-3145728) - -# " -0b11 G" -int(-3221225472) - -# " -0B11 G" -int(-3221225472) - -# " -0b11 G " -int(-3221225472) - -# " -0B11 G " -int(-3221225472) - -# " -0b11 g" -int(-3221225472) - -# " -0B11 g" -int(-3221225472) - -# " -0b11 g " -int(-3221225472) - -# " -0B11 g " -int(-3221225472) diff --git a/Zend/tests/zend_ini_parse_quantity_hex_prefixes.phpt b/Zend/tests/zend_ini_parse_quantity_hex_prefixes.phpt index 8d663ec5640b1..c2bdfe1c28d4e 100644 --- a/Zend/tests/zend_ini_parse_quantity_hex_prefixes.phpt +++ b/Zend/tests/zend_ini_parse_quantity_hex_prefixes.phpt @@ -9,7 +9,8 @@ zend_test foreach (['', ' '] as $leadingWS) { foreach (['', '+', '-'] as $sign) { foreach (['', ' '] as $midWS) { - foreach (['', 'K', 'k', 'M', 'm', 'G', 'g'] as $exp) { + // Ignore G due to overflow on 32bits + foreach (['', 'K', 'k', 'M', 'm'] as $exp) { foreach (['', ' '] as $trailingWS) { $setting = sprintf('%s%s0x1F%s%s%s', $leadingWS, $sign, $midWS, $exp, $trailingWS); @@ -88,30 +89,6 @@ int(32505856) # "0X1Fm " int(32505856) -# "0x1FG" -int(33285996544) - -# "0X1FG" -int(33285996544) - -# "0x1FG " -int(33285996544) - -# "0X1FG " -int(33285996544) - -# "0x1Fg" -int(33285996544) - -# "0X1Fg" -int(33285996544) - -# "0x1Fg " -int(33285996544) - -# "0X1Fg " -int(33285996544) - # "0x1F " int(31) @@ -172,30 +149,6 @@ int(32505856) # "0X1F m " int(32505856) -# "0x1F G" -int(33285996544) - -# "0X1F G" -int(33285996544) - -# "0x1F G " -int(33285996544) - -# "0X1F G " -int(33285996544) - -# "0x1F g" -int(33285996544) - -# "0X1F g" -int(33285996544) - -# "0x1F g " -int(33285996544) - -# "0X1F g " -int(33285996544) - # "+0x1F" int(31) @@ -256,30 +209,6 @@ int(32505856) # "+0X1Fm " int(32505856) -# "+0x1FG" -int(33285996544) - -# "+0X1FG" -int(33285996544) - -# "+0x1FG " -int(33285996544) - -# "+0X1FG " -int(33285996544) - -# "+0x1Fg" -int(33285996544) - -# "+0X1Fg" -int(33285996544) - -# "+0x1Fg " -int(33285996544) - -# "+0X1Fg " -int(33285996544) - # "+0x1F " int(31) @@ -340,30 +269,6 @@ int(32505856) # "+0X1F m " int(32505856) -# "+0x1F G" -int(33285996544) - -# "+0X1F G" -int(33285996544) - -# "+0x1F G " -int(33285996544) - -# "+0X1F G " -int(33285996544) - -# "+0x1F g" -int(33285996544) - -# "+0X1F g" -int(33285996544) - -# "+0x1F g " -int(33285996544) - -# "+0X1F g " -int(33285996544) - # "-0x1F" int(-31) @@ -424,30 +329,6 @@ int(-32505856) # "-0X1Fm " int(-32505856) -# "-0x1FG" -int(-33285996544) - -# "-0X1FG" -int(-33285996544) - -# "-0x1FG " -int(-33285996544) - -# "-0X1FG " -int(-33285996544) - -# "-0x1Fg" -int(-33285996544) - -# "-0X1Fg" -int(-33285996544) - -# "-0x1Fg " -int(-33285996544) - -# "-0X1Fg " -int(-33285996544) - # "-0x1F " int(-31) @@ -508,30 +389,6 @@ int(-32505856) # "-0X1F m " int(-32505856) -# "-0x1F G" -int(-33285996544) - -# "-0X1F G" -int(-33285996544) - -# "-0x1F G " -int(-33285996544) - -# "-0X1F G " -int(-33285996544) - -# "-0x1F g" -int(-33285996544) - -# "-0X1F g" -int(-33285996544) - -# "-0x1F g " -int(-33285996544) - -# "-0X1F g " -int(-33285996544) - # " 0x1F" int(31) @@ -592,30 +449,6 @@ int(32505856) # " 0X1Fm " int(32505856) -# " 0x1FG" -int(33285996544) - -# " 0X1FG" -int(33285996544) - -# " 0x1FG " -int(33285996544) - -# " 0X1FG " -int(33285996544) - -# " 0x1Fg" -int(33285996544) - -# " 0X1Fg" -int(33285996544) - -# " 0x1Fg " -int(33285996544) - -# " 0X1Fg " -int(33285996544) - # " 0x1F " int(31) @@ -676,30 +509,6 @@ int(32505856) # " 0X1F m " int(32505856) -# " 0x1F G" -int(33285996544) - -# " 0X1F G" -int(33285996544) - -# " 0x1F G " -int(33285996544) - -# " 0X1F G " -int(33285996544) - -# " 0x1F g" -int(33285996544) - -# " 0X1F g" -int(33285996544) - -# " 0x1F g " -int(33285996544) - -# " 0X1F g " -int(33285996544) - # " +0x1F" int(31) @@ -760,30 +569,6 @@ int(32505856) # " +0X1Fm " int(32505856) -# " +0x1FG" -int(33285996544) - -# " +0X1FG" -int(33285996544) - -# " +0x1FG " -int(33285996544) - -# " +0X1FG " -int(33285996544) - -# " +0x1Fg" -int(33285996544) - -# " +0X1Fg" -int(33285996544) - -# " +0x1Fg " -int(33285996544) - -# " +0X1Fg " -int(33285996544) - # " +0x1F " int(31) @@ -844,30 +629,6 @@ int(32505856) # " +0X1F m " int(32505856) -# " +0x1F G" -int(33285996544) - -# " +0X1F G" -int(33285996544) - -# " +0x1F G " -int(33285996544) - -# " +0X1F G " -int(33285996544) - -# " +0x1F g" -int(33285996544) - -# " +0X1F g" -int(33285996544) - -# " +0x1F g " -int(33285996544) - -# " +0X1F g " -int(33285996544) - # " -0x1F" int(-31) @@ -928,30 +689,6 @@ int(-32505856) # " -0X1Fm " int(-32505856) -# " -0x1FG" -int(-33285996544) - -# " -0X1FG" -int(-33285996544) - -# " -0x1FG " -int(-33285996544) - -# " -0X1FG " -int(-33285996544) - -# " -0x1Fg" -int(-33285996544) - -# " -0X1Fg" -int(-33285996544) - -# " -0x1Fg " -int(-33285996544) - -# " -0X1Fg " -int(-33285996544) - # " -0x1F " int(-31) @@ -1011,27 +748,3 @@ int(-32505856) # " -0X1F m " int(-32505856) - -# " -0x1F G" -int(-33285996544) - -# " -0X1F G" -int(-33285996544) - -# " -0x1F G " -int(-33285996544) - -# " -0X1F G " -int(-33285996544) - -# " -0x1F g" -int(-33285996544) - -# " -0X1F g" -int(-33285996544) - -# " -0x1F g " -int(-33285996544) - -# " -0X1F g " -int(-33285996544) diff --git a/Zend/tests/zend_ini_parse_quantity_octal_prefixes.phpt b/Zend/tests/zend_ini_parse_quantity_octal_prefixes.phpt index bd0588536ce07..b28d116e3a322 100644 --- a/Zend/tests/zend_ini_parse_quantity_octal_prefixes.phpt +++ b/Zend/tests/zend_ini_parse_quantity_octal_prefixes.phpt @@ -9,7 +9,8 @@ zend_test foreach (['', ' '] as $leadingWS) { foreach (['', '+', '-'] as $sign) { foreach (['', ' '] as $midWS) { - foreach (['', 'K', 'k', 'M', 'm', 'G', 'g'] as $exp) { + // Ignore G due to overflow on 32bits + foreach (['', 'K', 'k', 'M', 'm'] as $exp) { foreach (['', ' '] as $trailingWS) { $setting = sprintf('%s%s0o14%s%s%s', $leadingWS, $sign, $midWS, $exp, $trailingWS); @@ -88,30 +89,6 @@ int(12582912) # "0O14m " int(12582912) -# "0o14G" -int(12884901888) - -# "0O14G" -int(12884901888) - -# "0o14G " -int(12884901888) - -# "0O14G " -int(12884901888) - -# "0o14g" -int(12884901888) - -# "0O14g" -int(12884901888) - -# "0o14g " -int(12884901888) - -# "0O14g " -int(12884901888) - # "0o14 " int(12) @@ -172,30 +149,6 @@ int(12582912) # "0O14 m " int(12582912) -# "0o14 G" -int(12884901888) - -# "0O14 G" -int(12884901888) - -# "0o14 G " -int(12884901888) - -# "0O14 G " -int(12884901888) - -# "0o14 g" -int(12884901888) - -# "0O14 g" -int(12884901888) - -# "0o14 g " -int(12884901888) - -# "0O14 g " -int(12884901888) - # "+0o14" int(12) @@ -256,30 +209,6 @@ int(12582912) # "+0O14m " int(12582912) -# "+0o14G" -int(12884901888) - -# "+0O14G" -int(12884901888) - -# "+0o14G " -int(12884901888) - -# "+0O14G " -int(12884901888) - -# "+0o14g" -int(12884901888) - -# "+0O14g" -int(12884901888) - -# "+0o14g " -int(12884901888) - -# "+0O14g " -int(12884901888) - # "+0o14 " int(12) @@ -340,30 +269,6 @@ int(12582912) # "+0O14 m " int(12582912) -# "+0o14 G" -int(12884901888) - -# "+0O14 G" -int(12884901888) - -# "+0o14 G " -int(12884901888) - -# "+0O14 G " -int(12884901888) - -# "+0o14 g" -int(12884901888) - -# "+0O14 g" -int(12884901888) - -# "+0o14 g " -int(12884901888) - -# "+0O14 g " -int(12884901888) - # "-0o14" int(-12) @@ -424,30 +329,6 @@ int(-12582912) # "-0O14m " int(-12582912) -# "-0o14G" -int(-12884901888) - -# "-0O14G" -int(-12884901888) - -# "-0o14G " -int(-12884901888) - -# "-0O14G " -int(-12884901888) - -# "-0o14g" -int(-12884901888) - -# "-0O14g" -int(-12884901888) - -# "-0o14g " -int(-12884901888) - -# "-0O14g " -int(-12884901888) - # "-0o14 " int(-12) @@ -508,30 +389,6 @@ int(-12582912) # "-0O14 m " int(-12582912) -# "-0o14 G" -int(-12884901888) - -# "-0O14 G" -int(-12884901888) - -# "-0o14 G " -int(-12884901888) - -# "-0O14 G " -int(-12884901888) - -# "-0o14 g" -int(-12884901888) - -# "-0O14 g" -int(-12884901888) - -# "-0o14 g " -int(-12884901888) - -# "-0O14 g " -int(-12884901888) - # " 0o14" int(12) @@ -592,30 +449,6 @@ int(12582912) # " 0O14m " int(12582912) -# " 0o14G" -int(12884901888) - -# " 0O14G" -int(12884901888) - -# " 0o14G " -int(12884901888) - -# " 0O14G " -int(12884901888) - -# " 0o14g" -int(12884901888) - -# " 0O14g" -int(12884901888) - -# " 0o14g " -int(12884901888) - -# " 0O14g " -int(12884901888) - # " 0o14 " int(12) @@ -676,30 +509,6 @@ int(12582912) # " 0O14 m " int(12582912) -# " 0o14 G" -int(12884901888) - -# " 0O14 G" -int(12884901888) - -# " 0o14 G " -int(12884901888) - -# " 0O14 G " -int(12884901888) - -# " 0o14 g" -int(12884901888) - -# " 0O14 g" -int(12884901888) - -# " 0o14 g " -int(12884901888) - -# " 0O14 g " -int(12884901888) - # " +0o14" int(12) @@ -760,30 +569,6 @@ int(12582912) # " +0O14m " int(12582912) -# " +0o14G" -int(12884901888) - -# " +0O14G" -int(12884901888) - -# " +0o14G " -int(12884901888) - -# " +0O14G " -int(12884901888) - -# " +0o14g" -int(12884901888) - -# " +0O14g" -int(12884901888) - -# " +0o14g " -int(12884901888) - -# " +0O14g " -int(12884901888) - # " +0o14 " int(12) @@ -844,30 +629,6 @@ int(12582912) # " +0O14 m " int(12582912) -# " +0o14 G" -int(12884901888) - -# " +0O14 G" -int(12884901888) - -# " +0o14 G " -int(12884901888) - -# " +0O14 G " -int(12884901888) - -# " +0o14 g" -int(12884901888) - -# " +0O14 g" -int(12884901888) - -# " +0o14 g " -int(12884901888) - -# " +0O14 g " -int(12884901888) - # " -0o14" int(-12) @@ -928,30 +689,6 @@ int(-12582912) # " -0O14m " int(-12582912) -# " -0o14G" -int(-12884901888) - -# " -0O14G" -int(-12884901888) - -# " -0o14G " -int(-12884901888) - -# " -0O14G " -int(-12884901888) - -# " -0o14g" -int(-12884901888) - -# " -0O14g" -int(-12884901888) - -# " -0o14g " -int(-12884901888) - -# " -0O14g " -int(-12884901888) - # " -0o14 " int(-12) @@ -1011,27 +748,3 @@ int(-12582912) # " -0O14 m " int(-12582912) - -# " -0o14 G" -int(-12884901888) - -# " -0O14 G" -int(-12884901888) - -# " -0o14 G " -int(-12884901888) - -# " -0O14 G " -int(-12884901888) - -# " -0o14 g" -int(-12884901888) - -# " -0O14 g" -int(-12884901888) - -# " -0o14 g " -int(-12884901888) - -# " -0O14 g " -int(-12884901888) From 96d817c93f4b44a4a055ec62cb5fba7637392700 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sat, 24 Sep 2022 11:17:57 +0100 Subject: [PATCH 3/5] Address some comments --- .../zend_ini_parse_quantity.phpt | 0 ...nd_ini_parse_quantity_binary_prefixes.phpt | 0 .../zend_ini_parse_quantity_error.phpt | 19 +++++ .../zend_ini_parse_quantity_hex_prefixes.phpt | 0 ...zend_ini_parse_quantity_ini_set_error.phpt | 0 ..._ini_parse_quantity_ini_setting_error.phpt | 0 ...end_ini_parse_quantity_octal_prefixes.phpt | 0 .../zend_ini_parse_quantity_overflow.phpt | 0 .../zend_ini_parse_quantity_zero.phpt | 71 +++++++++++++++++++ .../zend_ini_parse_uquantity_overflow.phpt | 0 Zend/zend_ini.c | 71 +++++++++++-------- 11 files changed, 130 insertions(+), 31 deletions(-) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity.phpt (100%) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity_binary_prefixes.phpt (100%) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity_error.phpt (77%) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity_hex_prefixes.phpt (100%) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity_ini_set_error.phpt (100%) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity_ini_setting_error.phpt (100%) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity_octal_prefixes.phpt (100%) rename Zend/tests/{ => zend_ini}/zend_ini_parse_quantity_overflow.phpt (100%) create mode 100644 Zend/tests/zend_ini/zend_ini_parse_quantity_zero.phpt rename Zend/tests/{ => zend_ini}/zend_ini_parse_uquantity_overflow.phpt (100%) diff --git a/Zend/tests/zend_ini_parse_quantity.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity.phpt similarity index 100% rename from Zend/tests/zend_ini_parse_quantity.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_binary_prefixes.phpt similarity index 100% rename from Zend/tests/zend_ini_parse_quantity_binary_prefixes.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity_binary_prefixes.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_error.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_error.phpt similarity index 77% rename from Zend/tests/zend_ini_parse_quantity_error.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity_error.phpt index e455111e234d0..d9d1ed50499ee 100644 --- a/Zend/tests/zend_ini_parse_quantity_error.phpt +++ b/Zend/tests/zend_ini/zend_ini_parse_quantity_error.phpt @@ -13,6 +13,10 @@ $tests = [ '1X', # Unknown multiplier. '1.0K', # Non integral digits. + '0X', # Valid prefix with no value + '0Z', # Invalid prefix + '0XK', # Valid prefix with no value and multiplier + # Null bytes " 123\x00K", "\x00 123K", @@ -48,6 +52,21 @@ int(1) Warning: Invalid quantity "1.0K", interpreting as "1K" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(1024) +# "0X" + +Warning: Invalid quantity: no digits after base prefix, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +int(0) + +# "0Z" + +Warning: Invalid prefix "0Z", interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +int(0) + +# "0XK" + +Warning: Invalid quantity "0XK": no valid leading digits, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +int(0) + # " 123\000K" Warning: Invalid quantity " 123\x00K", interpreting as " 123K" for backwards compatibility in %s on line %d diff --git a/Zend/tests/zend_ini_parse_quantity_hex_prefixes.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_hex_prefixes.phpt similarity index 100% rename from Zend/tests/zend_ini_parse_quantity_hex_prefixes.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity_hex_prefixes.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_ini_set_error.phpt similarity index 100% rename from Zend/tests/zend_ini_parse_quantity_ini_set_error.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity_ini_set_error.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_ini_setting_error.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_ini_setting_error.phpt similarity index 100% rename from Zend/tests/zend_ini_parse_quantity_ini_setting_error.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity_ini_setting_error.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_octal_prefixes.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_octal_prefixes.phpt similarity index 100% rename from Zend/tests/zend_ini_parse_quantity_octal_prefixes.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity_octal_prefixes.phpt diff --git a/Zend/tests/zend_ini_parse_quantity_overflow.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_overflow.phpt similarity index 100% rename from Zend/tests/zend_ini_parse_quantity_overflow.phpt rename to Zend/tests/zend_ini/zend_ini_parse_quantity_overflow.phpt diff --git a/Zend/tests/zend_ini/zend_ini_parse_quantity_zero.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_zero.phpt new file mode 100644 index 0000000000000..86117ee31f573 --- /dev/null +++ b/Zend/tests/zend_ini/zend_ini_parse_quantity_zero.phpt @@ -0,0 +1,71 @@ +--TEST-- +Test parsing of valid 0 quantities +--EXTENSIONS-- +zend_test +--FILE-- + static HashTable *registered_zend_ini_directives; @@ -552,7 +553,6 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ char *str = ZSTR_VAL(value); char *str_end = &str[ZSTR_LEN(value)]; char *digits = str; - size_t digits_len = ZSTR_LEN(value); bool overflow = false; zend_ulong factor; smart_str invalid = {0}; @@ -561,10 +561,10 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ /* 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; --digits_len;} + while (digits < str_end && zend_is_whitespace(*digits)) {++digits;} /* Ignore trailing whitespace */ - while (digits < str_end && zend_is_whitespace(*(str_end-1))) {--str_end; --digits_len;} + while (digits < str_end && zend_is_whitespace(*(str_end-1))) {--str_end;} if (digits == str_end) { *errstr = NULL; @@ -574,69 +574,78 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ bool is_negative = false; if (digits[0] == '+') { ++digits; - --digits_len; } else if (digits[0] == '-') { is_negative = true; ++digits; - --digits_len; } + /* TODO Handle cases such as ++25, --25, or white space after sign symbol? + if (!isdigit(digits[0])) { + + } + */ + int base = 0; - if (digits_len >= 2 && digits[0] == '0') { + if (digits[0] == '0' && !isdigit(digits[1])) { + /* Value is just 0 */ + if ((digits+1) == str_end) { + *errstr = NULL; + return 0; + } + switch (digits[1]) { + /* Multiplier suffixes */ + case 'g': + case 'G': + case 'm': + case 'M': + case 'k': + case 'K': + goto evaluation; case 'x': case 'X': base = 16; - digits += 2; - digits_len -= 2; break; case 'o': case 'O': base = 8; - digits += 2; - digits_len -= 2; break; case 'b': case 'B': base = 2; - digits += 2; - digits_len -= 2; break; + default: + *errstr = zend_strpprintf(0, "Invalid prefix \"0%c\", interpreting as \"0\" for backwards compatibility", + digits[1]); + return 0; } - /* TODO Error for invalid prefix? */ - if (digits == str_end) { - *errstr = NULL; + digits += 2; + if (UNEXPECTED(digits == str_end)) { + *errstr = zend_strpprintf(0, "Invalid quantity: no digits after base prefix, interpreting as \"0\" for backwards compatibility"); return 0; } } + evaluation: - zend_ulong retval; errno = 0; - - if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { - retval = (zend_ulong) ZEND_STRTOL(digits, &digits_end, base); - } else { - retval = ZEND_STRTOUL(digits, &digits_end, base); - } + zend_ulong retval = ZEND_STRTOUL(digits, &digits_end, base); if (errno == ERANGE) { overflow = true; } 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. */ if (is_negative) { - if (digits_end - digits == 1 && digits_end == str_end && digits[0] == '1') { + /* Ignore "-1" as it is commonly used as max value, for instance in memory_limit=-1. */ + if (retval == 1 && digits_end == str_end) { retval = -1; } else { overflow = true; } } - } - - if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { - if (is_negative) { - retval = (zend_ulong) (-1 * (zend_long) retval); + } else if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { + if ((zend_long) retval < 0) { + overflow = true; + } else if (is_negative) { + retval = 0u - retval; } } From 227d8e644f279e66deb6da472a1817129238d659 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Tue, 27 Sep 2022 15:24:27 +0100 Subject: [PATCH 4/5] Handle PHP_INT_MIN properly --- Zend/tests/zend_ini/zend_ini_parse_quantity_overflow.phpt | 6 +++--- Zend/zend_ini.c | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Zend/tests/zend_ini/zend_ini_parse_quantity_overflow.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_overflow.phpt index acaca309c182e..f50f67f94a95c 100644 --- a/Zend/tests/zend_ini/zend_ini_parse_quantity_overflow.phpt +++ b/Zend/tests/zend_ini/zend_ini_parse_quantity_overflow.phpt @@ -30,13 +30,13 @@ $tests = [ 'No overflow 002' => '1', 'No overflow 003' => '100', 'No overflow 004' => strval(PHP_INT_MAX), - 'No overflow 005' => 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_MAX)), + 'Subject overflow 002' => decrement(strval(PHP_INT_MIN)), 'Multiplier overflow 001' => strval(PHP_INT_MAX).'K', - 'Multiplier overflow 002' => strval(-PHP_INT_MAX).'K', + 'Multiplier overflow 002' => strval(PHP_INT_MIN).'K', ]; foreach ($tests as $name => $value) { diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index b6bbc207fc4db..1ec0a588bef3f 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -642,7 +642,10 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ } } } else if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { - if ((zend_long) retval < 0) { + /* Handle PHP_INT_MIN case */ + if (is_negative && retval == ((zend_ulong)ZEND_LONG_MAX +1)) { + retval = 0u - retval; + } else if ((zend_long) retval < 0) { overflow = true; } else if (is_negative) { retval = 0u - retval; From e14035f8a387524b63be32a4f6e0380fa654af9e Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Tue, 27 Sep 2022 15:41:24 +0100 Subject: [PATCH 5/5] More error messages and improved --- .../zend_ini_parse_quantity_error.phpt | 27 ++++++++++++++++++- Zend/zend_ini.c | 22 ++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Zend/tests/zend_ini/zend_ini_parse_quantity_error.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_error.phpt index d9d1ed50499ee..9671ab856bccf 100644 --- a/Zend/tests/zend_ini/zend_ini_parse_quantity_error.phpt +++ b/Zend/tests/zend_ini/zend_ini_parse_quantity_error.phpt @@ -17,6 +17,11 @@ $tests = [ '0Z', # Invalid prefix '0XK', # Valid prefix with no value and multiplier + '++', + '-+', + '+ 25', + '- 25', + # Null bytes " 123\x00K", "\x00 123K", @@ -54,7 +59,7 @@ int(1024) # "0X" -Warning: Invalid quantity: no digits after base prefix, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +Warning: Invalid quantity "0X": no digits after base prefix, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d int(0) # "0Z" @@ -67,6 +72,26 @@ int(0) Warning: Invalid quantity "0XK": 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 "++": 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 "-+": no valid leading digits, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +int(0) + +# "+ 25" + +Warning: Invalid quantity "+ 25": no valid leading digits, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +int(0) + +# "- 25" + +Warning: Invalid quantity "- 25": no valid leading digits, interpreting as "0" for backwards compatibility in %s%ezend_ini_parse_quantity_error.php on line %d +int(0) + # " 123\000K" Warning: Invalid quantity " 123\x00K", interpreting as " 123K" for backwards compatibility in %s on line %d diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 1ec0a588bef3f..77fab940d664d 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -579,11 +579,19 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ ++digits; } - /* TODO Handle cases such as ++25, --25, or white space after sign symbol? + /* if there is no digit after +/- */ if (!isdigit(digits[0])) { + /* 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", + ZSTR_VAL(invalid.s)); + smart_str_free(&invalid); + return 0; } - */ int base = 0; if (digits[0] == '0' && !isdigit(digits[1])) { @@ -621,7 +629,15 @@ static zend_ulong zend_ini_parse_quantity_internal(zend_string *value, zend_ini_ } digits += 2; if (UNEXPECTED(digits == str_end)) { - *errstr = zend_strpprintf(0, "Invalid quantity: no digits after base prefix, interpreting as \"0\" for backwards compatibility"); + /* 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 digits after base prefix, interpreting as \"0\" for backwards compatibility", + ZSTR_VAL(invalid.s)); + + smart_str_free(&invalid); return 0; } }