On Mon, Sep 15, 2014 at 10:11 AM, Anatol Belski <a...@php.net> wrote:

> Moin,
>
> On Mon, September 15, 2014 01:01, Nikita Popov wrote:
> > On Sun, Sep 14, 2014 at 4:39 PM, Anatol Belski <a...@php.net> wrote:
> >
> >
> >> Commit:    29f8b21cd71bc4af1ead7b8a93cfe09338d2eff5
> >> Author:    Anatol Belski <a...@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.
>

I have no problem if the exact return value changes. Only the sign matters.
You can't derive anything useful from the exact value anyways.

Nikita

Reply via email to