[Python-Dev] Compiler warnings

James Y Knight foom at fuhm.net
Wed Feb 1 04:27:01 CET 2006


On Jan 31, 2006, at 8:16 PM, Tim Peters wrote:

> [Thomas Wouters]
>> I noticed a few compiler warnings, when I compile Python on my  
>> amd64 with
>> gcc 4.0.3:
>>
>> Objects/longobject.c: In function 'PyLong_AsDouble':
>> Objects/longobject.c:655: warning: 'e' may be used uninitialized  
>> in this function
>
> Well, that's pretty bizarre.  There's _obviously_ no way to get to a
> reference to `e` without going through
>
> 	x = _PyLong_AsScaledDouble(vv, &e);
>
> first.  That isn't a useful warning.


Look closer, and it's not quite so obvious. Here's the beginning of  
PyLong_AsDouble:
> double
> PyLong_AsDouble(PyObject *vv)
> {
>     int e;
>     double x;
>
>     if (vv == NULL || !PyLong_Check(vv)) {
>         PyErr_BadInternalCall();
>         return -1;
>     }
>     x = _PyLong_AsScaledDouble(vv, &e);
>     if (x == -1.0 && PyErr_Occurred())
>         return -1.0;
>     if (e > INT_MAX / SHIFT)
>         goto overflow;


Here's the beginning of _PyLong_AsScaledDouble:

> _PyLong_AsScaledDouble(PyObject *vv, int *exponent)
> {
> #define NBITS_WANTED 57
>     PyLongObject *v;
>     double x;
>     const double multiplier = (double)(1L << SHIFT);
>     int i, sign;
>     int nbitsneeded;
>
>     if (vv == NULL || !PyLong_Check(vv)) {
>         PyErr_BadInternalCall();
>         return -1;
>     }


Now here's the thing: _PyLong_AsScaledDouble *doesn't* set exponent  
before returning -1 there, which is where the warning comes from.  
Now, you might protest, it's impossible to go down that code path,  
because of two reasons:

1) PyLong_AsDouble has an identical "(vv == NULL || !PyLong_Check 
(vv))" check, so that codepath in _PyLong_AsScaledDouble cannot  
possibly be gone down. However, PyLong_Check is a macro which expands  
to a function call to an external function, "PyType_IsSubtype((vv)- 
 >ob_type, (&PyLong_Type)))", so GCC has no idea it cannot return an  
error the second time. This is the kind of thing C++'s const

2) There's a guard "(x == -1.0 && PyErr_Occurred())" before "e" is  
used in PyLong_AsDouble, which checks the conditions that  
_PyLong_AsScaledDouble set. Thus, e cannot possibly be used, even if  
the previous codepath *was* possible to go down. However, again,  
PyErr_BadInternalCall() is an external function, so the compiler has  
no way of knowing that PyErr_BadInternalCall() causes PyErr_Occurred 
() to return true.

So in conclusion, from all the information the compiler has available  
to it, it is giving a correct diagnostic.

James


More information about the Python-Dev mailing list