php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #69906 chr() behavior difference between 32- and 64-bit bulids
Submitted: 2015-06-23 07:22 UTC Modified: 2015-06-25 08:01 UTC
Votes:2
Avg. Score:3.5 ± 0.5
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: ab@php.net Assigned:
Status: Re-Opened Package: *General Issues
PHP Version: * OS: any
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: ab@php.net
New email:
PHP Version: OS:

 

 [2015-06-23 07:22 UTC] ab@php.net
Description:
------------
When passing an integer that overflows PHP_INT_MAX in 32-bit, the behavior of chr() differs. The documentation currently doesn't define what should happen in this situation, the only statement is that chr() expects an ASCII code. chr() should ensure the input is in the valid range, thus making the behavior consistent between 32- and 64-bit.

Test script:
---------------
Debug\php.exe -r "$a = chr(2632627629); var_dump($a, ord($a));"
string(1) " "
int(0)

x64\Debug\php.exe -r "$a = chr(2632627629); var_dump($a, ord($a));"
string(1) "ยก"
int(173)


Expected result:
----------------
string(1) " "
int(0)

Actual result:
--------------
Different behavior depending on 32- or 64-bit build.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-06-23 07:56 UTC] ab@php.net
-Assigned To: +Assigned To: ab
 [2015-06-23 20:15 UTC] bwoebi@php.net
May I request to not have that changed?

That's technically a BC break, because there's code out there relying on chr() implicitly doing & 0xFF on the passed param.

I think that's rather a doc bug?
 [2015-06-23 21:30 UTC] ab@php.net
-Status: Assigned +Status: Not a bug
 [2015-06-23 21:30 UTC] ab@php.net
Hi Bob,

yeah, i was investigating on this but didn't come to update the ticket. You're right, while it's an issue :) 

I first thought it's an issue on 64-bit, now it looks the issue is on 32-bit (expected should deliver int(173)). Namely - on 32-bit the argument that overflows PHP_INT_MAX will be just truncated to zero (read as 'l' by ZPP or alike). While I saw that there could be a way to fix this on 32-bit, it would be too expensive to be justified. Thus, probably best is to leave it as is, a cast to int should do more or less correct job on this.

So kinda marking this as no bug.

Thanks.
 [2015-06-24 07:06 UTC] jan dot slabon at setasign dot com
Hi Bob, hi Anatol,

I reported that problem while talking to Anatol about another bug by email. We really had such code which got broken by this change.

So technically it is a BC break but I'm not sure if we are the only one trapping into that issue?

We encountered the problem in an Ascii85 encoder which we fixed now by casting to int explicity. So I don't have a problem with this BC break as we've a fix for it:

$r = 0;
for ($j = 0; $j < 5; ++$j) {
    $r = (int)($r * 85 + $chn[$j]);
}

$out .= chr($r >> 24)
      . chr($r >> 16)
      . chr($r >> 8)
      . chr($r);

Anyhow this problem will only arise in special situations and will not be recognized until it happens (in our case PDF documents that uses an Ascii85 filter - very rare), which may lead people to think that the code is fine with PHP 7 while it is not... 

Here are some os projects/packages which current versions are affected:

https://packagist.org/search/?q=fpdi
https://packagist.org/search/?q=mpdf
https://packagist.org/search/?q=pdfparser (depends on https://packagist.org/search/?q=tcpdf which seems to use such structure in its filter class/method, too - which is actually only used by the pdfparser)

Additionally there are some hundreds packages depending on these packages, too.

If you want to stay with this BC break this have to be documentated.

At our end this would force people to update not only to PHP 7 but to the latest library version. So I'm fine with this BC break.
Anyhow it could end in some trouble around these packages and users.

Cheers,
Jan
 [2015-06-24 09:10 UTC] ab@php.net
-Status: Not a bug +Status: Re-Opened -Type: Bug +Type: Documentation Problem -Assigned To: ab +Assigned To:
 [2015-06-24 09:10 UTC] ab@php.net
Jan,

ok, doc bug sounds appropriate. Thanks for more extended info.

Actually it's not a local BC, but might be found somewhere else and is a general behavior change. In PHP5 on 32-bit it would happily allow the internal integer argument to be overflown by that big integral constant, while in PHP7 it'll be always truncated to zero.

Thanks.
 [2015-06-24 12:06 UTC] jan dot slabon at setasign dot com
Anatol,

Do you have some other functions which are also affected by this behavior change?

Thanks!
Jan
 [2015-06-24 12:44 UTC] ab@php.net
Jan,

yeah, quite a behavior difference can be seen here and there. In most cases it's related to the implementation of https://wiki.php.net/rfc/zpp_fail_on_overflow . Additionally, we have an alternative API (aka fast ZPP) which partially replaces the old one where it makes sense, here also a slight difference can be seen. For instance, you can compare rand(0, 2632627629) on x64/x86 in PHP7 and PHP5. But actually any other functions taking integer arguments.

Hereby one should be aware that on Windows it's once more different again, because PHP7 has full 64-bit support cross platform - so it's kinda new land for the users yet. But as mentioned, it's now consistent across platforms. In general, switching to x64 would bring the most correct results probably.

Thanks.
 [2015-06-25 08:01 UTC] kalle@php.net
-PHP Version: 7.0.0alpha1 +PHP Version: *
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Thu May 23 20:01:28 2019 UTC