Ctypes c_void_p overflow

eryk sun eryksun at gmail.com
Thu May 5 15:56:28 EDT 2016


On Thu, May 5, 2016 at 10:42 AM, Joseph L. Casale
<jcasale at activenetwerx.com> wrote:
> I have CDLL function I use to get a pointer, several other functions happily accept this
> pointer which is really a long when passed to ctypes.c_void_p. However, only one with
> same type def in the prototype overflows. Docs suggest c_void_p takes an int but that
> is not what the first call returns, nor what all but one function happily accept?

What you're describing isn't clear to me, so I'll describe the general
case of handling pointers with ctypes functions. If a function returns
a pointer, you must set the function's restype to a pointer type since
the default c_int restype truncates the upper half of a 64-bit
pointer. Generally you also have to do the same for pointer parameters
in argtypes. Otherwise integer arguments are converted to C int
values.

Note that when restype is set to c_void_p, the result gets converted
to a Python integer (or None for a NULL result). If you pass this
result back as a ctypes function argument, the function must have the
parameter set to c_void_p in argtypes. If argtypes isn't set, the
default integer conversion may truncate the pointer value. This
problem won't occur on a 32-bit platform, so there's a lot of
carelessly written ctypes code that makes this mistake.

Simple types are also automatically converted when accessed as a field
of a struct or union or as an index of an array or pointer. To avoid
this, you can use a subclass of the type, since ctypes won't
automatically convert subclasses of simple types.

I generally avoid c_void_p because its lenient from_param method
(called to convert arguments) doesn't provide much type safety. If a
bug causes an incorrect argument to be passed, I prefer getting an
immediate ctypes.ArgumentError rather than a segfault or data
corruption. For example, when a C API returns a void pointer as a
handle for an opaque structure or object, I prefer to handle it as a
pointer to an empty Structure subclass, as follows:

    class _ContosoHandle(ctypes.Structure):
        pass

    ContosoHandle = ctypes.POINTER(_ContosoHandle)

    lib.CreateContoso.restype = ContosoHandle
    lib.DestroyContoso.argtypes = (ContosoHandle,)

ctypes will raise an ArgumentError if DestroyContoso is called with
arguments such as 123456789 or "Crash Me".



More information about the Python-list mailing list