Re: com php-src: fix int overflow preserving the old behavior: ext/standard/strnatcmp.c
| From: | Anatol Belski | Date: | Mon, 15 Sep 2014 08:11:41 +0000 |
| Subject: | Re: com php-src: fix int overflow preserving the old behavior: ext/standard/strnatcmp.c | ||
| References: | 1 2 | Groups: | php.cvs php.internals |
| Request: | Send a blank email to internals+get-77214@lists.php.net to get a copy of this message | ||
Moin,
On Mon, September 15, 2014 01:01, Nikita Popov wrote:
> On Sun, Sep 14, 2014 at 4:39 PM, Anatol Belski <ab@php.net> wrote:
>
>
>> Commit: 29f8b21cd71bc4af1ead7b8a93cfe09338d2eff5
>> Author: Anatol Belski <ab@php.net> Sun, 14 Sep 2014 16:37:38
>> +0200
>> Parents: eda5ba1f8fa935b8d1b8bae9d189c6afbe833287
>> Branches: master
>>
>>
>> Link:
>>
>> http://git.php.net/?p=php-src.git;a=commitdiff;h=29f8b21cd71bc4af1ead7b8
>> a93cfe09338d2eff5
>>
>> Log:
>> fix int overflow preserving the old behavior
>>
>> Changed paths:
>> M ext/standard/strnatcmp.c
>>
>>
>>
>> Diff:
>> diff --git a/ext/standard/strnatcmp.c b/ext/standard/strnatcmp.c index
>> face191..7b3826b 100644 --- a/ext/standard/strnatcmp.c
>> +++ b/ext/standard/strnatcmp.c
>> @@ -108,8 +108,25 @@ PHPAPI int strnatcmp_ex(char const *a, size_t
>> a_len, char const *b, size_t b_len int fractional, result; short leading =
>> 1;
>>
>>
>> - if (a_len == 0 || b_len == 0)
>> - return a_len - b_len;
>> + if (a_len == 0 || b_len == 0) {
>> + result = 0;
>> +
>> + if (a_len > b_len) {
>> + if (a_len - b_len <= INT_MAX) {
>> + result = (int)(a_len - b_len);
>> + } else {
>> + result = 1;
>> + }
>> + } else {
>> + if (b_len - a_len <= (size_t)(-INT_MIN)) {
>> + result = -(int)(b_len - a_len);
>> + } else {
>> + result = -1;
>> + }
>> + }
>> +
>> + return result;
>> + }
>>
>>
>> ap = a; bp = b;
>>
>
> Unless I misunderstood the purpose of this code, this looks way too
> complicated. Shouldn't this be sufficient?
>
> if (a_len == 0 || b_len == 0) { return a_len == b_len ? 0 : a_len > b_len
> ? 1 : -1;
> }
>
>
> Or:
>
>
> if (b_len == 0) { return a_len > 0; } else if (a_len == 0) {
> return -1; }
>
>
Yeah, your snippets are similar to what I did when I saw this overflow.
However 1-2 tests was failing in ext/standard as they're depending on the
exact return value. The correct and simple way is just as you say, a
compare function should return 1,0,-1 ... nothing else.
Then I just thought - making it return zend_long (to have no overflow)
isn't possible as there are pointers for compare functions which are
shared. The correct solution with 1,0,-1 breaks tests (so potentially some
userspace code). Thus this mixed solution INT_MIN < ret < INT_MAX is the
old behavior, otherwise 1,0,-1.
Simpler were to solve it correctly and fix the tests, I'd be for that
actually. Especially if nobody thinks preserving the old behavior isn't
worth it.
Regards
Anatol