Title: Crash when returning a 64-bit char pointer in Python 2.6.3 ctypes
Type: crash Stage:
Components: ctypes Versions: Python 2.6
Status: closed Resolution:
Dependencies: Superseder:
Assigned To: theller Nosy List: Trundle, creachadair, theller
Priority: normal Keywords:

Created on 2009-10-17 16:31 by creachadair, last changed 2009-10-19 14:50 by creachadair. This issue is now closed.

File name Uploaded Description Edit
testlib.c creachadair, 2009-10-17 16:31 Test program to reproduce the described error.
crash-report.txt creachadair, 2009-10-17 16:31 MacOS X crash reporter log
Messages (4)
msg94181 - (view) Author: Michael J. Fromberger (creachadair) Date: 2009-10-17 16:31
A segmentation fault is generated in when calling a function that returns a char pointer on a system 
with 64-bit pointer types.  The attached crash dump is from a Python 2.6.3 built from MacPorts ("port install 
python26 +no_tkinter"), but the same behaviour occurs with the Python 2.6.1 installed by Apple.

To reproduce, build the attached sample program ("testlib.c"):

% gcc -Wall -c testlib.o
% ld -dylib -o testlib.o

Then, in Python:

# Common setup for each of the cases below.
>>> from ctypes import *
>>> lib = CDLL('')

# Case 1: Integer return value (no crash).
>>> get_value = CFUNCTYPE(c_int)(lib.get_value)
>>> get_value()

# Case 2: Pointer argument value (no crash).
>>> buf = create_string_buffer(256)
>>> copy_message = CFUNCTYPE(None, c_char_p)(lib.copy_message)
>>> copy_message(buf)

# Case 3: Pointer return value (crash).
>>> get_message = CFUNCTYPE(c_char_p)(lib.get_message)
>>> get_message()
Segmentation fault

-- System information:

% uname -a
MacOS 10.6.1
Darwin gorion.local 10.0.0 Darwin Kernel Version 10.0.0: Fri Jul 31 22:47:34 PDT 2009; root:xnu-
1456.1.25~1/RELEASE_I386 i386

% python
Python 2.6.3 (r263:75183, Oct 17 2009, 01:49:30) 
[GCC 4.2.1 (Apple Inc. build 5646) (dot 1)] on darwin

% gcc --version
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) (dot 1)
msg94182 - (view) Author: Michael J. Fromberger (creachadair) Date: 2009-10-17 16:47
I believe this error occurs because a pointer value is being truncated to 
32 bits.  The exception code is

KERN_INVALID_ADDRESS at 0x00000000002fe020

If you add a diagnostic printout to the body of get_message(), you will 
see that its return value is 0x1002fe020, so in other words, the high-
order word 0x00000001 is being discarded somewhere.
msg94183 - (view) Author: Andreas Stührk (Trundle) * Date: 2009-10-17 17:10
You are using `CFUNCTYPE` wrong. `CFUNCTYPE` returns a type which will 
take a *Python function* (or an address of a function as integer). You 
provide `lib.get_message` as Python function, which is a wrapper object 
for the C function. By default, ctypes assumes an int as return type for 
C functions. On your platform, the size of an int is not the same as the 
size of a pointer. Therefore, the return value is truncated. You call 
the CFUNCTION which then calls `lib.get_message` which returns the 
truncated pointer as integer and then ctypes tries to make a `c_char_p` 
out of the integer which segfaults because it's truncated.

I think what you are really looking for is ``lib.get_message.restype = 
msg94239 - (view) Author: Michael J. Fromberger (creachadair) Date: 2009-10-19 14:50
Thank you for setting me straight. 

I see now that I misunderstood the scope of `CFUNCTYPE`, as I was using 
it as a general wrapper when in fact it's only needed for callbacks. 
Mistakenly, I inferred from reading section of the ctypes 
manual [1] that it would be necessary to create prototype wrappers for 
calls into the foreign library as well. Obviously that is not the case, 
since your described solution works fine.

[1] <
Date User Action Args
2009-10-19 14:50:22creachadairsetstatus: open -> closed

messages: + msg94239
2009-10-17 17:10:26Trundlesetnosy: + Trundle
messages: + msg94183
2009-10-17 16:47:40creachadairsetmessages: + msg94182
2009-10-17 16:31:49creachadairsetfiles: + crash-report.txt
2009-10-17 16:31:03creachadaircreate