[Cython] Core dump when Python is built without debug symbols

Marin Atanasov Nikolov dnaeon at gmail.com
Thu May 30 15:51:16 CEST 2013


On Thu, May 30, 2013 at 3:08 PM, Nikita Nemkin <nikita at nemkin.ru> wrote:
>
>
> In pkg-db.pxi, this line:
>
>         return Pkg(<object>pkg)
>
> and in pkg-pkg.pxi this line:
>
>     def __cinit__(self, pkg):
>         self._pkg = <c_pkg.pkg *>pkg
>
> are the problem.
>
>
Thanks, Nikita! That was the problem indeed :)

The funny part is that I was looking for a way to actually pass a C pointer
to __cinit__ and doing it that way the compiler didn't complain at all. In
fact it used to work, until I've removed Python debug symbols and then I
started seeing surprises :)


> You are trying to pass a C pointer to __cinit__. What actually
> happens is that, because of the <object> cast, Cython treats pkg as
> as Python object _itself_ and tries to do some object operations on it.
>
> Two ways to solve this (really common) problem:
>
> 1) Pass your pointer as a real python object containing the integer value
>    of the pointer:
>
>     def __cinit__(self, pkg):
>         self._pkg = <c_pkg.pkg *><Py_ssize_t>pkg  # or Py_intptr_t
>
>     return Pkg(<object><Py_ssize_t>pkg)
>
>     Note the <Py_ssize_t> cast. When used on a C pointer, it makes a C
>     integer that Cython convert to python int object. And when <Py_ssize_t>
>     is used on a python int object, Cyton extracts its integer value
>     as a C-level value, so it is castable to a C-level pointer.
>
>     Using Py_ssize_t (or Py_intptr_t or your platform intptr_t) guarantees
>     that the pointer will fit.
>
> 2) Don't use __cinit__. Declare your own cdef init method and call that.
>    Since it's cdef method, it can take any C-level arguments, pointerw,
>    whatever without the need to convert to python objects and back.
>
>    @cython.final  # small optimization
>    cdef _init(self, c_pkg.pkg * pkg):
>         self._pkg = pkg
>
>    # cdef __cinit__ not needed. Maybe use it to set default
>    # attribute values.
>
>    cdef Pkg pkg = Pkg.__new__(Pkg)  # fast object creation. Pkg() also
> works.
>    pkg._init(pkg)
>
>    (When you use the __new__ trick, __cnit__ is called without
>    arguments and __init__ is not called at all. The benefit to
>    this ugly syntax is that __new__ is faster than creating the object
>    with traditional Pyhton syntax.)
>
> Also, if all your initialization is pointer assigment, you can
> just do it directly:
>
>    cdef Pkg pkg = Pkg.__new__(Pkg)  # fast object creation
>    pkg._pkg = pkg
>
>
>
I've chosen to stick with 2) -- I guess I like it better and having an
additional _init() is fine with me, makes things clearer. Thanks again!


> There is a problem related to cython-dev. I think the code you
> wrote should have never compiled in the first place. <PyObject*>
> cast must be required if you want to reinterpret a C pointer
> as object or vice versa.
>
>
Actually the code compiles just fine and also works as expected :) The only
condition is to have Python with debug symbols installed.

Any idea why having Python with debug symbols actually overcomes this issue?

Thanks again Nikita!

Best regards,
Marin


>
> Best regards,
> Nikita Nemkin
> ______________________________**_________________
> cython-devel mailing list
> cython-devel at python.org
> http://mail.python.org/**mailman/listinfo/cython-devel<http://mail.python.org/mailman/listinfo/cython-devel>
>



-- 
Marin Atanasov Nikolov

dnaeon AT gmail DOT com
http://www.unix-heaven.org/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cython-devel/attachments/20130530/3feec5b4/attachment-0001.html>


More information about the cython-devel mailing list