]> granicus.if.org Git - php/commitdiff
Constrain number parameter of numfmt_format to int|float
authorChristoph M. Becker <cmbecker69@gmx.de>
Sun, 16 Feb 2020 15:41:43 +0000 (16:41 +0100)
committerChristoph M. Becker <cmbecker69@gmx.de>
Sun, 16 Feb 2020 15:48:35 +0000 (16:48 +0100)
This is inline with similar changes to the math functions.  Especially,
array to number conversion makes no sense here, and is likely to hide
a programming error.

To make that feasible, we introduce the `n` specifier for classic ZPP
so we can stick with `zend_parse_method_parameters()`.

We also remove a test case, which has been degenerated to a ZPP test.

Zend/zend_API.c
Zend/zend_API.h
docs/parameter-parsing-api.md
ext/intl/formatter/formatter.stub.php
ext/intl/formatter/formatter_arginfo.h
ext/intl/formatter/formatter_format.c
ext/intl/tests/bug48227.phpt
ext/intl/tests/bug53735.phpt
ext/intl/tests/bug79212.phpt [deleted file]

index a3e452bf7d9c56881abd9bdcaacac0a908704bfe..ed8440f1047ea3d06d253b28f72e114f3f3d2a0f 100644 (file)
@@ -522,6 +522,16 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
                        }
                        break;
 
+               case 'n':
+                       {
+                               zval **p = va_arg(*va, zval **);
+
+                               if (!zend_parse_arg_number(arg, p, check_null)) {
+                                       return "number";
+                               }
+                       }
+                       break;
+
                case 's':
                        {
                                char **p = va_arg(*va, char **);
@@ -793,7 +803,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
                        case 'f': case 'A':
                        case 'H': case 'p':
                        case 'S': case 'P':
-                       case 'L':
+                       case 'L': case 'n':
                                max_num_args++;
                                break;
 
index 70879fe2a8013afa7fda72973fca8515779456a8..2f1b58eb755286ad9a96ff9f13088243e04dd924 100644 (file)
@@ -1384,7 +1384,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int num, char *e
 #define Z_PARAM_LONG_OR_NULL(dest, is_null) \
        Z_PARAM_LONG_EX(dest, is_null, 1, 0)
 
-/* no old equivalent */
+/* old "n" */
 #define Z_PARAM_NUMBER_EX(dest, check_null) \
        Z_PARAM_PROLOGUE(0, 0); \
        if (UNEXPECTED(!zend_parse_arg_number(_arg, &dest, check_null))) { \
index e038a20dee3cdcf114b26ab152405b57f3d6f2fa..6bf035673b54f154f0f35edb5b4bad0f482957ad 100644 (file)
@@ -75,6 +75,7 @@ f  - function or array containing php method call info (returned as
 h  - array (returned as HashTable*)
 H  - array or HASH_OF(object) (returned as HashTable*)
 l  - long (zend_long)
+n  - long or double (zval*)
 o  - object of any type (zval*)
 O  - object of specific type given by class entry (zval*, zend_class_entry)
 p  - valid path (string without null bytes in the middle) and its length (char*, size_t)
index 8d976f79e2270f07bcef5b6b4b83d062ff350845..2edc28d6fd4c4d2eacd30636da811689843da229 100644 (file)
@@ -8,7 +8,7 @@ class NumberFormatter
     public static function create(string $locale, int $style, string $pattern = "") {}
 
     /** @return string|false */
-    public function format($value, int $type = NumberFormatter::TYPE_DEFAULT) {}
+    public function format(int|float $value, int $type = NumberFormatter::TYPE_DEFAULT) {}
 
     /** @return int|float|false */
     public function parse(string $value, int $type = NumberFormatter::TYPE_DOUBLE, &$position = null) {}
@@ -58,7 +58,7 @@ class NumberFormatter
 
 function numfmt_create(string $locale, int $style, string $pattern = ""): ?NumberFormatter {}
 
-function numfmt_format(NumberFormatter $fmt, $value, int $type = NumberFormatter::TYPE_DEFAULT): string|false {}
+function numfmt_format(NumberFormatter $fmt, int|float $value, int $type = NumberFormatter::TYPE_DEFAULT): string|false {}
 
 function numfmt_parse(NumberFormatter $fmt, string $value, int $type = NumberFormatter::TYPE_DOUBLE, &$position = null): int|float|false {}
 
index 313d0dd714dcecc2ebb63b557209965830ec4444..eced76d82b4287780f76322f7bf8a495b1127932 100644 (file)
@@ -9,7 +9,7 @@ ZEND_END_ARG_INFO()
 #define arginfo_class_NumberFormatter_create arginfo_class_NumberFormatter___construct
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NumberFormatter_format, 0, 0, 1)
-       ZEND_ARG_INFO(0, value)
+       ZEND_ARG_TYPE_MASK(0, value, MAY_BE_LONG|MAY_BE_DOUBLE)
        ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
@@ -73,7 +73,7 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_numfmt_format, 0, 2, MAY_BE_STRING|MAY_BE_FALSE)
        ZEND_ARG_OBJ_INFO(0, fmt, NumberFormatter, 0)
-       ZEND_ARG_INFO(0, value)
+       ZEND_ARG_TYPE_MASK(0, value, MAY_BE_LONG|MAY_BE_DOUBLE)
        ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
index 8c6a567eb2b78cbfead4492ecb76cee89ae2321f..4f87a981f29a8910b720df00086d3f1106eb8087 100644 (file)
@@ -39,7 +39,7 @@ PHP_FUNCTION( numfmt_format )
        FORMATTER_METHOD_INIT_VARS;
 
        /* Parse parameters. */
-       if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Oz|l",
+       if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "On|l",
                &object, NumberFormatter_ce_ptr,  &number, &type ) == FAILURE )
        {
                RETURN_THROWS();
@@ -48,12 +48,6 @@ PHP_FUNCTION( numfmt_format )
        /* Fetch the object. */
        FORMATTER_METHOD_FETCH_OBJECT;
 
-       if(Z_TYPE_P(number) != IS_ARRAY) {
-               convert_scalar_to_number_ex(number);
-       } else {
-               convert_to_long(number);
-       }
-
        if(type == FORMAT_TYPE_DEFAULT) {
                switch(Z_TYPE_P(number)) {
                        case IS_LONG:
index 42a4ffaf867a208a3cd9e24535e8c4ad7e78da74..a5946e035f57841243319f99106caef4f0a840a3 100644 (file)
@@ -6,16 +6,17 @@ Bug #48227 (NumberFormatter::format leaks memory)
 <?php
 
 $x = new NumberFormatter('en_US', NumberFormatter::DECIMAL);
-var_dump($x->format(''));
-var_dump($x->format(1));
-var_dump($x->format(NULL));
-var_dump($x->format($x));
+foreach (['', 1, NULL, $x] as $value) {
+    try {
+        var_dump($x->format($value));
+    } catch (TypeError $ex) {
+        echo $ex->getMessage(), PHP_EOL;
+    }
+}
 
 ?>
---EXPECTF--
-string(1) "0"
+--EXPECT--
+NumberFormatter::format() expects parameter 1 to be number, string given
 string(1) "1"
 string(1) "0"
-
-Notice: Object of class NumberFormatter could not be converted to number in %s on line %d
-string(1) "1"
+NumberFormatter::format() expects parameter 1 to be number, object given
index 1deebb22766324a9559d30db2ac346e23eb0576e..66370e61f2e4ce76d326ec428d055f116b059c81 100644 (file)
@@ -25,6 +25,8 @@ var_dump($f->format(0.26));
 --EXPECTF--
 string(%d) "5,50 kr%A"
 string(%d) "5,50 kr%A"
+
+Notice: A non well formed numeric value encountered in %s on line %d
 string(%d) "5,00 kr%A"
 string(5) "23,25"
 string(3) "26%"
diff --git a/ext/intl/tests/bug79212.phpt b/ext/intl/tests/bug79212.phpt
deleted file mode 100644 (file)
index 3d20830..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
---TEST--
-Bug #79212 (NumberFormatter::format() may detect wrong type)
---SKIPIF--
-<?php
-if (!extension_loaded('intl')) die('skip intl extension not available');
-if (!extension_loaded('gmp')) die('skip gmp extension not available');
-?>
---FILE--
-<?php
-$fmt = new NumberFormatter('en_US', NumberFormatter::PATTERN_DECIMAL);
-var_dump($fmt->format(gmp_init('823749273428379492374')));
-
-$fmt = new NumberFormatter('en_US', NumberFormatter::PATTERN_DECIMAL);
-var_dump($fmt->format([1], NumberFormatter::TYPE_INT64));
-?>
---EXPECTF--
-string(21) "823749273428379%c%c%c%c%c%c"
-string(1) "1"