diff --git a/Zend/tests/zend_atol.phpt b/Zend/tests/zend_atol.phpt new file mode 100644 index 0000000000000..350c3398b0c19 --- /dev/null +++ b/Zend/tests/zend_atol.phpt @@ -0,0 +1,193 @@ +--TEST-- +Test parsing of INI "size" values (e.g. "16M") +--FILE-- +mm_heap = malloc(sizeof(zend_mm_heap)); memset(alloc_globals->mm_heap, 0, sizeof(zend_mm_heap)); alloc_globals->mm_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_STD; @@ -2673,7 +2673,7 @@ static void alloc_globals_ctor(zend_alloc_globals *alloc_globals) #endif tmp = getenv("USE_ZEND_ALLOC_HUGE_PAGES"); - if (tmp && zend_atoi(tmp, 0)) { + if (tmp && ZEND_STRTOL(tmp, NULL, 0)) { zend_mm_use_huge_pages = 1; } alloc_globals->mm_heap = zend_mm_init(); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 361223a7c09b6..a7fcbd1577426 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -39,6 +39,8 @@ static _locale_t current_locale = NULL; #define zend_tolower(c) tolower(c) #endif +#define ZEND_IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r') || ((c) == '\v') || ((c) == '\f')) + #define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2)) static const unsigned char tolower_map[256] = { @@ -80,56 +82,64 @@ static const unsigned char tolower_map[256] = { ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, size_t str_len) /* {{{ */ { - int retval; - - if (!str_len) { - str_len = strlen(str); - } - retval = ZEND_STRTOL(str, NULL, 0); - if (str_len>0) { - switch (str[str_len-1]) { - case 'g': - case 'G': - retval *= 1024; - /* break intentionally missing */ - case 'm': - case 'M': - retval *= 1024; - /* break intentionally missing */ - case 'k': - case 'K': - retval *= 1024; - break; - } - } - return retval; + return (int)zend_atol(str, str_len); } /* }}} */ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* {{{ */ { zend_long retval; + char *end = NULL; if (!str_len) { str_len = strlen(str); } - retval = ZEND_STRTOL(str, NULL, 0); - if (str_len>0) { - switch (str[str_len-1]) { - case 'g': - case 'G': - retval *= 1024; - /* break intentionally missing */ - case 'm': - case 'M': - retval *= 1024; - /* break intentionally missing */ - case 'k': - case 'K': - retval *= 1024; - break; - } + + /* Ignore trailing whitespace */ + while (str_len && ZEND_IS_WHITESPACE(str[str_len-1])) --str_len; + if (!str_len) return 0; + + /* Parse integral portion */ + retval = ZEND_STRTOL(str, &end, 0); + + if (!(end - str)) { + zend_error(E_WARNING, "Invalid numeric string '%.*s', no valid leading digits, interpreting as '0'", + (int)str_len, str); + return 0; } + + /* Allow for whitespace between integer portion and any suffix character */ + while (ZEND_IS_WHITESPACE(*end)) ++end; + + /* No exponent suffix. */ + if (!*end) return retval; + + switch (str[str_len-1]) { + case 'g': + case 'G': + retval *= 1024; + /* break intentionally missing */ + case 'm': + case 'M': + retval *= 1024; + /* break intentionally missing */ + case 'k': + case 'K': + retval *= 1024; + break; + default: + /* Unknown suffix */ + zend_error(E_WARNING, "Invalid numeric string '%.*s', interpreting as '%.*s'", + (int)str_len, str, (int)(end - str), str); + return retval; + } + + if (end < (str + str_len - 1)) { + /* More than one character in suffix */ + zend_error(E_WARNING, "Invalid numeric string '%.*s', interpreting as '%.*s%c'", + (int)str_len, str, (int)(end - str), str, str[str_len-1]); + } + return retval; } /* }}} */ @@ -3007,7 +3017,7 @@ ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t /* Skip any whitespace * This is much faster than the isspace() function */ - while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') { + while (ZEND_IS_WHITESPACE(*str)) { str++; length--; } diff --git a/ext/session/session.c b/ext/session/session.c index b639f432c3a42..9f5a9eeb007fc 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -768,8 +768,8 @@ static PHP_INI_MH(OnUpdateLazyWrite) /* {{{ */ static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */ { - int tmp; - tmp = zend_atoi(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + zend_long tmp = ZEND_STRTOL(ZSTR_VAL(new_value), NULL, 0); + if(tmp < 0) { php_error_docref(NULL, E_WARNING, "session.upload_progress.freq must be greater than or equal to zero"); return FAILURE; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 4b3804f589555..8696f2bf778e9 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -5994,7 +5994,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_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/zlib/zlib.c b/ext/zlib/zlib.c index 7eb38c3c04dc0..c81a288603664 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -1436,7 +1436,7 @@ static PHP_INI_MH(OnUpdate_zlib_output_compression) } else if (!strncasecmp(ZSTR_VAL(new_value), "on", sizeof("on"))) { int_value = 1; } else { - int_value = zend_atoi(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + int_value = ZEND_STRTOL(ZSTR_VAL(new_value), NULL, 0); } ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0);