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: ctypes docs must be more explicit about the type a func returns
Type: enhancement Stage: resolved
Components: ctypes, Documentation Versions: Python 3.5, Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Christian Kothe, docs@python, eryksun
Priority: normal Keywords:

Created on 2016-08-26 21:43 by Christian Kothe, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (2)
msg273732 - (view) Author: Christian Kothe (Christian Kothe) Date: 2016-08-26 21:43
The ctypes documentation leaves an important detail very implicit, which can cause non-deterministic hard crashes when overlooked. The issue is that when you explicitly set the .restype of a function to c_void_p, the function returns not a c_void_p (like a newcomer might assume) but an int -- and when he/she passes that value into the next library function (which should have gotten a c_void_p), then they'll get a hard crash if that memory location lies outside the 32-bit range.

I take it that the implicit assumption in ctypes is that the data types that you get back from the library calls are native python types where applicable for convenience, and the restype (just like argtypes) only configures the marshaling layer. However, that's not very explicitly stated anywhere (except maybe between the lines).
msg273750 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2016-08-27 02:36
See section 2.7 in the ctypes docs: 

    Fundamental data types, when returned as foreign function call
    results, or, for example, by retrieving structure field members
    or array items, are transparently converted to native Python
    types. In other words, if a foreign function has a restype of
    c_char_p, you will always receive a Python bytes object, not a
    c_char_p instance.

    Subclasses of fundamental data types do not inherit this
    behavior. So, if a foreign functions restype is a subclass of
    c_void_p, you will receive an instance of this subclass from the
    function call. Of course, you can get the value of the pointer
    by accessing the value attribute.

For example:

    class my_char_p(ctypes.c_char_p):
        pass

    >>> locale = ctypes.create_string_buffer(b'en_US.UTF-8')
    >>> setlocale.restype = ctypes.c_char_p
    >>> result = setlocale(0, locale)
    >>> result
    b'en_US.UTF-8'

    >>> setlocale.restype = my_char_p
    >>> result = setlocale(0, locale)
    >>> result
    my_char_p(31391216)
    >>> result.value
    b'en_US.UTF-8'

> when he/she passes that value into the next library function

A function that takes pointer arguments really should have argtypes defined so that there's no chance of accidentally getting the default integer conversion to a C int.
History
Date User Action Args
2022-04-11 14:58:35adminsetgithub: 72058
2016-08-27 02:36:01eryksunsetstatus: open -> closed

assignee: docs@python
components: + Documentation
versions: - Python 3.2, Python 3.3, Python 3.4
nosy: + docs@python, eryksun

messages: + msg273750
resolution: not a bug
stage: resolved
2016-08-26 21:43:23Christian Kothecreate