Skip to content

Commit c11af2b

Browse files
committed
Explicit casts should not warn
1 parent dd0a049 commit c11af2b

10 files changed

+69
-24
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
Explicit (int) cast must not warn
3+
--FILE--
4+
<?php
5+
6+
$values =[
7+
3.0,
8+
3.5,
9+
10e120,
10+
10e300,
11+
fdiv(0, 0),
12+
(string) 3.0,
13+
(string) 3.5,
14+
(string) 10e120,
15+
(string) 10e300,
16+
(string) fdiv(0, 0),
17+
];
18+
19+
foreach($values as $value) {
20+
var_dump((int) $value);
21+
}
22+
23+
?>
24+
--EXPECT--
25+
int(3)
26+
int(3)
27+
int(0)
28+
int(0)
29+
int(0)
30+
int(3)
31+
int(3)
32+
int(9223372036854775807)
33+
int(9223372036854775807)
34+
int(0)

Zend/tests/float_to_int/warning_float_does_not_fit_zend_long_arrays.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ var_dump($array[$string_float]);
2424
?>
2525
--EXPECTF--
2626
int(0)
27-
28-
Warning: Implicit float string to int conversion in %s on line %d
2927
int(9223372036854775807)
3028

3129
Warning: Implicit float to int conversion in %s on line %d

Zend/tests/float_to_int/warning_float_does_not_fit_zend_long_strings.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ try {
5858
?>
5959
--EXPECTF--
6060
int(0)
61-
62-
Warning: Implicit float string to int conversion in %s on line %d
6361
int(9223372036854775807)
6462
Attempt to read
6563
Float

Zend/tests/float_to_int/warning_float_does_not_fit_zend_long_write_variation1.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ try {
2020
--EXPECTF--
2121
Float casted to string compile
2222

23-
Warning: Implicit float string to int conversion in %s on line %d
24-
2523
Warning: Uncaught TypeError: Cannot access offset of type string on string in %s:%d
2624
Stack trace:
2725
#0 {main}

Zend/tests/float_to_int/warning_float_does_not_fit_zend_long_write_variation2.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ try {
2020
--EXPECTF--
2121
Float string variable
2222

23-
Warning: Implicit float string to int conversion in %s on line %d
24-
2523
Warning: Uncaught TypeError: Cannot access offset of type string on string in %s:%d
2624
Stack trace:
2725
#0 {main}

Zend/zend_execute.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,7 +1428,7 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type
14281428
break;
14291429
}
14301430

1431-
offset = zval_get_long_func(dim);
1431+
offset = zval_get_long_func(dim, true);
14321432
} else {
14331433
offset = Z_LVAL_P(dim);
14341434
}
@@ -2361,6 +2361,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
23612361

23622362
try_string_offset:
23632363
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
2364+
bool is_lax = false;
23642365
switch (Z_TYPE_P(dim)) {
23652366
case IS_STRING:
23662367
{
@@ -2387,6 +2388,8 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
23872388
case IS_FALSE:
23882389
case IS_TRUE:
23892390
if (type != BP_VAR_IS) {
2391+
/* Warning already occurred */
2392+
is_lax = true;
23902393
zend_error(E_WARNING, "String offset cast occurred");
23912394
}
23922395
break;
@@ -2398,7 +2401,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
23982401
break;
23992402
}
24002403

2401-
offset = zval_get_long_func(dim);
2404+
offset = zval_get_long_func(dim, is_lax);
24022405
} else {
24032406
offset = Z_LVAL_P(dim);
24042407
}

Zend/zend_operators.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, bo
333333
* We use use saturating conversion to emulate strtol()'s
334334
* behaviour.
335335
*/
336-
return zend_dval_to_lval_cap(dval);
336+
return zend_dval_to_lval_cap_safe(dval);
337337
}
338338
}
339339
case IS_OBJECT:
@@ -785,7 +785,7 @@ ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
785785
}
786786
/* }}} */
787787

788-
ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op) /* {{{ */
788+
ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op, bool is_lax) /* {{{ */
789789
{
790790
try_again:
791791
switch (Z_TYPE_P(op)) {
@@ -816,7 +816,11 @@ ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op) /* {{{ */
816816
* We use saturating conversion to emulate strtol()'s
817817
* behaviour.
818818
*/
819-
return zend_dval_to_lval_cap(dval);
819+
/* For (int) casts */
820+
if (UNEXPECTED(is_lax)) {
821+
return zend_dval_to_lval_cap(dval);
822+
}
823+
return zend_dval_to_lval_cap_safe(dval);
820824
}
821825
}
822826
case IS_ARRAY:

Zend/zend_operators.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,9 @@ static zend_always_inline zend_long zend_dval_to_lval(double d)
122122
}
123123
#endif
124124

125-
/* Used to convert a string float to integer */
125+
/* Used to convert a string float to integer during an (int) cast */
126126
static zend_always_inline zend_long zend_dval_to_lval_cap(double d)
127127
{
128-
if ((double)(zend_long) d != d) {
129-
zend_error(E_WARNING, "Implicit float string to int conversion");
130-
}
131128
if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
132129
return 0;
133130
} else if (!ZEND_DOUBLE_FITS_LONG(d)) {
@@ -144,6 +141,18 @@ static zend_always_inline zend_long zend_dval_to_lval_safe(double d)
144141
}
145142
return zend_dval_to_lval(d);
146143
}
144+
static zend_always_inline zend_long zend_dval_to_lval_cap_safe(double d)
145+
{
146+
if ((double)(zend_long) d != d) {
147+
zend_error(E_WARNING, "Implicit float string to int conversion");
148+
}
149+
if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) {
150+
return 0;
151+
} else if (!ZEND_DOUBLE_FITS_LONG(d)) {
152+
return (d > 0 ? ZEND_LONG_MAX : ZEND_LONG_MIN);
153+
}
154+
return (zend_long)d;
155+
}
147156

148157
#define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
149158
#define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
@@ -279,13 +288,16 @@ ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op);
279288
ZEND_API void ZEND_FASTCALL convert_to_array(zval *op);
280289
ZEND_API void ZEND_FASTCALL convert_to_object(zval *op);
281290

282-
ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op);
291+
ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op, bool is_lax);
283292
ZEND_API double ZEND_FASTCALL zval_get_double_func(zval *op);
284293
ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op);
285294
ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op);
286295

287296
static zend_always_inline zend_long zval_get_long(zval *op) {
288-
return EXPECTED(Z_TYPE_P(op) == IS_LONG) ? Z_LVAL_P(op) : zval_get_long_func(op);
297+
return EXPECTED(Z_TYPE_P(op) == IS_LONG) ? Z_LVAL_P(op) : zval_get_long_func(op, 0);
298+
}
299+
static zend_always_inline zend_long zval_get_long_ex(zval *op, bool is_lax) {
300+
return EXPECTED(Z_TYPE_P(op) == IS_LONG) ? Z_LVAL_P(op) : zval_get_long_func(op, is_lax);
289301
}
290302
static zend_always_inline double zval_get_double(zval *op) {
291303
return EXPECTED(Z_TYPE_P(op) == IS_DOUBLE) ? Z_DVAL_P(op) : zval_get_double_func(op);

Zend/zend_vm_def.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6099,7 +6099,7 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
60996099

61006100
switch (opline->extended_value) {
61016101
case IS_LONG:
6102-
ZVAL_LONG(result, zval_get_long(expr));
6102+
ZVAL_LONG(result, zval_get_long_ex(expr, true));
61036103
break;
61046104
case IS_DOUBLE:
61056105
ZVAL_DOUBLE(result, zval_get_double(expr));

Zend/zend_vm_execute.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4602,7 +4602,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H
46024602

46034603
switch (opline->extended_value) {
46044604
case IS_LONG:
4605-
ZVAL_LONG(result, zval_get_long(expr));
4605+
ZVAL_LONG(result, zval_get_long_ex(expr, true));
46064606
break;
46074607
case IS_DOUBLE:
46084608
ZVAL_DOUBLE(result, zval_get_double(expr));
@@ -18824,7 +18824,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC
1882418824

1882518825
switch (opline->extended_value) {
1882618826
case IS_LONG:
18827-
ZVAL_LONG(result, zval_get_long(expr));
18827+
ZVAL_LONG(result, zval_get_long_ex(expr, true));
1882818828
break;
1882918829
case IS_DOUBLE:
1883018830
ZVAL_DOUBLE(result, zval_get_double(expr));
@@ -21433,7 +21433,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC
2143321433

2143421434
switch (opline->extended_value) {
2143521435
case IS_LONG:
21436-
ZVAL_LONG(result, zval_get_long(expr));
21436+
ZVAL_LONG(result, zval_get_long_ex(expr, true));
2143721437
break;
2143821438
case IS_DOUBLE:
2143921439
ZVAL_DOUBLE(result, zval_get_double(expr));
@@ -38109,7 +38109,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO
3810938109

3811038110
switch (opline->extended_value) {
3811138111
case IS_LONG:
38112-
ZVAL_LONG(result, zval_get_long(expr));
38112+
ZVAL_LONG(result, zval_get_long_ex(expr, true));
3811338113
break;
3811438114
case IS_DOUBLE:
3811538115
ZVAL_DOUBLE(result, zval_get_double(expr));

0 commit comments

Comments
 (0)