Search code examples
pythonc++macospointerspython-cffi

How to support 64 bits pointers in cffi?


I'm using cffi to interface my Python module with a C-library.

I got everything working fine on Linux but I'm having a hard time with Mac OS X (Yosemite - 64 bits). Here is a minimal sample I wrote that shows the problem:

foo.h

#ifndef FOO_H
#define FOO_H
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

void* mymalloc(size_t);

#ifdef __cplusplus
}
#endif
#endif

foo.cpp

#include "foo.h"

#include <cstdlib>
#include <cstdio>

void* mymalloc(size_t size) {
    void* const result = ::malloc(size);
    printf("%p\n", result);
    return result;
}

Makefile

run: foo.py libfoo.dylib
    DYLD_LIBRARY_PATH=. LIBRARY_PATH=. python foo.py

libfoo.dylib: foo.cpp foo.h
    g++ -dynamiclib -o $@ $<

foo.py

import cffi

ffi = cffi.FFI()
ffi.cdef("""
         void* malloc(size_t);
         void* mymalloc(size_t);
         """)
api = ffi.verify("", libraries=['foo'])
result = api.malloc(4)
print "malloc", result
result = api.mymalloc(4)
print "mymalloc", result

So nothing too fancy here: a simple mymalloc(size_t) functions that acts as a wrapper for the real malloc(size_t) one and shows the generated pointer before returning.

When executing foo.py (with make run), I however see the following output:

g++ -dynamiclib -o libfoo.dylib foo.cpp
DYLD_LIBRARY_PATH=. LIBRARY_PATH=. python foo.py
malloc <cdata 'void *' 0x7fdba0e01670>
0x7fdba0e00280
mymalloc <cdata 'void *' 0xffffffffa0e00280>

In the case of mymalloc(size_t), it seems that cffi somehow truncated/modified the pointer integral value: I get 0xffffffffa0e00280 instead of the expected 0x7fdba0e00280. This is basically the value of the pointer but stored only on 32 bits. malloc(size_t) which has the exact same prototype seems however to be correctly handled by cffi and returns a 64 bits address.

I'm at loss trying to find what I do wrong here. Would anyone have a clue ?


Solution

  • According to an official answer, my way of calling verify() is bogus.

    The correct code should read:

    import cffi
    
    ffi = cffi.FFI()
    code = """
        void* malloc(size_t);
        void* mymalloc(size_t);
    """
    ffi.cdef(code)
    api = ffi.verify(code, libraries=['foo'])
    result = api.malloc(4)
    print "malloc", result
    result = api.mymalloc(4)
    print "mymalloc", result
    

    Which indeeds yields the expected result !