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: inconsistency behavior in ctypes.c_char_p dereferencing
Type: behavior Stage: resolved
Components: ctypes Versions: Python 3.1, Python 3.2, Python 2.7
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: theller Nosy List: eryksun, iritkatriel, nullnil, theller, vladris
Priority: normal Keywords:

Created on 2010-03-17 09:09 by nullnil, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (4)
msg101214 - (view) Author: Jackson Yang (nullnil) Date: 2010-03-17 09:09
# Python 3.1.2rc1 (r312rc1:78742, Mar  7 2010, 07:49:40)
# [MSC v.1500 32 bit (Intel)] on win32
import ctypes

class T(ctypes.Structure):
	_fields_ = (
		('member', ctypes.c_char * 16),
	)

# dereference a c_char_Array variable would return <bytes>
print('%r'%((ctypes.c_char * 16)()[:]))
# dereference from a c_char_Array member would return <str>, which is buggy
print('%r'%(T().member[:]))
msg140095 - (view) Author: Vlad Riscutia (vladris) Date: 2011-07-11 00:21
Looks like this was implemented by design at some point. In cfield.c, we have specific code to treat character array fields as strings:

    /*  Field descriptors for 'c_char * n' are be scpecial cased to
        return a Python string instead of an Array object instance...
    */
    if (PyCArrayTypeObject_Check(proto)) {
        StgDictObject *adict = PyType_stgdict(proto);
        StgDictObject *idict;
        if (adict && adict->proto) {
            idict = PyType_stgdict(adict->proto);
            if (!idict) {
                PyErr_SetString(PyExc_TypeError,
                                "has no _stginfo_");
                Py_DECREF(self);
                return NULL;
            }
            if (idict->getfunc == _ctypes_get_fielddesc("c")->getfunc) {
                struct fielddesc *fd = _ctypes_get_fielddesc("s");
                getfunc = fd->getfunc;
                setfunc = fd->setfunc;
            }
#ifdef CTYPES_UNICODE
            if (idict->getfunc == _ctypes_get_fielddesc("u")->getfunc) {
                struct fielddesc *fd = _ctypes_get_fielddesc("U");
                getfunc = fd->getfunc;
                setfunc = fd->setfunc;
            }
#endif
        }
    }

Simple fix would be to just remove this whole section though this might break code which relied on string assignment to such fields. For example:

class T(ctypes.Structure):
	_fields_ = (
		('member', ctypes.c_char * 16),
	)

x = T()
x.member = bytes('Spam', 'ascii')

Above works now but will fail if change is made. There is a high chance this would break existing code as I imagine people using this due to convenience. An alternative would be to keep string setfunc but don't change getfunc, though that is also pretty inconsistent as you will be able to set a string but not get one back.

If we are willing to take the risk, fix is easy.
msg407854 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-12-06 18:36
On 3.11 I'm not getting str for the second expression, I get an empty bytes object:


>>> import ctypes
>>> class T(ctypes.Structure):
...     _fields_ = (
...             ('member', ctypes.c_char * 16),
...     )
... 
>>> print('%r'%((ctypes.c_char * 16)()[:]))
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> print('%r'%(T().member[:]))
b''
msg407878 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-12-06 23:19
This appears to be misreported. The implementation in 3.1.2rc1 looks correct to me [1]. Either way, it's out of date.

That said, the emulation of a simple type in an aggregate type is still incomplete nowadays. It's not implemented when a c_char or c_wchar array type is itself the type of an array. It's also inconsistent with simple types because the automatic get-set conversion isn't disabled for subclasses of c_char and c_wchar array types. For a subclass, one should have to use the `value` attribute.

---
[1] https://github.com/python/cpython/blob/v3.1.2rc1/Modules/_ctypes/cfield.c#L110-L137
History
Date User Action Args
2022-04-11 14:56:58adminsetgithub: 52408
2021-12-06 23:19:35eryksunsetstatus: pending -> closed

nosy: + eryksun
messages: + msg407878

resolution: out of date
stage: needs patch -> resolved
2021-12-06 18:36:08iritkatrielsetstatus: open -> pending
nosy: + iritkatriel
messages: + msg407854

2011-07-11 00:21:38vladrissetnosy: + vladris
messages: + msg140095
2010-08-05 03:41:50BreamoreBoysetstage: needs patch
versions: + Python 3.1, Python 2.7
2010-03-17 09:09:45nullnilcreate