diff --git a/Zend/tests/bug39018.phpt b/Zend/tests/bug39018.phpt index 32566ba8646..a00e1fb819d 100644 --- a/Zend/tests/bug39018.phpt +++ b/Zend/tests/bug39018.phpt @@ -64,6 +64,8 @@ print "\nDone\n"; --EXPECTF-- Notice: String offset cast occurred in %s on line %d +Notice: Uninitialized string offset: %s in %s on line 6 + Notice: Uninitialized string offset: 0 in %s on line %d Notice: Uninitialized string offset: 0 in %s on line %d diff --git a/Zend/tests/dval_to_lval_32.phpt b/Zend/tests/dval_to_lval_32.phpt new file mode 100644 index 00000000000..f2acc39f51f --- /dev/null +++ b/Zend/tests/dval_to_lval_32.phpt @@ -0,0 +1,32 @@ +--TEST-- +zend_dval_to_lval preserves low bits (32 bit long) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(-2056257536) +int(-2055733248) +int(-2055208960) +int(-2054684672) +int(-2054160384) +int(2147483647) diff --git a/Zend/tests/dval_to_lval_64.phpt b/Zend/tests/dval_to_lval_64.phpt new file mode 100644 index 00000000000..da7f56d81ce --- /dev/null +++ b/Zend/tests/dval_to_lval_64.phpt @@ -0,0 +1,29 @@ +--TEST-- +zend_dval_to_lval preserves low bits (64 bit long) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(2943463994971652096) +int(2943463994972176384) +int(2943463994972700672) +int(2943463994973224960) +int(2943463994973749248) diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 93c60e49015..a82c14b8c26 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -68,22 +68,40 @@ END_EXTERN_C() #if ZEND_DVAL_TO_LVAL_CAST_OK # define zend_dval_to_lval(d) ((long) (d)) -#elif SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64) +#elif SIZEOF_LONG == 4 static zend_always_inline long zend_dval_to_lval(double d) { if (d > LONG_MAX || d < LONG_MIN) { - return (long)(unsigned long)(zend_long64) d; + double two_pow_32 = pow(2., 32.), + dmod; + + dmod = fmod(d, two_pow_32); + if (dmod < 0) { + /* we're going to make this number positive; call ceil() + * to simulate rounding towards 0 of the negative number */ + dmod = ceil(dmod) + two_pow_32; + } + return (long)(unsigned long)dmod; } - return (long) d; + return (long)d; } #else static zend_always_inline long zend_dval_to_lval(double d) { /* >= as (double)LONG_MAX is outside signed range */ - if (d >= LONG_MAX) { - return (long)(unsigned long) d; + if (d >= LONG_MAX || d < LONG_MIN) { + double two_pow_64 = pow(2., 64.), + dmod; + + dmod = fmod(d, two_pow_64); + if (dmod < 0) { + /* no need to call ceil; original double must have had no + * fractional part, hence dmod does not have one either */ + dmod += two_pow_64; + } + return (long)(unsigned long)dmod; } - return (long) d; + return (long)d; } #endif /* }}} */