1

I'm developing on a Mac using MacOSX 10.8.2 with the latest xcode and the stock python interpreter.

Here's some code I put into fails.cpp

#include <iostream>

using namespace std;

extern "C" {

void mysort(long *data, long data2) {
    cout << hex << *data << ' ' << data2 << endl;
}

}

Here's some code to call it from python that I put in fails.py:

import ctypes

sort_dll = ctypes.CDLL("fails.dylib")
mysort = ctypes.CFUNCTYPE(None, ctypes.POINTER(ctypes.c_long), ctypes.c_long)(sort_dll.mysort)

a = ctypes.c_long(0x987654321)
mysort(ctypes.byref(a), 0x123456789)

I compile and run with

c++ -arch x86_64 -o fails.o -c fails.cpp && g++ -o fails.dylib -dynamiclib fails.o && python fails.py

The result is:

987654321 23456789

Why is the 64-bit integer passed by value being truncated to 32 bits? Surprisingly, the pointer to a 64-bit long isn't truncated.

1 Answer 1

1

I suspect it is because the Python ctypes library has decided that c_long is 32-bits in size. There are some hints in the docs:

Represents the C signed int datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where sizeof(int) == sizeof(long) it is an alias to c_long.

This code will tell you how big c_long actually is:

import ctypes
print ctypes.sizeof(ctypes.c_long())

The value the pointer references wouldn't be truncated since ctypes only has to marshall the pointer itself. It's possible the pointer is being truncated, but it doesn't matter as the high bits are all zero anyway. It's also possible that ctypes decided that ctypes.POINTER is 64-bit. You can find out by modifying the above example just slightly.

Sign up to request clarification or add additional context in comments.

3 Comments

Good idea. But ctypes.sizeof(ctypes.c_long()) gives 8 so it's not truncating because it has the wrong size for c_long. I'm inclined to think it's a bug though I'd have though such a blatant bug would have been caught by basic testing.
It's possible the bug is in the implicit conversion from a Python int to a c_long. As a workaround, it is probably worth trying the explicit ctypes.c_long(0x123456789) as a workaround or even the int64.
I've tried quite a few combinations of code explicitly converting to 64-bit ints and they all seem to fail. My workaround is to pass by reference. It works fine but I don't know what I can trust...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.