Skip to content

Commit c7f9ef7

Browse files
committed
Make float to string casts locale-independent
1 parent cb933d6 commit c7f9ef7

File tree

5 files changed

+87
-22
lines changed

5 files changed

+87
-22
lines changed

Zend/zend_operators.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -512,15 +512,7 @@ ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
512512

513513
ZEND_API void ZEND_FASTCALL _convert_to_cstring(zval *op) /* {{{ */
514514
{
515-
if (Z_TYPE_P(op) == IS_DOUBLE) {
516-
zend_string *str;
517-
double dval = Z_DVAL_P(op);
518-
519-
str = zend_strpprintf_unchecked(0, "%.*H", (int) EG(precision), dval);
520-
ZVAL_NEW_STR(op, str);
521-
} else {
522-
_convert_to_string(op);
523-
}
515+
_convert_to_string(op);
524516
}
525517
/* }}} */
526518

@@ -553,7 +545,7 @@ ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op) /* {{{ */
553545
zend_string *str;
554546
double dval = Z_DVAL_P(op);
555547

556-
str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval);
548+
str = zend_strpprintf_unchecked(0, "%.*H", (int) EG(precision), dval);
557549
/* %G already handles removing trailing zeros from the fractional part, yay */
558550
ZVAL_NEW_STR(op, str);
559551
break;
@@ -866,7 +858,7 @@ static zend_always_inline zend_string* __zval_get_string_func(zval *op, zend_boo
866858
return zend_long_to_str(Z_LVAL_P(op));
867859
}
868860
case IS_DOUBLE: {
869-
return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
861+
return zend_strpprintf_unchecked(0, "%.*H", (int) EG(precision), Z_DVAL_P(op));
870862
}
871863
case IS_ARRAY:
872864
zend_error(E_WARNING, "Array to string conversion");

ext/pdo/pdo_stmt.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,8 @@ static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_s
230230
}
231231

232232
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
233-
if (Z_TYPE_P(parameter) == IS_DOUBLE) {
234-
char *p;
235-
int len = zend_spprintf_unchecked(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(parameter));
236-
ZVAL_STRINGL(parameter, p, len);
237-
efree(p);
238-
} else {
239-
if (!try_convert_to_string(parameter)) {
240-
return 0;
241-
}
233+
if (!try_convert_to_string(parameter)) {
234+
return 0;
242235
}
243236
} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE)) {
244237
convert_to_long(parameter);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Test that float to string and string to float casts are consistent
3+
--SKIPIF--
4+
<?php
5+
if (!setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8")) {
6+
die("skip locale needed for this test is not supported on this platform");
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
12+
setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8");
13+
14+
$float = 1/3;
15+
$string = (string) $float;
16+
$float = (float) $string;
17+
18+
printf("%.2f", $float);
19+
20+
?>
21+
--EXPECT--
22+
0,33
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
Test that floats are converted to string locale independently
3+
--SKIPIF--
4+
<?php
5+
if (!setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8")) {
6+
die("skip locale needed for this test is not supported on this platform");
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
$f = 3.14;
12+
13+
setlocale(LC_ALL, "C");
14+
echo "C:\n";
15+
16+
var_dump($f);
17+
var_dump((string) $f);
18+
var_dump(strval($f));
19+
var_export($f);
20+
debug_zval_dump($f);
21+
var_dump(serialize($f));
22+
var_dump(json_encode($f));
23+
printf("%.2f\n", $f);
24+
var_dump(sprintf("%.2f", $f));
25+
26+
setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8");
27+
echo "\nde_DE:\n";
28+
29+
var_dump($f);
30+
var_dump((string) $f);
31+
var_dump(strval($f));
32+
var_export($f);
33+
debug_zval_dump($f);
34+
var_dump(serialize($f));
35+
var_dump(json_encode($f));
36+
printf("%.2f\n", $f);
37+
var_dump(sprintf("%.2f", $f));
38+
39+
?>
40+
--EXPECT--
41+
C:
42+
float(3.14)
43+
string(4) "3.14"
44+
string(4) "3.14"
45+
3.14float(3.14)
46+
string(7) "d:3.14;"
47+
string(4) "3.14"
48+
3.14
49+
string(4) "3.14"
50+
51+
de_DE:
52+
float(3,14)
53+
string(4) "3.14"
54+
string(4) "3.14"
55+
3.14float(3,14)
56+
string(7) "d:3.14;"
57+
string(4) "3.14"
58+
3,14
59+
string(4) "3,14"

main/php.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ ssize_t pread(int, void *, size_t, off64_t);
309309
BEGIN_EXTERN_C()
310310
void phperror(char *error);
311311
PHPAPI size_t php_write(void *buf, size_t size);
312-
PHPAPI size_t php_printf(const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1,
313-
2);
312+
PHPAPI size_t php_printf(const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1, 2);
314313
PHPAPI int php_get_module_initialized(void);
315314
#ifdef HAVE_SYSLOG_H
316315
#include "php_syslog.h"

0 commit comments

Comments
 (0)