Hi Gustavo,
        I got two tests failed on Mac OS X:

➜  php-src-master git:(master) ✗ cat  Zend/tests/dval_to_lval_64.diff
001+ int(-9223372036854775808)
002+ int(-9223372036854775808)
003+ int(-9223372036854775808)
004+ int(-9223372036854775808)
005+ int(-9223372036854775808)
001- int(2943463994971652096)
002- int(2943463994972176384)
003- int(2943463994972700672)
004- int(2943463994973224960)
005- int(2943463994973749248)


➜  php-src-master git:(master) ✗ cat Zend/tests/bug39018.diff
003- Notice: Uninitialized string offset: %s in %s on line 6
004-  


$ uname -a
Darwin MacBookPro.local 12.2.0 Darwin Kernel Version 12.2.0: RELEASE_X86_64 
x86_64


--  
reeze | reeze.cn

已使用 Sparrow (http://www.sparrowmailapp.com/?sig)  

在 2013年2月24日星期日,上午12:23,Gustavo André dos Santos Lopes 写道:

> Commit: 77566edbafb969e166239b3fbc929588c6630ee9
> Author: Gustavo Lopes <glo...@nebm.ist.utl.pt 
> (mailto:glo...@nebm.ist.utl.pt)> Sun, 17 Feb 2013 23:40:26 +0100
> Parents: 64a2a8a7536de781aac015e7392cb56308d8aed0
> Branches: PHP-5.5 master
>  
> Link: 
> http://git.php.net/?p=php-src.git;a=commitdiff;h=77566edbafb969e166239b3fbc929588c6630ee9
>  
> Log:
> Fix zend_dval_to_lval outside 64bit integers range
>  
> PHP should preserve the least significant bits when casting from double
> to long. Zend.m4 contains this:
>  
> AC_DEFINE([ZEND_DVAL_TO_LVAL_CAST_OK], 1, [Define if double cast to long 
> preserves least significant bits])
>  
> If ZEND_DVAL_TO_LVAL_CAST_OK is not defined, zend_operators.h had an
> inline implementation of zend_dval_to_lval() that would do a cast to an
> int64_t (when sizeof(long) == 4), then a cast to unsigned long and
> finally the cast to long.
>  
> While this works well for doubles inside the range of values of the type
> used in the first cast (int64_t in the 32-bit version and unsigned long
> in the 64-bit version), if outside the range, it is undefined behavior
> that WILL give varying and not particularly useful results.
>  
> This commit uses fmod() to first put the double in a range that can
> safely be cast to unsigned long and then casts this unsigned long to
> long. This last cast is implementation defined, but it's very likely
> that this gives the expected result (i.e. the internal 2's complement
> representation is unchanged) on all platforms that PHP supports. In any
> case, the previous implementationa already had this assumption.
>  
> This alternative code path is indeed significantly slower than simply
> casting the double (almost an order of magnitude), but that should not
> matter because casting doubles with a very high absolute value is a
> rare event.
>  
> Changed paths:
> M Zend/tests/bug39018.phpt
> A Zend/tests/dval_to_lval_32.phpt
> A Zend/tests/dval_to_lval_64.phpt
> M Zend/zend_operators.h
>  
>  
> Diff:
> diff --git a/Zend/tests/bug39018.phpt b/Zend/tests/bug39018.phpt
> index 32566ba..a00e1fb 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 0000000..ddb16cc
> --- /dev/null
> +++ b/Zend/tests/dval_to_lval_32.phpt
> @@ -0,0 +1,29 @@
> +--TEST--
> +zend_dval_to_lval preserves low bits (32 bit long)
> +--SKIPIF--
> +<?php
> +if (PHP_INT_SIZE != 4)
> + die("skip for machines with 32-bit longs");
> +?>
> +--FILE--
> +<?php
> + /* test doubles around -4e21 */
> + $values = [
> + -4000000000000001048576.,
> + -4000000000000000524288.,
> + -4000000000000000000000.,
> + -3999999999999999475712.,
> + -3999999999999998951424.,
> + ];
> +
> + foreach ($values as $v) {
> + var_dump((int)$v);
> + }
> +
> +?>
> +--EXPECT--
> +int(-2056257536)
> +int(-2055733248)
> +int(-2055208960)
> +int(-2054684672)
> +int(-2054160384)
> diff --git a/Zend/tests/dval_to_lval_64.phpt b/Zend/tests/dval_to_lval_64.phpt
> new file mode 100644
> index 0000000..da7f56d
> --- /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--
> +<?php
> +if (PHP_INT_SIZE != 8)
> + die("skip for machines with 64-bit longs");
> +?>
> +--FILE--
> +<?php
> + /* test doubles around -4e21 */
> + $values = [
> + -4000000000000001048576.,
> + -4000000000000000524288.,
> + -4000000000000000000000.,
> + -3999999999999999475712.,
> + -3999999999999998951424.,
> + ];
> +
> + foreach ($values as $v) {
> + var_dump((int)$v);
> + }
> +
> +?>
> +--EXPECT--
> +int(2943463994971652096)
> +int(2943463994972176384)
> +int(2943463994972700672)
> +int(2943463994973224960)
> +int(2943463994973749248)
> diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
> index 93c60e4..a3a432f 100644
> --- a/Zend/zend_operators.h
> +++ b/Zend/zend_operators.h
> @@ -68,22 +68,36 @@ 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) {
> + 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) {
> + dmod += two_pow_64;
> + }
> + return (long)(unsigned long)dmod;
> }
> - return (long) d;
> + return (long)d;
> }
> #endif
> /* }}} */
>  
>  
> --  
> PHP CVS Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>  
>  


Reply via email to