php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69693 Compatibility with x32 ABI
Submitted: 2015-05-22 18:39 UTC Modified: 2016-07-12 23:12 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: bugs at tmarques dot com Assigned:
Status: Open Package: *General Issues
PHP Version: 5.6.23 OS: Linux x32
Private report: No CVE-ID:
Have you experienced this issue?
Rate the importance of this bug to you:

 [2015-05-22 18:39 UTC] bugs at tmarques dot com
Description:
------------
This is a bug I ran into when using Wordpress normally. After running a script for a while on a x32 ABI php, it enters an infinite loop that exhausts process memory. Upon investigation, two variables that have integers get summed and return a float. Depending on the input text, the loop doesn't trigger the bug.

This doesn't happen on i386/i686, haven't tested on x86-64.

Test script:
---------------
Please see both examples at: 

https://gist.github.com/anonymous/4320f460cd1e4144df2a

Relevant code is "run.php" from lines 96 to 120.

It never triggers if I copy the $text variable to another one that's not even used ($_test).
It also returns the correct sum for a test in the code as:

if ( is_float( $i + $l ) === TRUE )

So I have to sum and check if the value is big (it usually returns some float of E+18 magnitude).



Expected result:
----------------
Integer variables sum and result in an integer.

Actual result:
--------------
Sum of two integers returns a float.

Patches

zend_operators-x32.patch (last revision 2015-05-25 01:29 UTC) by bugs at tmarques dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-05-22 18:47 UTC] bugs at tmarques dot com
P.S. I would look into this further but have no idea where to look for the problem or how to debug PHP internal's. Looking for some input and happy to help with testing in any way I can.
 [2015-05-22 22:30 UTC] danack@php.net
-Status: Open +Status: Feedback
 [2015-05-22 22:30 UTC] danack@php.net
"two variables that have integers get summed and return a float."

Yes - this is the defined behaviour for when an operation occurs and the result is no longer representable as an integer type. e.g.

<?php

$x = PHP_INT_MAX;
$x += 1;
var_dump($x);

?>

Will say that $x is a float value. Or to quote from the manual - http://php.net/manual/en/language.types.integer.php

"If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead."

If you think the conversion from int to float is occurring inappropriately, please can you provide a simple reproduction case?
 [2015-05-23 00:36 UTC] bugs at tmarques dot com
Sure, it's small values. Real code was $i=68 and $l=71, IIRC. You can see the test case on the Gist I posted in the description on the bug. There it returns a float with smaller integers. What should have been 10 or so becomes 9.xx*10^18, something like that.

As I mentioned, all code runs fine in i686 but "blows up" on x32 ABI (which is quite useful no virtualized servers).
 [2015-05-23 08:28 UTC] nikic@php.net
-Status: Feedback +Status: Open
 [2015-05-23 08:28 UTC] nikic@php.net
I don't think we currently really support the x32 ABI. You're likely tripping over some inline assembly that is not properly #if'd.
 [2015-05-25 01:27 UTC] bugs at tmarques dot com
Managed to fix some stuff, though they're mostly hacks to always run i386 code. 
Current problem is most of the Zend operators are passing 64bit instructions to x32 PHP, so I just #if'd them to add ILP32 checks to the i386 assembly instead. I think this is mostly correct (not optimized) but x86-64 assembly has the same issue with these x32 changes: it is still using x87 instead of the faster SSE2, as it should on x86-64 capable CPUs. 

From looking at the current code, I didn't understand why the FPU is being used to calculate integer operations (this shouldn't be faster).

I also think there might be problems with the 'safe_address' function in 'Zend/zend_alloc.c', as it has LP_SUFF defined for the 'mul' instruction, as it should, but uses both 'add/adc'. My understanding from the manuals is that this is correct if the operands to the instruction are 32bit for x32, then all will be ok, while 64bit operands will execute as 64bit. Still, if this is a mixup of AT&T and Intel syntax for opcodes, it should probably be unified and checked for correct word size on the parameters.

Below are the results of 'make test' before and after the patch submitted, which shows no regressions. The test case I submitted also passes now.

=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
Bug #24054 (Assignment operator *= broken) [tests/lang/bug24054.phpt]
Test >= operator : max int 32bit range [tests/lang/operators/operator_gt_or_equal_variation.phpt]
Test > operator : max int 32bit range [tests/lang/operators/operator_gt_variation.phpt]
Test <= operator : max int 32bit range [tests/lang/operators/operator_lt_or_equal_variation.phpt]
Test < operator : max int 32bit range [tests/lang/operators/operator_lt_variation.phpt]
Bug #45877 (Array key '2147483647' left as string) [Zend/tests/bug45877.phpt]
decrementing different variables [Zend/tests/decrement_001.phpt]
incrementing different variables [Zend/tests/increment_001.phpt]
Bug #41523 (strtotime('0000-00-00 00:00:00') is parsed as 1999-11-30) (32 bit) [ext/date/tests/bug41523.phpt]
Test getdate() function : usage variation - Passing high positive and negative float values to timestamp. [ext/date/tests/getdate_variation7.phpt]
Test localtime() function : usage variation - Passing higher positive and negetive float values to timestamp. [ext/date/tests/localtime_variation3.phpt]
Test array_sum() [ext/standard/tests/array/array_sum.phpt]
Bug #65304 (Use of max int in array_sum) [ext/standard/tests/array/bug65304.phpt]
Simple math tests [ext/standard/tests/math/abs.phpt]
Various pow() tests [ext/standard/tests/math/pow.phpt]
Simple math tests [ext/standard/tests/math/round.phpt]
Bug #64146 (serialize incorrectly saving objects when they are cloned) [ext/standard/tests/serialize/bug64146.phpt]
=====================================================================

Patched:

=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
Bug #41523 (strtotime('0000-00-00 00:00:00') is parsed as 1999-11-30) (32 bit) [ext/date/tests/bug41523.phpt]
Test getdate() function : usage variation - Passing high positive and negative float values to timestamp. [ext/date/tests/getdate_variation7.phpt]
Test localtime() function : usage variation - Passing higher positive and negetive float values to timestamp. [ext/date/tests/localtime_variation3.phpt]
Bug #64146 (serialize incorrectly saving objects when they are cloned) [ext/standard/tests/serialize/bug64146.phpt]
=====================================================================
 [2015-05-25 01:32 UTC] bugs at tmarques dot com
Forgot to mention I'll be looking at the rest of the tests to see if I can fix them. Pointers to the Date issues would be useful.
 [2015-05-25 09:01 UTC] nikic@php.net
For the record, PHP 7 is now mostly working on x32 as well. I've landed some tweaks in https://github.com/php/php-src/commit/f3dde29394831c59fc927bd5e7a7800a3fbe8519 which make nearly all tests pass - there's two or three failures left due to wrong size_t/zend_long usage resulting in overflows.

I went for making PHP integers 64bit - this integrates very nicely with how zend_long is currently used (all our assembly is still correct) and I think this is what PHP programmers would want to have. But not totally sure if this is the right choice.
 [2015-05-25 09:02 UTC] nikic@php.net
-Summary: Reproducible Corruption on Variables +Summary: Compatibility with x32 ABI
 [2015-10-17 14:14 UTC] bugs at tmarques dot com
-PHP Version: 5.5.25 +PHP Version: 5.6.13
 [2015-10-17 14:14 UTC] bugs at tmarques dot com
Hey there,

Had been looking at the date bugs I posted before from the test suite but everything seemed fine where I looked. Today I tried the zend operators patch on 5.6.13 and those are gone. Tests below configured with:

=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
Bug #53437 DateInterval unserialize bad data, 32 bit [ext/date/tests/bug53437_var3.phpt]
Bug #64146 (serialize incorrectly saving objects when they are cloned) [ext/standard/tests/serialize/bug64146.phpt]
=====================================================================
WARNED TEST SUMMARY
---------------------------------------------------------------------
Bug #70172 - Use After Free Vulnerability in unserialize()
[ext/standard/tests/serialize/bug70172.phpt] (warn: XFAIL section but test passes)
=====================================================================

Compiled on i686 to check for differences and the i686 versions shows one more failed test but is otherwise the same. I imagine this is due to some fix related to x86-64.

=====================================================================
Bug #41655 (open_basedir bypass via glob()) 1/2 [ext/standard/tests/file/bug41655_1.phpt]
chroot() [ext/standard/tests/file/chroot_001.phpt]
Test glob() function: ensure no platform difference, variation 3 [ext/standard/tests/file/glob_variation5.phpt]
=====================================================================

At this time, the zend_operators patch seems to work for these versions, so could it possibly be merged?

Glad to hear PHP7 is looking good on x32! As for the integer size, it would be better to be 32bit to be consistent with C and be able to make use of both of 32 and 64bit registers, which is one of the performance benefits. My understanding is that PHP only supports one integer size, so being 64bit is probably better if the programmer can't choose.
 [2016-07-12 23:12 UTC] bugs at tmarques dot com
-PHP Version: 5.6.13 +PHP Version: 5.6.23
 [2016-07-12 23:12 UTC] bugs at tmarques dot com
Hey there,

Been trying x32 on PHP 7 and it has various bugs that keep it from working. I've been trying to fix some stuff but still have problems with PHAR during compilation, which seems to stem from a memcpy().

Would it be possible to merge this updated patch below? I backported some changes from the assembly in PHP 7 that seems to fix a movb that was malformed. It works on both 5.5.37 and 5.6.23.

There are some 32-bit tests that fail because time values are expected to overflow and don't, which haven't tracked but may be related to x32 having 64-bit time values.

https://github.com/tmarques/overlay_x32-abi/raw/master/dev-lang/php/files/zend_operators_x32-5.patch
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue May 23 03:01:36 2017 UTC