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
[email protected]
http://mail.python.org/mailman/listinfo/cplusplus-sig