def test_address_of_global_var(): ffi = FFI() ffi.cdef(""" long bottom, bottoms[2]; long FetchRectBottom(void); long FetchRectBottoms1(void); #define FOOBAR 42 """) lib = verify( ffi, "test_address_of_global_var", """ long bottom, bottoms[2]; long FetchRectBottom(void) { return bottom; } long FetchRectBottoms1(void) { return bottoms[1]; } #define FOOBAR 42 """) lib.bottom = 300 assert lib.FetchRectBottom() == 300 lib.bottom += 1 assert lib.FetchRectBottom() == 301 lib.bottoms[1] = 500 assert lib.FetchRectBottoms1() == 500 lib.bottoms[1] += 2 assert lib.FetchRectBottoms1() == 502 # p = ffi.addressof(lib, 'bottom') assert ffi.typeof(p) == ffi.typeof("long *") assert p[0] == 301 p[0] += 1 assert lib.FetchRectBottom() == 302 p = ffi.addressof(lib, 'bottoms') assert ffi.typeof(p) == ffi.typeof("long(*)[2]") assert p[0] == lib.bottoms # py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var') py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR")
def test_verify_struct(): ffi = FFI() ffi.cdef("""struct foo_s { int b; short a; ...; }; struct bar_s { struct foo_s *f; };""") lib = verify(ffi, 'test_verify_struct', """struct foo_s { short a; int b; }; struct bar_s { struct foo_s *f; };""") ffi.typeof("struct bar_s *") p = ffi.new("struct foo_s *", {'a': -32768, 'b': -2147483648}) assert p.a == -32768 assert p.b == -2147483648 py.test.raises(OverflowError, "p.a -= 1") py.test.raises(OverflowError, "p.b -= 1") q = ffi.new("struct bar_s *", {'f': p}) assert q.f == p # assert ffi.offsetof("struct foo_s", "a") == 0 assert ffi.offsetof("struct foo_s", "b") == 4 assert ffi.offsetof(u+"struct foo_s", u+"b") == 4 # py.test.raises(TypeError, ffi.addressof, p) assert ffi.addressof(p[0]) == p assert ffi.typeof(ffi.addressof(p[0])) is ffi.typeof("struct foo_s *") assert ffi.typeof(ffi.addressof(p, "b")) is ffi.typeof("int *") assert ffi.addressof(p, "b")[0] == p.b
def test_address_of_global_var(): ffi = FFI() ffi.cdef(""" long bottom, bottoms[2]; long FetchRectBottom(void); long FetchRectBottoms1(void); #define FOOBAR 42 """) lib = verify(ffi, "test_address_of_global_var", """ long bottom, bottoms[2]; long FetchRectBottom(void) { return bottom; } long FetchRectBottoms1(void) { return bottoms[1]; } #define FOOBAR 42 """) lib.bottom = 300 assert lib.FetchRectBottom() == 300 lib.bottom += 1 assert lib.FetchRectBottom() == 301 lib.bottoms[1] = 500 assert lib.FetchRectBottoms1() == 500 lib.bottoms[1] += 2 assert lib.FetchRectBottoms1() == 502 # p = ffi.addressof(lib, 'bottom') assert ffi.typeof(p) == ffi.typeof("long *") assert p[0] == 301 p[0] += 1 assert lib.FetchRectBottom() == 302 p = ffi.addressof(lib, 'bottoms') assert ffi.typeof(p) == ffi.typeof("long(*)[2]") assert p[0] == lib.bottoms # py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var') py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR")
def test_verify_struct(): ffi = FFI() ffi.cdef("""struct foo_s { int b; short a; ...; }; struct bar_s { struct foo_s *f; };""") lib = verify( ffi, 'test_verify_struct', """struct foo_s { short a; int b; }; struct bar_s { struct foo_s *f; };""") ffi.typeof("struct bar_s *") p = ffi.new("struct foo_s *", {'a': -32768, 'b': -2147483648}) assert p.a == -32768 assert p.b == -2147483648 py.test.raises(OverflowError, "p.a -= 1") py.test.raises(OverflowError, "p.b -= 1") q = ffi.new("struct bar_s *", {'f': p}) assert q.f == p # assert ffi.offsetof("struct foo_s", "a") == 0 assert ffi.offsetof("struct foo_s", "b") == 4 assert ffi.offsetof(u + "struct foo_s", u + "b") == 4 # py.test.raises(TypeError, ffi.addressof, p) assert ffi.addressof(p[0]) == p assert ffi.typeof(ffi.addressof(p[0])) is ffi.typeof("struct foo_s *") assert ffi.typeof(ffi.addressof(p, "b")) is ffi.typeof("int *") assert ffi.addressof(p, "b")[0] == p.b
def test_variable_of_unknown_size(): ffi = FFI() ffi.cdef(""" typedef ... opaque_t; opaque_t globvar; """) lib = verify( ffi, 'test_constant_of_unknown_size', """ typedef char opaque_t[6]; opaque_t globvar = "hello"; """) # can't read or write it at all e = py.test.raises(TypeError, getattr, lib, 'globvar') assert str(e.value) in [ "cdata 'opaque_t' is opaque", "'opaque_t' is opaque or not completed yet" ] #pypy e = py.test.raises(TypeError, setattr, lib, 'globvar', []) assert str(e.value) in [ "'opaque_t' is opaque", "'opaque_t' is opaque or not completed yet" ] #pypy # but we can get its address p = ffi.addressof(lib, 'globvar') assert ffi.typeof(p) == ffi.typeof('opaque_t *') assert ffi.string(ffi.cast("char *", p), 8) == b"hello"
def test_addressof_lib(self): if self.module is None: py.test.skip("fix the auto-generation of the tiny test lib") if self.Backend is CTypesBackend: py.test.skip("not implemented with the ctypes backend") ffi = FFI(backend=self.Backend()) ffi.cdef("long left; int test_getting_errno(void);") lib = ffi.dlopen(self.module) lib.left = 123456 p = ffi.addressof(lib, "left") assert ffi.typeof(p) == ffi.typeof("long *") assert p[0] == 123456 p[0] += 1 assert lib.left == 123457 pfn = ffi.addressof(lib, "test_getting_errno") assert ffi.typeof(pfn) == ffi.typeof("int(*)(void)") assert pfn == lib.test_getting_errno
def test_address_of_function_with_struct(): ffi = FFI() ffi.cdef("struct foo_s { int x; }; long myfunc(struct foo_s);") lib = verify(ffi, "test_addressof_function_with_struct", """ struct foo_s { int x; }; char myfunc(struct foo_s input) { return (char)(input.x + 42); } """) s = ffi.new("struct foo_s *", [5])[0] assert lib.myfunc(s) == 47 assert not isinstance(lib.myfunc, ffi.CData) assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)") addr = ffi.addressof(lib, 'myfunc') assert addr(s) == 47 assert isinstance(addr, ffi.CData) assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)")
def test_address_of_function(): ffi = FFI() ffi.cdef("long myfunc(long x);") lib = verify(ffi, "test_addressof_function", """ char myfunc(char x) { return (char)(x + 42); } """) assert lib.myfunc(5) == 47 assert lib.myfunc(0xABC05) == 47 assert not isinstance(lib.myfunc, ffi.CData) assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(long)") addr = ffi.addressof(lib, 'myfunc') assert addr(5) == 47 assert addr(0xABC05) == 47 assert isinstance(addr, ffi.CData) assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
def test_macro_var_callback(): ffi = FFI() ffi.cdef("int my_value; int *(*get_my_value)(void);") lib = verify(ffi, 'test_macro_var_callback', "int *(*get_my_value)(void);\n" "#define my_value (*get_my_value())") # values = ffi.new("int[50]") def it(): for i in range(50): yield i it = it() # @ffi.callback("int *(*)(void)") def get_my_value(): for nextvalue in it: return values + nextvalue lib.get_my_value = get_my_value # values[0] = 41 assert lib.my_value == 41 # [0] p = ffi.addressof(lib, 'my_value') # [1] assert p == values + 1 assert p[-1] == 41 assert p[+1] == 0 lib.my_value = 42 # [2] assert values[2] == 42 assert p[-1] == 41 assert p[+1] == 42 # # if get_my_value raises or returns nonsense, the exception is printed # to stderr like with any callback, but then the C expression 'my_value' # expand to '*NULL'. We assume here that '&my_value' will return NULL # without segfaulting, and check for NULL when accessing the variable. @ffi.callback("int *(*)(void)") def get_my_value(): raise LookupError lib.get_my_value = get_my_value py.test.raises(ffi.error, getattr, lib, 'my_value') py.test.raises(ffi.error, setattr, lib, 'my_value', 50) py.test.raises(ffi.error, ffi.addressof, lib, 'my_value') @ffi.callback("int *(*)(void)") def get_my_value(): return "hello" lib.get_my_value = get_my_value py.test.raises(ffi.error, getattr, lib, 'my_value') e = py.test.raises(ffi.error, setattr, lib, 'my_value', 50) assert str(e.value) == "global variable 'my_value' is at address NULL"
def test_variable_of_unknown_size(): ffi = FFI() ffi.cdef(""" typedef ... opaque_t; opaque_t globvar; """) lib = verify(ffi, 'test_variable_of_unknown_size', """ typedef char opaque_t[6]; opaque_t globvar = "hello"; """) # can't read or write it at all e = py.test.raises(TypeError, getattr, lib, 'globvar') assert str(e.value) in ["cdata 'opaque_t' is opaque", "'opaque_t' is opaque or not completed yet"] #pypy e = py.test.raises(TypeError, setattr, lib, 'globvar', []) assert str(e.value) in ["'opaque_t' is opaque", "'opaque_t' is opaque or not completed yet"] #pypy # but we can get its address p = ffi.addressof(lib, 'globvar') assert ffi.typeof(p) == ffi.typeof('opaque_t *') assert ffi.string(ffi.cast("char *", p), 8) == b"hello"
class TestLocationdLib(unittest.TestCase): def setUp(self): header = '''typedef ...* Localizer_t; Localizer_t localizer_init(); void localizer_get_message_bytes(Localizer_t localizer, uint64_t logMonoTime, bool inputsOK, bool sensorsOK, bool gpsOK, char *buff, size_t buff_size); void localizer_handle_msg_bytes(Localizer_t localizer, const char *data, size_t size);''' self.ffi = FFI() self.ffi.cdef(header) self.lib = self.ffi.dlopen(LIBLOCATIOND_PATH) self.localizer = self.lib.localizer_init() self.buff_size = 2048 self.msg_buff = self.ffi.new(f'char[{self.buff_size}]') def localizer_handle_msg(self, msg_builder): bytstr = msg_builder.to_bytes() self.lib.localizer_handle_msg_bytes(self.localizer, self.ffi.from_buffer(bytstr), len(bytstr)) def localizer_get_msg(self, t=0, inputsOK=True, sensorsOK=True, gpsOK=True): self.lib.localizer_get_message_bytes( self.localizer, t, inputsOK, sensorsOK, gpsOK, self.ffi.addressof(self.msg_buff, 0), self.buff_size) return log.Event.from_bytes(self.ffi.buffer(self.msg_buff), nesting_limit=self.buff_size // 8) def test_liblocalizer(self): msg = messaging.new_message('liveCalibration') msg.liveCalibration.validBlocks = random.randint(1, 10) msg.liveCalibration.rpyCalib = [random.random() for _ in range(3)] self.localizer_handle_msg(msg) liveloc = self.localizer_get_msg() self.assertTrue(liveloc is not None) def test_device_fell(self): msg = messaging.new_message('sensorEvents', 1) msg.sensorEvents[0].sensor = 1 msg.sensorEvents[0].type = 1 msg.sensorEvents[0].init('acceleration') msg.sensorEvents[0].acceleration.v = [10.0, 0.0, 0.0] # zero with gravity self.localizer_handle_msg(msg) ret = self.localizer_get_msg() self.assertTrue(ret.liveLocationKalman.deviceStable) msg = messaging.new_message('sensorEvents', 1) msg.sensorEvents[0].sensor = 1 msg.sensorEvents[0].type = 1 msg.sensorEvents[0].init('acceleration') msg.sensorEvents[0].acceleration.v = [50.1, 0.0, 0.0] # more than 40 m/s**2 self.localizer_handle_msg(msg) ret = self.localizer_get_msg() self.assertFalse(ret.liveLocationKalman.deviceStable) def test_posenet_spike(self): for _ in range(SENSOR_DECIMATION): msg = messaging.new_message('carState') msg.carState.vEgo = 6.0 # more than 5 m/s self.localizer_handle_msg(msg) ret = self.localizer_get_msg() self.assertTrue(ret.liveLocationKalman.posenetOK) for _ in range(20 * VISION_DECIMATION): # size of hist_old msg = messaging.new_message('cameraOdometry') msg.cameraOdometry.rot = [0.0, 0.0, 0.0] msg.cameraOdometry.rotStd = [0.0, 0.0, 0.0] msg.cameraOdometry.trans = [0.0, 0.0, 0.0] msg.cameraOdometry.transStd = [2.0, 0.0, 0.0] self.localizer_handle_msg(msg) for _ in range(20 * VISION_DECIMATION): # size of hist_new msg = messaging.new_message('cameraOdometry') msg.cameraOdometry.rot = [0.0, 0.0, 0.0] msg.cameraOdometry.rotStd = [0.0, 0.0, 0.0] msg.cameraOdometry.trans = [0.0, 0.0, 0.0] msg.cameraOdometry.transStd = [8.1, 0.0, 0.0] # more than 4 times larger self.localizer_handle_msg(msg) ret = self.localizer_get_msg() self.assertFalse(ret.liveLocationKalman.posenetOK)
""" ) # struct MyCom mycom = {0}; # typedef struct { # int n; # } mycom; lib = ffi.dlopen("build/libdynamic.so") mycom = ffi.new("struct MyCom *", [5]) print("Python mycom.n", mycom.n) mycom.n += 1 print("Python mycom.n", mycom.n) mycom[0] = {"n": 777} print("Python mycom.n", mycom.n) print("Type of Python mycom =", type(mycom)) print("Address of Python mycom =", ffi.addressof(mycom, 0)) print("Address of hello =", ffi.addressof(lib, "hello")) print("Address of /mycom/ =", ffi.addressof(lib, "mycom")) print("Python modifying /mycom/ n...") lib.mycom.n = 778 # n = ffi.cast("int", 1) # mycom = ffi.new("mycom *", {"n": 1}) # print(mycom) lib.hello()
def test_types(tp_args, tp_result): global TEST_RUN_COUNTER print(tp_args, tp_result) cdefs = [] structs = {} def build_type(tp): if type(tp) is list: field_types = [build_type(tp1) for tp1 in tp] fields = ['%s f%d;' % (ftp, j) for (j, ftp) in enumerate(field_types)] fields = '\n '.join(fields) name = 's%d' % len(cdefs) cdefs.append("typedef struct {\n %s\n} %s;" % (fields, name)) structs[name] = field_types return name else: return tp args = [build_type(tp) for tp in tp_args] result = build_type(tp_result) TEST_RUN_COUNTER += 1 signature = "%s testfargs(%s)" % (result, ', '.join(['%s a%d' % (arg, i) for (i, arg) in enumerate(args)]) or 'void') source = list(cdefs) cdefs.append("%s;" % signature) cdefs.append("extern %s testfargs_result;" % result) for i, arg in enumerate(args): cdefs.append("extern %s testfargs_arg%d;" % (arg, i)) source.append("%s testfargs_result;" % result) for i, arg in enumerate(args): source.append("%s testfargs_arg%d;" % (arg, i)) source.append(signature) source.append("{") for i, arg in enumerate(args): source.append(" testfargs_arg%d = a%d;" % (i, i)) source.append(" return testfargs_result;") source.append("}") typedef_line = "typedef %s;" % (signature.replace('testfargs', '(*mycallback_t)'),) assert signature.endswith(')') sig_callback = "%s testfcallback(mycallback_t callback)" % result cdefs.append(typedef_line) cdefs.append("%s;" % sig_callback) source.append(typedef_line) source.append(sig_callback) source.append("{") source.append(" return callback(%s);" % ', '.join(["testfargs_arg%d" % i for i in range(len(args))])) source.append("}") ffi = FFI() ffi.cdef("\n".join(cdefs)) lib = verify(ffi, 'test_function_args_%d' % TEST_RUN_COUNTER, "\n".join(source), no_cpp=True) # when getting segfaults, enable this: if False: from extra_tests.cffi_tests.udir import udir import subprocess f = open(str(udir.join('run1.py')), 'w') f.write('import sys; sys.path = %r\n' % (sys.path,)) f.write('from _CFFI_test_function_args_%d import ffi, lib\n' % TEST_RUN_COUNTER) for i in range(len(args)): f.write('a%d = ffi.new("%s *")\n' % (i, args[i])) aliststr = ', '.join(['a%d[0]' % i for i in range(len(args))]) f.write('lib.testfargs(%s)\n' % aliststr) f.write('ffi.addressof(lib, "testfargs")(%s)\n' % aliststr) f.close() print("checking for segfault for direct call...") rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir)) assert rc == 0, rc def make_arg(tp): if tp in structs: return [make_arg(tp1) for tp1 in structs[tp]] else: return draw_primitive(ffi, tp) passed_args = [make_arg(arg) for arg in args] returned_value = make_arg(result) def write(p, v): if type(v) is list: for i, v1 in enumerate(v): write(ffi.addressof(p, 'f%d' % i), v1) else: p[0] = v write(ffi.addressof(lib, 'testfargs_result'), returned_value) ## CALL forcing libffi print("CALL forcing libffi") received_return = ffi.addressof(lib, 'testfargs')(*passed_args) ## _tp_long_double = ffi.typeof("long double") def check(p, v): if type(v) is list: for i, v1 in enumerate(v): check(ffi.addressof(p, 'f%d' % i), v1) else: if ffi.typeof(p).item is _tp_long_double: assert ffi.cast("double", p[0]) == v else: assert p[0] == v for i, arg in enumerate(passed_args): check(ffi.addressof(lib, 'testfargs_arg%d' % i), arg) ret = ffi.new(result + "*", received_return) check(ret, returned_value) ## CALLBACK def expand(value): if isinstance(value, ffi.CData): t = ffi.typeof(value) if t is _tp_long_double: return float(ffi.cast("double", value)) return [expand(getattr(value, 'f%d' % i)) for i in range(len(t.fields))] else: return value # when getting segfaults, enable this: if False: from extra_tests.cffi_tests.udir import udir import subprocess f = open(str(udir.join('run1.py')), 'w') f.write('import sys; sys.path = %r\n' % (sys.path,)) f.write('from _CFFI_test_function_args_%d import ffi, lib\n' % TEST_RUN_COUNTER) f.write('def callback(*args): return ffi.new("%s *")[0]\n' % result) f.write('fptr = ffi.callback("%s(%s)", callback)\n' % (result, ','.join(args))) f.write('print(lib.testfcallback(fptr))\n') f.close() print("checking for segfault for callback...") rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir)) assert rc == 0, rc seen_args = [] def callback(*args): seen_args.append([expand(arg) for arg in args]) return returned_value fptr = ffi.callback("%s(%s)" % (result, ','.join(args)), callback) print("CALL with callback") received_return = lib.testfcallback(fptr) assert len(seen_args) == 1 assert passed_args == seen_args[0] ret = ffi.new(result + "*", received_return) check(ret, returned_value)
ffi = FFI() #define structure ffi.cdef(""" typedef struct t_point t_point; struct t_point { double x; double y; }; """) # allocate structure p = ffi.new("t_point *") assert ffi.offsetof('t_point', 'y') == 8 y = ffi.addressof(p, 'y') y[0] = 3 p.y == 3 # use allocate memory to write to structure data = np.zeros(10) p2 = ffi.cast('t_point *', data.ctypes.data) p2.x = 4 p2[3].x = 5 assert data[0] == 4.0 assert data[6] == 5.0