[Python-Dev] Why is nb_inplace_add copied to sq_inplace_concat?

Matt Newell newellm at blur.com
Fri May 17 01:17:20 CEST 2013


I have encountered what I believe to be a bug but I'm sure there is some 
reason things are done as they are and I am hoping someone can shed some light 
or confirm it is indeed a bug.

As a bit of background I have a c++ class that I use sip to generate python 
bindings.  The potential python bug manifests itself as:

>>> rl = RecordList()
>>> rl += []
>>> rl
NotImplemented

The bindings fill in nb_inplace_add which appears to be implemented properly, 
returning a new reference to Py_NotImplemented if the right hand argument is 
not as expected.

Where things appear to go wrong is that PyNumber_InPlaceAdd, after getting a 
NotImplemented return value from nb_inplace_add, then attempts to call 
sq_inplace_concat.  From reading the code it appears that sq_inplace_concat is 
not supposed to return NotImplemented, instead it should set an exception and 
return null if the right hand arg is not supported.  In my case 
sq_inplace_concat ends up being the same function as nb_inplace_add, which 
results in the buggy behavior.

When I figured this out I tried to find out why sq_inplace_concat was set to the 
same function as nb_inplace_add, and ended up having to set a watchpoint in 
gdb which finally gave me the answer that python itself is setting 
sq_inplace_concat during type creation in the various functions in 
typeobject.c. Stack trace is below.

I don't really understand what the fixup_slot_dispatchers function is doing, 
but it does seem like there must be a bug either in what it's doing, or in 
PyNumber_InPlaceAdd's handling of a NotImplemented return value from 
sq_inplace_concat.

Thanks,
Matt



Python 2.7.3 (default, Jan  2 2013, 13:56:14) 
[GCC 4.7.2] on linux2


Stack trace where a watch on sq->sq_inplace_concat reveals the change:

Hardware watchpoint 5: *(binaryfunc *) 0xcf6f88

Old value = (binaryfunc) 0
New value = (binaryfunc) 0x7ffff4d41c78 <slot_RecordList___iadd__(PyObject*, 
PyObject*)>

#0  update_one_slot.25588 (type=type at entry=0xcf6c70, p=0x86ba90) at 
../Objects/typeobject.c:6203
#1  0x00000000004b96d0 in fixup_slot_dispatchers (type=0xcf6c70) at 
../Objects/typeobject.c:6299
#2  type_new.part.40 (kwds=<optimized out>, args=0x0, metatype=<optimized 
out>) at ../Objects/typeobject.c:2464
#3  type_new.25999 (metatype=<optimized out>, args=0x0, kwds=<optimized out>) 
at ../Objects/typeobject.c:2048
#4  0x0000000000463c08 in type_call.25547 (type=0x7ffff65953a0, 
args=('RecordList', (<sip.wrappertype at remote 0x7ffff5201080>,), 
{'__module__': 'blur.Stone'}), kwds=0x0) at ../Objects/typeobject.c:721
#5  0x00000000004644eb in PyObject_Call (func=<type at remote 0x7ffff65953a0>, 
arg=<optimized out>, kw=<optimized out>) at ../Objects/abstract.c:2529




More information about the Python-Dev mailing list