From 86ffde3c3837062423b5e4abb9765157960c4a9d Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 4 Apr 2023 16:14:24 +0200 Subject: [PATCH] Improve ini number handling with INI_SCANNER_TYPED Fixes GH-11010 Closes GH-11014 --- NEWS | 3 ++ Zend/zend_ini_parser.y | 52 +++++++++++++++++-- Zend/zend_ini_scanner.l | 25 --------- .../tests/general_functions/bug70157.phpt | 2 +- .../tests/general_functions/bug77844.phpt | 4 +- .../parse_ini_string_bug76068.phpt | 4 +- ext/standard/tests/gh11010.phpt | 9 ++++ 7 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 ext/standard/tests/gh11010.phpt diff --git a/NEWS b/NEWS index 5da63a489dc..a458ae4151d 100644 --- a/NEWS +++ b/NEWS @@ -170,6 +170,9 @@ PHP NEWS . Fix GH-10239 (proc_close after proc_get_status always returns -1). (nielsdos) . Improve the warning message for unpack() in case not enough values were provided. (nielsdos) + . Fix GH-11010 (parse_ini_string() now preserves formatting of unquoted + strings starting with numbers when the INI_SCANNER_TYPED flag is + specified). (ilutov) - Streams: . Fixed bug #51056: blocking fread() will block even if data is available. diff --git a/Zend/zend_ini_parser.y b/Zend/zend_ini_parser.y index 322424b979e..dc635176d4d 100644 --- a/Zend/zend_ini_parser.y +++ b/Zend/zend_ini_parser.y @@ -43,6 +43,7 @@ int ini_parse(void); #endif #define ZEND_SYSTEM_INI CG(ini_parser_unbuffered_errors) +#define INI_ZVAL_IS_NUMBER 1 static int get_int_val(zval *op) { switch (Z_TYPE_P(op)) { @@ -92,8 +93,12 @@ static void zend_ini_do_op(char type, zval *result, zval *op1, zval *op2) break; } - str_len = sprintf(str_result, "%d", i_result); - ZVAL_NEW_STR(result, zend_string_init(str_result, str_len, ZEND_SYSTEM_INI)); + if (INI_SCNG(scanner_mode) != ZEND_INI_SCANNER_TYPED) { + str_len = sprintf(str_result, "%d", i_result); + ZVAL_NEW_STR(result, zend_string_init(str_result, str_len, ZEND_SYSTEM_INI)); + } else { + ZVAL_LONG(result, i_result); + } } /* }}} */ @@ -276,6 +281,41 @@ static void zval_ini_dtor(zval *zv) } /* }}} */ +static inline zend_result convert_to_number(zval *retval, const char *str, const int str_len) +{ + uint8_t type; + int overflow; + zend_long lval; + double dval; + + if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) { + if (type == IS_LONG) { + ZVAL_LONG(retval, lval); + return SUCCESS; + } else if (type == IS_DOUBLE && !overflow) { + ZVAL_DOUBLE(retval, dval); + return SUCCESS; + } + } + + return FAILURE; +} + +static void normalize_value(zval *zv) +{ + if (INI_SCNG(scanner_mode) != ZEND_INI_SCANNER_TYPED) { + return; + } + + if (Z_EXTRA_P(zv) == INI_ZVAL_IS_NUMBER && Z_TYPE_P(zv) == IS_STRING) { + zval number_rv; + if (convert_to_number(&number_rv, Z_STRVAL_P(zv), Z_STRLEN_P(zv)) == SUCCESS) { + zval_ptr_dtor(zv); + ZVAL_COPY_VALUE(zv, &number_rv); + } + } +} + %} %expect 0 @@ -351,7 +391,7 @@ section_string_or_value: ; string_or_value: - expr { $$ = $1; } + expr { $$ = $1; normalize_value(&$$); } | BOOL_TRUE { $$ = $1; } | BOOL_FALSE { $$ = $1; } | NULL_NULL { $$ = $1; } @@ -412,7 +452,11 @@ constant_literal: constant_string: TC_CONSTANT { zend_ini_get_constant(&$$, &$1); } | TC_RAW { $$ = $1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ } - | TC_NUMBER { $$ = $1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ } + | TC_NUMBER { + $$ = $1; + Z_EXTRA($$) = INI_ZVAL_IS_NUMBER; + /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ + } | TC_STRING { $$ = $1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ } | TC_WHITESPACE { $$ = $1; /*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ } ; diff --git a/Zend/zend_ini_scanner.l b/Zend/zend_ini_scanner.l index 6e6ffc7bbb7..534b0e938d3 100644 --- a/Zend/zend_ini_scanner.l +++ b/Zend/zend_ini_scanner.l @@ -151,26 +151,6 @@ ZEND_API zend_ini_scanner_globals ini_scanner_globals; return type; \ } -static inline zend_result convert_to_number(zval *retval, const char *str, const int str_len) -{ - uint8_t type; - int overflow; - zend_long lval; - double dval; - - if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) { - if (type == IS_LONG) { - ZVAL_LONG(retval, lval); - return SUCCESS; - } else if (type == IS_DOUBLE && !overflow) { - ZVAL_DOUBLE(retval, dval); - return SUCCESS; - } - } - - return FAILURE; -} - static void zend_ini_copy_typed_value(zval *retval, const int type, const char *str, int len) { switch (type) { @@ -183,11 +163,6 @@ static void zend_ini_copy_typed_value(zval *retval, const int type, const char * ZVAL_NULL(retval); break; - case TC_NUMBER: - if (convert_to_number(retval, str, len) == SUCCESS) { - break; - } - ZEND_FALLTHROUGH; default: zend_ini_copy_value(retval, str, len); } diff --git a/ext/standard/tests/general_functions/bug70157.phpt b/ext/standard/tests/general_functions/bug70157.phpt index f593682051d..815ccdcf966 100644 --- a/ext/standard/tests/general_functions/bug70157.phpt +++ b/ext/standard/tests/general_functions/bug70157.phpt @@ -21,7 +21,7 @@ array(%d) { ["foo"]=> array(%d) { [123]=> - string(%d) "24575" + int(24575) [456]=> int(123) } diff --git a/ext/standard/tests/general_functions/bug77844.phpt b/ext/standard/tests/general_functions/bug77844.phpt index a8b6bf3d0dd..608ea865b82 100644 --- a/ext/standard/tests/general_functions/bug77844.phpt +++ b/ext/standard/tests/general_functions/bug77844.phpt @@ -13,7 +13,7 @@ var_dump(parse_ini_string($ini, true, INI_SCANNER_TYPED)); --EXPECT-- array(2) { ["val1"]=> - string(1) "2" + int(2) ["val2"]=> - string(1) "2" + int(2) } diff --git a/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt b/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt index 359e9c34466..74d28718a03 100644 --- a/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt +++ b/ext/standard/tests/general_functions/parse_ini_string_bug76068.phpt @@ -21,7 +21,7 @@ array(1) { ["foo"]=> array(1) { ["bar"]=> - string(1) "1" + int(1) } } array(1) { @@ -42,6 +42,6 @@ array(1) { ["foo"]=> array(1) { ["bar"]=> - string(2) "42" + int(42) } } diff --git a/ext/standard/tests/gh11010.phpt b/ext/standard/tests/gh11010.phpt new file mode 100644 index 00000000000..cde4be52a66 --- /dev/null +++ b/ext/standard/tests/gh11010.phpt @@ -0,0 +1,9 @@ +--TEST-- +GH-11010: Preserve ini formatting of concatenated numbers +--FILE-- + +--EXPECT-- +string(9) "-00 20 30"