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/zend_ini_parse_quantity_binary_prefixes.phpt b/Zend/tests/zend_ini/zend_ini_parse_quantity_binary_prefixes.phpt new file mode 100644 index 0000000000000..750a377bb142f --- /dev/null +++ b/Zend/tests/zend_ini/zend_ini_parse_quantity_binary_prefixes.phpt @@ -0,0 +1,750 @@ +--TEST-- +Test parsing of binary quantities +--EXTENSIONS-- +zend_test +--FILE-- + static HashTable *registered_zend_ini_directives; @@ -560,33 +561,110 @@ 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;} /* 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;} if (digits == str_end) { *errstr = NULL; return 0; } - zend_ulong retval; - errno = 0; + bool is_negative = false; + if (digits[0] == '+') { + ++digits; + } else if (digits[0] == '-') { + is_negative = true; + ++digits; + } - 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); + /* 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])) { + /* 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; + break; + case 'o': + case 'O': + base = 8; + break; + case 'b': + case 'B': + base = 2; + break; + default: + *errstr = zend_strpprintf(0, "Invalid prefix \"0%c\", interpreting as \"0\" for backwards compatibility", + digits[1]); + return 0; + } + digits += 2; + if (UNEXPECTED(digits == str_end)) { + /* 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; + } } + evaluation: + + errno = 0; + 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 (digits[0] == '-' && !(digits_end - digits == 2 && digits_end == str_end && digits[1] == '1')) { + if (is_negative) { + /* 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; + } + } + } else if (signed_result == ZEND_INI_PARSE_QUANTITY_SIGNED) { + /* 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; } }