Bug #77742 [NEW]: bcpow() implementation related to gcc compiler optimization
| From: | samding at ca dot ibm dot com | Date: | Thu, 14 Mar 2019 16:10:38 +0000 |
| Subject: | Bug #77742 [NEW]: bcpow() implementation related to gcc compiler optimization | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-219962@lists.php.net to get a copy of this message | ||
From: samding at ca dot ibm dot com
Operating system: Linux
PHP version: 7.3.3
Package: Unknown/Other Function
Bug Type: Bug
Bug description:bcpow() implementation related to gcc compiler optimization
Description:
------------
When testing case "ext/bcmath/tests/bcpow_error2.phpt", it is found that
gcc compiler optimization ("-O2") skipped two statements in following
implementation code on s390x:
46 long
47 bc_num2long (num)
48 bc_num num;
49 {
50 long val;
51 char *nptr;
52 int index;
53
54 /* Extract the int value, ignore the fraction. */
55 val = 0;
56 nptr = num->n_value;
57 for (index=num->n_len; (index>0) && (val<=(LONG_MAX/BASE));
index--)
58 val = val*BASE + *nptr++;
59
60 /* Check for overflow. If overflow, return zero. */
61 if (index>0) val = 0; // when -O2 is
used, these 2 lines (61 & 62) are skipped and causes a wrong value
returned.
62 if (val < 0) val = 0;
....
Here is the comment from gcc compiler developer:
"this code appears to rely on a strictly defined signed overflow. But
that's not the case with C/C++. By default GCC assumes that a signed
overflow will never happen. So it will optimize away the val < 0 check
if it is possible to prove that val will never be subtracted from.
I think the reason why it hits us only on S390x is that we by default
have an unsigned char. So on S/390 the loop constantly adds a positive
value to val so GCC deduces that val can only be less than 0 if there
was an overflow.
But in the end the code is not correct I think. It relies on undefined
behavior and therefore should be fixed. Perhaps val could be turned into
an unsigned long where an overflow is well-defined?
"
A possible solution is to define "val" as "unsigned long" and
change the line 62 as " if (val >=0x8000000000000000 ) val =0;", which
does not
depend on the overflow but can detect if val >= 2**63
Test script:
---------------
sapi/cli/php run-tests.php -P ext/bcmath/tests/bcpow_error2.phpt
Expected result:
----------------
val == 0;
Actual result:
--------------
val != 0
--
Edit bug report at https://bugs.php.net/bug.php?id=77742&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=77742&r=trysnapshot54
Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=77742&r=trysnapshot55
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=77742&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=77742&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=77742&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=77742&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=77742&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=77742&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=77742&r=support
Expected behavior: https://bugs.php.net/fix.php?id=77742&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=77742&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=77742&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=77742&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=77742&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=77742&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=77742&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=77742&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=77742&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=77742&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=77742&r=mysqlcfg