This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: possible bug in mystrtol.c with recent gcc
Type: Stage:
Components: Interpreter Core Versions: Python 2.4
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: arigo, marienz, nmm, nnorwitz, splitscreen, tim.peters
Priority: normal Keywords:

Created on 2006-07-13 17:39 by marienz, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (14)
msg29159 - (view) Author: Marien Zwart (marienz) * Date: 2006-07-13 17:39
python 2.5b2 compiled with gentoo's gcc 4.1.1 and -O2
fails test_unary_minus in test_compile.py. Some
investigating showed that the -ftree-vrp pass of that
gcc (implied by -O2) optimizes out the "result ==
-result" test on line 215 of PyOS_strtol, meaning
PyOS_strtol of the most negative long will incorrectly
overflow. 

Python deals with this in this case by constructing a
python long object instead of a python int object, so
at least in this case the problem is not serious. I
have no idea if there is a case where this is a "real"
problem.

At first I reported this as a gentoo compiler bug, but
got the reply that:

"""
I'm pretty sure it's broken. -LONG_MIN overflows when
LONG_MIN < -LONG_MAX, and in standard C as well as "GNU
C", behaviour after overflow on signed integer
operations is undefined.
"""

(see https://bugs.gentoo.org/show_bug.cgi?id=140133)

So now I'm reporting this here. There seems to be a
LONG_MIN constant in limits.h here that could checked
against instead, but I have absolutely no idea how
standard that is. Or this could be a compiler bug after
all, in which case I would appreciate information I Can
use to back that up :)
msg29160 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2006-07-17 01:13
Logged In: YES 
user_id=33168

Is this a duplicate of 1521726?
msg29161 - (view) Author: Nick Maclaren (nmm) Date: 2006-07-17 09:20
Logged In: YES 
user_id=42444

Yes, this is a duplicate of 1521726.

The compiler people's answer is correct, and mystrtoul.c is
incorrect. LONG_MIN has been in C since C90, so should be
safe, but its value may not always be what you expect.

However, the code breakage is worse that just that test, and
there are the following 3 cases of undefined behaviour:

    1) Casting and unsigned long to long above LONG_MAX.
    2) That test.
    3) result = -result.

The fix should be to make result unsigned long, and check
the range BEFORE any conversion.  Nothing else is safe.

It is a matter of taste whether to include a fiddle for the
number that can be held only when negated - I wouldn't, and
would let that number be converted to a Python long, but
others might disagree.
msg29162 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2006-07-27 01:16
Logged In: YES 
user_id=31435

Made a non-heroic effort to repair this in rev 50855, but
have no platform on which it could make any difference (and
apparently no Python buildbot test platform cares either) .
 Would be nice if someone who has such a platform could
check against current Python trunk.
msg29163 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2006-07-27 04:35
Logged In: YES 
user_id=33168

Tim's fix corrected the problem on amd64 gentoo linux with
gcc 4.1.1.
msg29164 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2006-07-27 04:48
Logged In: YES 
user_id=33168

I reopened this bug as it still affects 2.4.  Tim's fix
should be backported.
msg29165 - (view) Author: Nick Maclaren (nmm) Date: 2006-07-27 08:31
Logged In: YES 
user_id=42444

Fixed for me, too, and the code looks solid.
msg29166 - (view) Author: Matt Fleming (splitscreen) Date: 2006-07-27 10:49
Logged In: YES 
user_id=1126061

Fixed for me on NetBSD -current AMD64, gcc 4.1.2
msg29167 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2006-07-27 21:00
Logged In: YES 
user_id=31435

Neal, as I said in the checkin comment, I expect it's no
less likely that we'll get screwed by goofy platform values
for LONG_MIN and LONG_MAX than that we /got/ screwed by an
"over ambitious" compiler optimizing away "result ==
-result", so I'm not sure backporting is a good idea.  I
stuck in an assert that might fail if a platform is insane;
if there are no reports of that assert triggering, then I'd
feel better about backporting the change.
msg29168 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2006-09-05 05:12
Logged In: YES 
user_id=33168

Tim, how do you feel about backporting now?  (Not sure if
your opinion changed based on the other bug.)  That and I'm
cleaning out my mailbox, so I don't have to look at this any
more. :-)
msg29169 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2006-09-05 05:21
Logged In: YES 
user_id=31435

Well, I deliberately avoided using LONG_MIN in the patches
for the other bug, so that should answer your question ;-)

If someone wants to take the small risk of backporting it,
fine by me -- it's not going to break on Windows, and if it
doesn't break on your box either ...
msg29170 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2006-10-03 10:10
Logged In: YES 
user_id=4771

Based on the other bug I guess that casting an arbitrary
long to unsigned long is allowed.  If so, then maybe we could
use the following test:

  if (sign == '-' && uresult == 0-(unsigned long)LONG_MIN) {
      result = LONG_MIN;
  }

which states the intention a bit more clearly and without the
assert().
msg29171 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2006-10-03 10:35
Logged In: YES 
user_id=31435

> Based on the other bug I guess that casting an arbitrary
> long to unsigned long is allowed.

Right, C defines the result of casting any integral type to
any unsigned integral type.

> If so, then maybe we could use the following test:
>
>  if (sign == '-' && uresult == 0-(unsigned
long)LONG_MIN) {
>      result = LONG_MIN;
>  }
>
> which states the intention a bit more clearly and
> without the assert().

We could.  It's not really clearer to me, given that the
current code is explained in a comment block before
PyOS_strtol(), and I couldn't care less about removing an
assert, so I'm not going to bother.  I wouldn't object to
changing it, although "0-" instead of plain unary "-" also
begs for an explanation lest someone delete the "0" because
it looks plain silly.
msg29172 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2006-10-04 12:24
Logged In: YES 
user_id=4771

Ok.  Done within the larger r52136-52139.
History
Date User Action Args
2022-04-11 14:56:18adminsetgithub: 43666
2006-07-13 17:39:49marienzcreate