Hi internals,

I tried to fix http://bugs.php.net/bug.php?id=38770. 
The pack and unpack function returns different values on different
platform for options like "N". 

Example:
 print_r(unpack("N", pack("N", -3000)));

prints -3000 und x86
and 4294937296 on x86_64.

That happens because all the 32 bit integers are handled as long in the
zend engine, but long differs from platform (8byte on x86_64 and 4byte on
x86).

If we pack e.g. a integer to big endian and unpack it to little endian,
the long value will be filled by the complete 4byte integer value, so
negative values are keeped. But on x86_64 (little endian) only the lower
4byte are set to the integer value while the highter 4bytes are set to
zero. Thats why the long values that holds the negative integer value is
treaten like a positive long.

Thats why I added a few lines to the pack.c to detect if I get a negative
integer (e.g. highest bit is set on little endian machines). For a
negative integer I fill the higher 4bytes with 1, so that the long value
is treaten as negative. 

You may ask why I take a 4byte _unsigned_ 32bit int from pack and test if
the highest bit is set to "cast" it to an signed integer? Thats exactly
what php does on x86 machines as it uses signed long internal.

here is the patch (against 5.2.0 release):
http://sqlbackup.net/data/pack.c.diff 


I tested it on x86_64 and x86 linux for various pack options. 

It#s not the best way, the best way might be to cast the signed integers
to unsigned in the pack command not in the unpack, but that might be a BC.

What do you think?

Greets
David

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to