Hello,

Py++ translates the struct

typedef int cb_fun_t(char *);
struct info {
   cb_fun_t* cb_fun;
   int flag;
};

into the Python Structure

class info(ctypes.Structure):
    """class info"""
info._fields_ = [ #class info
    ("cb_fun", ctypes.POINTER( ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p 
) )),
    ("flag", ctypes.c_int),
]

This is wrong and produces segfaults. The correct version is

class info(ctypes.Structure):
    """class info"""
info._fields_ = [ #class info
    ("cb_fun", ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) ),
    ("flag", ctypes.c_int),
]


I have attached a small example that demonstrates the problem. lib.c is
a small C library, build_api.py creates the broken api.py with Py++.
api_correct.py is the manually corrected API with the correct structure.
call.py demonstrates that the first API segfaults and the second API
works:

$ python call.py 
Calling do_callback with flag=7
do_callback called with flag=7
cb_fun received 'Hello World'
cb_fun returns 42
cb_fun returned 42
do_callback returned 42
Calling do_callback with flag=7
do_callback called with flag=7
Segmentation fault


Please let me know if you can reproduce the problem. It took me quite
some time to figure this out.


Best,

   -Nikolaus

-- 
 »Time flies like an arrow, fruit flies like a Banana.«

  PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C
#include <stdio.h>

typedef int cb_fun_t(char *);

struct info {
   cb_fun_t* cb_fun;
   int flag;
};

int do_callback(struct info* info) {
    char* str = "Hello World";
    int ret;
    printf("do_callback called with flag=%i\n", info->flag);
    ret = info->cb_fun(str);
    printf("cb_fun returned %i\n", ret);
    return(ret);
}
#!/usr/bin/env python

# Generate the code
from pygccxml import parser
from pygccxml import declarations
from pyplusplus.module_builder import ctypes_module_builder_t, ctypes_decls_dependencies
shared_library_path = './lib.so'
header_file = './lib.c'
gccxml_cfg = parser.gccxml_configuration_t()
mb = ctypes_module_builder_t( [header_file], shared_library_path, gccxml_config=gccxml_cfg )
mb.global_ns.decl('cb_fun_t').include()
mb.build_code_creator(shared_library_path)
mb.write_module('api.py')

# This file has been generated by Py++.

import ctypes

import ctypes_utils

lib_lib = ctypes.CDLL( r"./lib.so" )

lib_lib.undecorated_names = {#mapping between decorated and undecorated names
    "int do_callback(info * info) [free function]" : "do_callback", 
    "do_callback" : "int do_callback(info * info) [free function]", 
}

class info(ctypes.Structure):
    """class info"""

info._fields_ = [ #class info
    ("cb_fun", ctypes.POINTER( ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) )),
    ("flag", ctypes.c_int),
]

cb_fun_t = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p )

do_callback_type = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.POINTER( info )  )
do_callback = do_callback_type( ( lib_lib.undecorated_names["int do_callback(info * info) [free function]"], lib_lib ) )
# This file has been generated by Py++.

import ctypes

import ctypes_utils

lib_lib = ctypes.CDLL( r"./lib.so" )

lib_lib.undecorated_names = {#mapping between decorated and undecorated names
    "int do_callback(info * info) [free function]" : "do_callback", 
    "do_callback" : "int do_callback(info * info) [free function]", 
}

class info(ctypes.Structure):
    """class info"""

info._fields_ = [ #class info
    ("cb_fun", ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p ) ),
    ("flag", ctypes.c_int),
]

cb_fun_t = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_char_p )

do_callback_type = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.POINTER( info )  )
do_callback = do_callback_type( ( lib_lib.undecorated_names["int do_callback(info * info) [free function]"], lib_lib ) )
#!/usr/bin/env python
import api
import api_correct

def cb_fun(str):
    print 'cb_fun received %r' % str
    print 'cb_fun returns 42'
    return 42

# First try the fixed API
info = api_correct.info()
info.flag = 7
info.cb_fun = api_correct.cb_fun_t(cb_fun)
print 'Calling do_callback with flag=%d' % info.flag
ret = api_correct.do_callback(info)
print 'do_callback returned %d' % ret


# And now the one generated by Py++
from ctypes import pointer
info = api.info()
info.flag = 7
info.cb_fun = pointer(api.cb_fun_t(cb_fun))
print 'Calling do_callback with flag=%d' % info.flag
ret = api.do_callback(info)
print 'do_callback returned %d' % ret


_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to