Bug #77742 [NEW]: bcpow() implementation related to gcc compiler optimization

From: 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

« previous php.bugs (#219962) next »