php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #51275 unpack('I', $x) on 64 bit big endian unreliable
Submitted: 2010-03-11 16:20 UTC Modified: 2011-11-16 14:17 UTC
From: stuart_hayton at uk dot ibm dot com Assigned: felipe (profile)
Status: Closed Package: Strings related
PHP Version: 5.3.2 OS: AIX64
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: stuart_hayton at uk dot ibm dot com
New email:
PHP Version: OS:

 

 [2010-03-11 16:20 UTC] stuart_hayton at uk dot ibm dot com
Description:
------------
Testing unpack 'I' format on a 64bit big-endian architecture.
The result depends on the sign bit in the *next* integer in the packed buffer 
or a out of buffer byte if it is not that long.

A patch which resolves this is below.

I think the code ends up producing identical results for the I and i
format which may be the most desirable thing but the code looks like it was
intended to behave differently. Maybe it can be simplified.

Similar to bug #40894 but a different format (I).

patch:
*** pack.c      Thu Mar 11 15:05:11 2010
--- pack.c.orig Thu Mar 11 15:03:20 2010
***************
*** 752,758 ****

                                                if (type == 'i') {
                                                        issigned = input[inputpos + (machine_little_endian ? (sizeof(int) - 1) : 0)] & 0x80;
!                                               } else if (sizeof(long) > 4 && input[inputpos + (machine_little_endian ? (sizeof(int) - 1) : 0)] & 0x80 == 0x80) {
                                                        v = ~INT_MAX;
                                                }

--- 752,758 ----

                                                if (type == 'i') {
                                                        issigned = input[inputpos + (machine_little_endian ? (sizeof(int) - 1) : 0)] & 0x80;
!                                               } else if (sizeof(long) > 4 && (input[inputpos + machine_endian_long_map[3]] & 0x80) == 0x80) {
                                                        v = ~INT_MAX;
                                                }


Test script:
---------------
<?php

echo PHP_INT_MAX."\n";
print_r(unpack('I', pack('I', -10000) . pack('I', 10000)));
print_r(unpack('I', pack('I', -10000) . pack('I', -10000)));

?>

Expected result:
----------------
9223372036854775807
Array
(
    [1] => -10000
)
Array
(
    [1] => -10000
)

Actual result:
--------------
9223372036854775807
Array
(
    [1] => 4294957296
)
Array
(
    [1] => -10000
)


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-03-12 04:45 UTC] kalle@php.net
Hi, could you please upload the patch using diff -u to the bug tracker?
 [2010-06-08 14:55 UTC] tony2001@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: kalle
 [2010-10-23 16:46 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: kalle +Assigned To:
 [2011-11-16 14:17 UTC] felipe@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: felipe
 [2011-11-16 14:17 UTC] felipe@php.net
It looks already fixed, I got the expected result.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sun May 11 10:01:27 2025 UTC