PageRenderTime 129ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py

https://bitbucket.org/pypy/pypy/
Python | 1524 lines | 1501 code | 8 blank | 15 comment | 9 complexity | 74102a105b3ba46a4665c9951d46f087 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. import sys, struct
  3. import ctypes
  4. from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
  5. from rpython.rtyper.tool import rffi_platform
  6. from rpython.rtyper.lltypesystem.ll2ctypes import lltype2ctypes, ctypes2lltype
  7. from rpython.rtyper.lltypesystem.ll2ctypes import standard_c_lib
  8. from rpython.rtyper.lltypesystem.ll2ctypes import uninitialized2ctypes
  9. from rpython.rtyper.lltypesystem.ll2ctypes import ALLOCATED, force_cast
  10. from rpython.rtyper.lltypesystem.ll2ctypes import cast_adr_to_int, get_ctypes_type
  11. from rpython.rtyper.lltypesystem.ll2ctypes import _llgcopaque
  12. from rpython.rtyper.annlowlevel import llhelper
  13. from rpython.rlib import rposix
  14. from rpython.rlib.rposix import UNDERSCORE_ON_WIN32
  15. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  16. from rpython.translator import cdir
  17. from rpython.tool.udir import udir
  18. from rpython.rtyper.test.test_llinterp import interpret
  19. from rpython.annotator.annrpython import RPythonAnnotator
  20. from rpython.rtyper.rtyper import RPythonTyper
  21. from rpython.rlib.rarithmetic import r_uint, get_long_pattern, is_emulated_long
  22. from rpython.rlib.rarithmetic import is_valid_int
  23. if False: # for now, please keep it False by default
  24. from rpython.rtyper.lltypesystem import ll2ctypes
  25. ll2ctypes.do_allocation_in_far_regions()
  26. """
  27. Win64:
  28. To decouple the cpython machine level long from the faked integer
  29. of the target rpython, I replaced most 'lltype.Signed' by 'rffi.LONG'.
  30. It would be nicer to replace all lltypes constants by rffi equivalents,
  31. or better if we had a way to address the specific different types of
  32. the current and the target system layout explicitly.
  33. Let's think of that when we go further and make the target completely
  34. independent and configurable.
  35. Why most and not all replaced?
  36. Tests with direct tests become cumbersome, instead of direct number
  37. assignment rffi.setintfield(s, 'x', 123) must be used.
  38. So in cases with number constants, where the size is not relevant,
  39. I kept lltype.signed .
  40. """
  41. class TestLL2Ctypes(object):
  42. def setup_method(self, meth):
  43. ALLOCATED.clear()
  44. def test_primitive(self):
  45. assert lltype2ctypes(5) == 5
  46. assert lltype2ctypes('?') == ord('?')
  47. assert lltype2ctypes('\xE0') == 0xE0
  48. assert lltype2ctypes(unichr(1234)) == 1234
  49. assert ctypes2lltype(lltype.Signed, 5) == 5
  50. assert ctypes2lltype(lltype.Char, ord('a')) == 'a'
  51. assert ctypes2lltype(lltype.UniChar, ord(u'x')) == u'x'
  52. assert ctypes2lltype(lltype.Char, 0xFF) == '\xFF'
  53. assert lltype2ctypes(5.25) == 5.25
  54. assert ctypes2lltype(lltype.Float, 5.25) == 5.25
  55. assert lltype2ctypes(u'x') == ord(u'x')
  56. res = lltype2ctypes(rffi.r_singlefloat(-3.5))
  57. assert isinstance(res, ctypes.c_float)
  58. assert res.value == -3.5
  59. res = ctypes2lltype(lltype.SingleFloat, ctypes.c_float(-3.5))
  60. assert isinstance(res, rffi.r_singlefloat)
  61. assert float(res) == -3.5
  62. assert lltype2ctypes(rffi.r_ulong(-1)) == (1 << rffi.r_ulong.BITS) - 1
  63. res = ctypes2lltype(lltype.Unsigned, sys.maxint * 2 + 1)
  64. assert (res, type(res)) == (r_uint(-1), r_uint)
  65. assert ctypes2lltype(lltype.Bool, 0) is False
  66. assert ctypes2lltype(lltype.Bool, 1) is True
  67. res = lltype2ctypes(llmemory.sizeof(rffi.LONG))
  68. assert res == struct.calcsize("l")
  69. S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG))
  70. res = lltype2ctypes(llmemory.sizeof(S))
  71. assert res == struct.calcsize("ll")
  72. p = lltype.nullptr(S)
  73. cptr = lltype2ctypes(p)
  74. assert not cptr
  75. py.test.raises(ValueError, 'cptr.contents') # NULL pointer access
  76. res = ctypes2lltype(lltype.Ptr(S), cptr)
  77. assert res == p
  78. assert not ALLOCATED # detects memory leaks in the test
  79. def test_simple_struct(self):
  80. S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed))
  81. s = lltype.malloc(S, flavor='raw')
  82. rffi.setintfield(s, 'x', 123)
  83. sc = lltype2ctypes(s)
  84. assert isinstance(sc.contents, ctypes.Structure)
  85. assert sc.contents.x == 123
  86. sc.contents.x = 456
  87. assert s.x == 456
  88. s.x = 789
  89. assert sc.contents.x == 789
  90. s.y = 52
  91. assert sc.contents.y == 52
  92. lltype.free(s, flavor='raw')
  93. assert not ALLOCATED # detects memory leaks in the test
  94. def test_get_pointer(self):
  95. # Equivalent of the C code::
  96. # struct S1 { struct S2 *ptr; struct S2 buf; };
  97. # struct S1 s1;
  98. # s1.ptr = & s1.buf;
  99. S2 = lltype.Struct('S2', ('y', lltype.Signed))
  100. S1 = lltype.Struct('S',
  101. ('sub', lltype.Struct('SUB',
  102. ('ptr', lltype.Ptr(S2)))),
  103. ('ptr', lltype.Ptr(S2)),
  104. ('buf', S2), # Works when this field is first!
  105. )
  106. s1 = lltype.malloc(S1, flavor='raw')
  107. s1.ptr = s1.buf
  108. s1.sub.ptr = s1.buf
  109. x = rffi.cast(rffi.CCHARP, s1)
  110. lltype.free(s1, flavor='raw')
  111. def test_struct_ptrs(self):
  112. S2 = lltype.Struct('S2', ('y', lltype.Signed))
  113. S1 = lltype.Struct('S', ('x', lltype.Signed), ('p', lltype.Ptr(S2)))
  114. s1 = lltype.malloc(S1, flavor='raw')
  115. s2a = lltype.malloc(S2, flavor='raw')
  116. s2b = lltype.malloc(S2, flavor='raw')
  117. s2a.y = ord('a')
  118. s2b.y = ord('b')
  119. sc1 = lltype2ctypes(s1)
  120. sc1.contents.x = 50
  121. assert s1.x == 50
  122. sc1.contents.p = lltype2ctypes(s2a)
  123. assert s1.p == s2a
  124. s1.p.y -= 32
  125. assert sc1.contents.p.contents.y == ord('A')
  126. s1.p = s2b
  127. sc1.contents.p.contents.y -= 32
  128. assert s2b.y == ord('B')
  129. lltype.free(s1, flavor='raw')
  130. lltype.free(s2a, flavor='raw')
  131. lltype.free(s2b, flavor='raw')
  132. assert not ALLOCATED # detects memory leaks in the test
  133. def test_simple_array(self):
  134. A = lltype.Array(lltype.Signed)
  135. a = lltype.malloc(A, 10, flavor='raw')
  136. a[0] = 100
  137. a[1] = 101
  138. a[2] = 102
  139. ac = lltype2ctypes(a, normalize=False)
  140. assert isinstance(ac.contents, ctypes.Structure)
  141. assert ac.contents.length == 10
  142. if is_emulated_long:
  143. lentype = ctypes.c_longlong
  144. else:
  145. lentype = ctypes.c_long
  146. assert ac.contents._fields_[0] == ('length', lentype)
  147. assert ac.contents.items[1] == 101
  148. ac.contents.items[2] = 456
  149. assert a[2] == 456
  150. a[3] = 789
  151. assert ac.contents.items[3] == 789
  152. lltype.free(a, flavor='raw')
  153. assert not ALLOCATED # detects memory leaks in the test
  154. def test_array_inside_struct(self):
  155. # like rstr.STR, but not Gc
  156. STR = lltype.Struct('STR', ('x', rffi.LONG), ('y', lltype.Array(lltype.Char)))
  157. a = lltype.malloc(STR, 3, flavor='raw')
  158. a.y[0] = 'x'
  159. a.y[1] = 'y'
  160. a.y[2] = 'z'
  161. # we need to pass normalize=False, otherwise 'ac' is returned of
  162. # a normalized standard type, which complains about IndexError
  163. # when doing 'ac.contents.y.items[2]'.
  164. ac = lltype2ctypes(a, normalize=False)
  165. assert ac.contents.y.length == 3
  166. assert ac.contents.y.items[2] == ord('z')
  167. lltype.free(a, flavor='raw')
  168. assert not ALLOCATED
  169. def test_array_nolength(self):
  170. A = lltype.Array(lltype.Signed, hints={'nolength': True})
  171. a = lltype.malloc(A, 10, flavor='raw')
  172. a[0] = 100
  173. a[1] = 101
  174. a[2] = 102
  175. ac = lltype2ctypes(a, normalize=False)
  176. assert isinstance(ac.contents, ctypes.Structure)
  177. assert ac.contents.items[1] == 101
  178. ac.contents.items[2] = 456
  179. assert a[2] == 456
  180. a[3] = 789
  181. assert ac.contents.items[3] == 789
  182. assert ctypes.sizeof(ac.contents) == 10 * rffi.sizeof(lltype.Signed)
  183. lltype.free(a, flavor='raw')
  184. assert not ALLOCATED # detects memory leaks in the test
  185. def test_charp(self):
  186. s = rffi.str2charp("hello")
  187. sc = lltype2ctypes(s, normalize=False)
  188. assert sc.contents.items[0] == ord('h')
  189. assert sc.contents.items[1] == ord('e')
  190. assert sc.contents.items[2] == ord('l')
  191. assert sc.contents.items[3] == ord('l')
  192. assert sc.contents.items[4] == ord('o')
  193. assert sc.contents.items[5] == 0
  194. assert not hasattr(sc.contents, 'length')
  195. sc.contents.items[1] = ord('E')
  196. assert s[1] == 'E'
  197. s[0] = 'H'
  198. assert sc.contents.items[0] == ord('H')
  199. rffi.free_charp(s)
  200. assert not ALLOCATED # detects memory leaks in the test
  201. def test_unicharp(self):
  202. SP = rffi.CArrayPtr(lltype.UniChar)
  203. s = lltype.malloc(SP.TO, 4, flavor='raw')
  204. s[0] = u'x'
  205. s[1] = u'y'
  206. s[2] = u'z'
  207. s[3] = u'\x00'
  208. sc = lltype2ctypes(s, normalize=False)
  209. assert sc.contents.items[0] == ord(u'x')
  210. assert sc.contents.items[1] == ord(u'y')
  211. assert sc.contents.items[2] == ord(u'z')
  212. assert not hasattr(sc.contents, 'length')
  213. lltype.free(s, flavor='raw')
  214. assert not ALLOCATED
  215. def test_strlen(self):
  216. eci = ExternalCompilationInfo(includes=['string.h'])
  217. strlen = rffi.llexternal('strlen', [rffi.CCHARP], rffi.SIZE_T,
  218. compilation_info=eci)
  219. s = rffi.str2charp("xxx")
  220. res = strlen(s)
  221. rffi.free_charp(s)
  222. assert res == 3 # actually r_size_t(3)
  223. s = rffi.str2charp("")
  224. res = strlen(s)
  225. rffi.free_charp(s)
  226. assert res == 0 # actually r_size_t(0)
  227. assert not ALLOCATED # detects memory leaks in the test
  228. def test_func_not_in_clib(self):
  229. eci = ExternalCompilationInfo(libraries=['m'])
  230. foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG)
  231. py.test.raises(NotImplementedError, foobar)
  232. foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG,
  233. compilation_info=eci) # math library
  234. py.test.raises(NotImplementedError, foobar)
  235. eci = ExternalCompilationInfo(libraries=['m', 'z'])
  236. foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG,
  237. compilation_info=eci) # math and zlib
  238. py.test.raises(NotImplementedError, foobar)
  239. eci = ExternalCompilationInfo(libraries=['I_really_dont_exist_either'])
  240. foobar = rffi.llexternal('I_really_dont_exist', [], rffi.LONG,
  241. compilation_info=eci)
  242. py.test.raises(NotImplementedError, foobar)
  243. assert not ALLOCATED # detects memory leaks in the test
  244. def test_cstruct_to_ll(self):
  245. S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed))
  246. s = lltype.malloc(S, flavor='raw')
  247. s2 = lltype.malloc(S, flavor='raw')
  248. s.x = 123
  249. sc = lltype2ctypes(s)
  250. t = ctypes2lltype(lltype.Ptr(S), sc)
  251. assert lltype.typeOf(t) == lltype.Ptr(S)
  252. assert s == t
  253. assert not (s != t)
  254. assert t == s
  255. assert not (t != s)
  256. assert t != lltype.nullptr(S)
  257. assert not (t == lltype.nullptr(S))
  258. assert lltype.nullptr(S) != t
  259. assert not (lltype.nullptr(S) == t)
  260. assert t != s2
  261. assert not (t == s2)
  262. assert s2 != t
  263. assert not (s2 == t)
  264. assert t.x == 123
  265. t.x += 1
  266. assert s.x == 124
  267. s.x += 1
  268. assert t.x == 125
  269. lltype.free(s, flavor='raw')
  270. lltype.free(s2, flavor='raw')
  271. assert not ALLOCATED # detects memory leaks in the test
  272. def test_carray_to_ll(self):
  273. A = lltype.Array(lltype.Signed, hints={'nolength': True})
  274. a = lltype.malloc(A, 10, flavor='raw')
  275. a2 = lltype.malloc(A, 10, flavor='raw')
  276. a[0] = 100
  277. a[1] = 101
  278. a[2] = 110
  279. ac = lltype2ctypes(a)
  280. b = ctypes2lltype(lltype.Ptr(A), ac)
  281. assert lltype.typeOf(b) == lltype.Ptr(A)
  282. assert b == a
  283. assert not (b != a)
  284. assert a == b
  285. assert not (a != b)
  286. assert b != lltype.nullptr(A)
  287. assert not (b == lltype.nullptr(A))
  288. assert lltype.nullptr(A) != b
  289. assert not (lltype.nullptr(A) == b)
  290. assert b != a2
  291. assert not (b == a2)
  292. assert a2 != b
  293. assert not (a2 == b)
  294. assert b[2] == 110
  295. b[2] *= 2
  296. assert a[2] == 220
  297. a[2] *= 3
  298. assert b[2] == 660
  299. lltype.free(a, flavor='raw')
  300. lltype.free(a2, flavor='raw')
  301. assert not ALLOCATED # detects memory leaks in the test
  302. def test_strchr(self):
  303. eci = ExternalCompilationInfo(includes=['string.h'])
  304. strchr = rffi.llexternal('strchr', [rffi.CCHARP, rffi.INT],
  305. rffi.CCHARP, compilation_info=eci)
  306. s = rffi.str2charp("hello world")
  307. res = strchr(s, ord('r'))
  308. assert res[0] == 'r'
  309. assert res[1] == 'l'
  310. assert res[2] == 'd'
  311. assert res[3] == '\x00'
  312. # XXX maybe we should also allow res[-1], res[-2]...
  313. rffi.free_charp(s)
  314. assert not ALLOCATED # detects memory leaks in the test
  315. def test_frexp(self):
  316. if sys.platform != 'win32':
  317. eci = ExternalCompilationInfo(includes=['math.h'],
  318. libraries=['m'])
  319. else:
  320. eci = ExternalCompilationInfo(includes=['math.h'])
  321. A = lltype.FixedSizeArray(rffi.INT, 1)
  322. frexp = rffi.llexternal('frexp', [rffi.DOUBLE, lltype.Ptr(A)],
  323. rffi.DOUBLE, compilation_info=eci)
  324. p = lltype.malloc(A, flavor='raw')
  325. res = frexp(2.5, p)
  326. assert res == 0.625
  327. assert p[0] == 2
  328. lltype.free(p, flavor='raw')
  329. assert not ALLOCATED # detects memory leaks in the test
  330. def test_rand(self):
  331. eci = ExternalCompilationInfo(includes=['stdlib.h'])
  332. rand = rffi.llexternal('rand', [], rffi.INT,
  333. compilation_info=eci)
  334. srand = rffi.llexternal('srand', [rffi.UINT], lltype.Void,
  335. compilation_info=eci)
  336. srand(rffi.r_uint(123))
  337. res1 = rand()
  338. res2 = rand()
  339. res3 = rand()
  340. srand(rffi.r_uint(123))
  341. res1b = rand()
  342. res2b = rand()
  343. res3b = rand()
  344. assert res1 == res1b
  345. assert res2 == res2b
  346. assert res3 == res3b
  347. assert not ALLOCATED # detects memory leaks in the test
  348. def test_opaque_obj(self):
  349. if sys.platform == 'win32':
  350. py.test.skip("No gettimeofday on win32")
  351. eci = ExternalCompilationInfo(
  352. includes = ['sys/time.h', 'time.h']
  353. )
  354. TIMEVALP = rffi.COpaquePtr('struct timeval', compilation_info=eci)
  355. TIMEZONEP = rffi.COpaquePtr('struct timezone', compilation_info=eci)
  356. gettimeofday = rffi.llexternal('gettimeofday', [TIMEVALP, TIMEZONEP],
  357. rffi.INT, compilation_info=eci)
  358. ll_timevalp = lltype.malloc(TIMEVALP.TO, flavor='raw')
  359. ll_timezonep = lltype.malloc(TIMEZONEP.TO, flavor='raw')
  360. res = gettimeofday(ll_timevalp, ll_timezonep)
  361. assert res != -1
  362. lltype.free(ll_timezonep, flavor='raw')
  363. lltype.free(ll_timevalp, flavor='raw')
  364. assert not ALLOCATED # detects memory leaks in the test
  365. def test_opaque_obj_2(self):
  366. FILEP = rffi.COpaquePtr('FILE')
  367. fopen = rffi.llexternal('fopen', [rffi.CCHARP, rffi.CCHARP], FILEP)
  368. fclose = rffi.llexternal('fclose', [FILEP], rffi.INT)
  369. tmppath = udir.join('test_ll2ctypes.test_opaque_obj_2')
  370. ll_file = fopen(str(tmppath), "w")
  371. assert ll_file
  372. fclose(ll_file)
  373. assert tmppath.check(file=1)
  374. assert not ALLOCATED # detects memory leaks in the test
  375. assert rffi.cast(FILEP, -1) == rffi.cast(FILEP, -1)
  376. def test_simple_cast(self):
  377. assert rffi.cast(rffi.SIGNEDCHAR, 0x123456) == 0x56
  378. assert rffi.cast(rffi.SIGNEDCHAR, 0x123481) == -127
  379. assert rffi.cast(rffi.CHAR, 0x123456) == '\x56'
  380. assert rffi.cast(rffi.CHAR, 0x123481) == '\x81'
  381. assert rffi.cast(rffi.UCHAR, 0x123481) == 0x81
  382. assert not ALLOCATED # detects memory leaks in the test
  383. def test_forced_ptr_cast(self):
  384. import array
  385. A = lltype.Array(lltype.Signed, hints={'nolength': True})
  386. B = lltype.Array(lltype.Char, hints={'nolength': True})
  387. a = lltype.malloc(A, 10, flavor='raw')
  388. for i in range(10):
  389. a[i] = i*i
  390. b = rffi.cast(lltype.Ptr(B), a)
  391. expected = ''
  392. for i in range(10):
  393. expected += get_long_pattern(i*i)
  394. for i in range(len(expected)):
  395. assert b[i] == expected[i]
  396. c = rffi.cast(rffi.VOIDP, a)
  397. addr = lltype2ctypes(c)
  398. #assert addr == ctypes.addressof(a._obj._ctypes_storage)
  399. d = ctypes2lltype(rffi.VOIDP, addr)
  400. assert lltype.typeOf(d) == rffi.VOIDP
  401. assert c == d
  402. e = rffi.cast(lltype.Ptr(A), d)
  403. for i in range(10):
  404. assert e[i] == i*i
  405. c = lltype.nullptr(rffi.VOIDP.TO)
  406. addr = rffi.cast(rffi.LONG, c)
  407. assert addr == 0
  408. lltype.free(a, flavor='raw')
  409. assert not ALLOCATED # detects memory leaks in the test
  410. def test_adr_cast(self):
  411. from rpython.rtyper.annlowlevel import llstr
  412. from rpython.rtyper.lltypesystem.rstr import STR
  413. P = lltype.Ptr(lltype.FixedSizeArray(lltype.Char, 1))
  414. def f():
  415. a = llstr("xyz")
  416. b = (llmemory.cast_ptr_to_adr(a) + llmemory.offsetof(STR, 'chars')
  417. + llmemory.itemoffsetof(STR.chars, 0))
  418. buf = rffi.cast(rffi.VOIDP, b)
  419. return buf[2]
  420. assert f() == 'z'
  421. res = interpret(f, [])
  422. assert res == 'z'
  423. def test_funcptr1(self):
  424. def dummy(n):
  425. return n+1
  426. FUNCTYPE = lltype.FuncType([lltype.Signed], lltype.Signed)
  427. cdummy = lltype2ctypes(llhelper(lltype.Ptr(FUNCTYPE), dummy))
  428. if not is_emulated_long:
  429. assert cdummy.argtypes == (ctypes.c_long,)
  430. assert cdummy.restype == ctypes.c_long
  431. else:
  432. # XXX maybe we skip this if it breaks on some platforms
  433. assert cdummy.argtypes == (ctypes.c_longlong,)
  434. assert cdummy.restype == ctypes.c_longlong
  435. res = cdummy(41)
  436. assert res == 42
  437. lldummy = ctypes2lltype(lltype.Ptr(FUNCTYPE), cdummy)
  438. assert lltype.typeOf(lldummy) == lltype.Ptr(FUNCTYPE)
  439. res = lldummy(41)
  440. assert res == 42
  441. assert not ALLOCATED # detects memory leaks in the test
  442. def test_funcptr2(self):
  443. FUNCTYPE = lltype.FuncType([rffi.CCHARP], rffi.LONG)
  444. cstrlen = standard_c_lib.strlen
  445. llstrlen = ctypes2lltype(lltype.Ptr(FUNCTYPE), cstrlen)
  446. assert lltype.typeOf(llstrlen) == lltype.Ptr(FUNCTYPE)
  447. p = rffi.str2charp("hi there")
  448. res = llstrlen(p)
  449. assert res == 8
  450. cstrlen2 = lltype2ctypes(llstrlen)
  451. cp = lltype2ctypes(p)
  452. assert cstrlen2.restype == ctypes.c_long
  453. res = cstrlen2(cp)
  454. assert res == 8
  455. rffi.free_charp(p)
  456. assert not ALLOCATED # detects memory leaks in the test
  457. def test_funcptr_cast(self):
  458. eci = ExternalCompilationInfo(
  459. include_dirs = [cdir],
  460. separate_module_sources=["""
  461. #include "src/precommondefs.h"
  462. long mul(long x, long y) { return x*y; }
  463. RPY_EXPORTED long(*get_mul(long x)) () { return &mul; }
  464. """])
  465. get_mul = rffi.llexternal(
  466. 'get_mul', [],
  467. lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)),
  468. compilation_info=eci)
  469. # This call returns a pointer to a function taking one argument
  470. funcptr = get_mul()
  471. # cast it to the "real" function type
  472. FUNCTYPE2 = lltype.FuncType([lltype.Signed, lltype.Signed],
  473. lltype.Signed)
  474. cmul = rffi.cast(lltype.Ptr(FUNCTYPE2), funcptr)
  475. # and it can be called with the expected number of arguments
  476. res = cmul(41, 42)
  477. assert res == 41 * 42
  478. py.test.raises(TypeError, cmul, 41)
  479. py.test.raises(TypeError, cmul, 41, 42, 43)
  480. def test_qsort(self):
  481. CMPFUNC = lltype.FuncType([rffi.VOIDP, rffi.VOIDP], rffi.INT)
  482. qsort = rffi.llexternal('qsort', [rffi.VOIDP,
  483. rffi.SIZE_T,
  484. rffi.SIZE_T,
  485. lltype.Ptr(CMPFUNC)],
  486. lltype.Void)
  487. lst = [23, 43, 24, 324, 242, 34, 78, 5, 3, 10]
  488. A = lltype.Array(lltype.Signed, hints={'nolength': True})
  489. a = lltype.malloc(A, 10, flavor='raw')
  490. for i in range(10):
  491. a[i] = lst[i]
  492. SIGNEDPTR = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1))
  493. def my_compar(p1, p2):
  494. p1 = rffi.cast(SIGNEDPTR, p1)
  495. p2 = rffi.cast(SIGNEDPTR, p2)
  496. print 'my_compar:', p1[0], p2[0]
  497. return rffi.cast(rffi.INT, cmp(p1[0], p2[0]))
  498. qsort(rffi.cast(rffi.VOIDP, a),
  499. rffi.cast(rffi.SIZE_T, 10),
  500. rffi.cast(rffi.SIZE_T, llmemory.sizeof(lltype.Signed)),
  501. llhelper(lltype.Ptr(CMPFUNC), my_compar))
  502. for i in range(10):
  503. print a[i],
  504. print
  505. lst.sort()
  506. for i in range(10):
  507. assert a[i] == lst[i]
  508. lltype.free(a, flavor='raw')
  509. assert not ALLOCATED # detects memory leaks in the test
  510. # def test_signal(self):...
  511. def test_uninitialized2ctypes(self):
  512. # for now, uninitialized fields are filled with 0xDD in the ctypes data
  513. def checkobj(o, size):
  514. p = ctypes.cast(ctypes.c_void_p(ctypes.addressof(o)),
  515. ctypes.POINTER(ctypes.c_ubyte*size))
  516. for i in range(size):
  517. assert p.contents[i] == 0xDD
  518. def checkval(v, fmt):
  519. res = struct.pack(fmt, v)
  520. assert res == "\xDD" * len(res)
  521. checkval(uninitialized2ctypes(rffi.CHAR), 'B')
  522. checkval(uninitialized2ctypes(rffi.SHORT), 'h')
  523. if not is_emulated_long:
  524. checkval(uninitialized2ctypes(rffi.INT), 'i')
  525. checkval(uninitialized2ctypes(rffi.UINT), 'I')
  526. checkval(uninitialized2ctypes(rffi.LONGLONG), 'q')
  527. checkval(uninitialized2ctypes(rffi.DOUBLE), 'd')
  528. checkobj(uninitialized2ctypes(rffi.INTP),
  529. ctypes.sizeof(ctypes.c_void_p))
  530. checkobj(uninitialized2ctypes(rffi.CCHARP),
  531. ctypes.sizeof(ctypes.c_void_p))
  532. S = lltype.Struct('S', ('x', rffi.LONG), ('y', rffi.LONG))
  533. s = lltype.malloc(S, flavor='raw')
  534. sc = lltype2ctypes(s)
  535. checkval(sc.contents.x, 'l')
  536. checkval(sc.contents.y, 'l')
  537. lltype.free(s, flavor='raw')
  538. assert not ALLOCATED # detects memory leaks in the test
  539. def test_substructures(self):
  540. S1 = lltype.Struct('S1', ('x', lltype.Signed))
  541. BIG = lltype.Struct('BIG', ('s1a', S1), ('s1b', S1))
  542. s = lltype.malloc(BIG, flavor='raw')
  543. s.s1a.x = 123
  544. s.s1b.x = 456
  545. sc = lltype2ctypes(s)
  546. assert sc.contents.s1a.x == 123
  547. assert sc.contents.s1b.x == 456
  548. sc.contents.s1a.x += 1
  549. sc.contents.s1b.x += 10
  550. assert s.s1a.x == 124
  551. assert s.s1b.x == 466
  552. s.s1a.x += 3
  553. s.s1b.x += 30
  554. assert sc.contents.s1a.x == 127
  555. assert sc.contents.s1b.x == 496
  556. lltype.free(s, flavor='raw')
  557. s = lltype.malloc(BIG, flavor='raw')
  558. s1ac = lltype2ctypes(s.s1a)
  559. s1ac.contents.x = 53
  560. sc = lltype2ctypes(s)
  561. assert sc.contents.s1a.x == 53
  562. sc.contents.s1a.x += 1
  563. assert s1ac.contents.x == 54
  564. assert s.s1a.x == 54
  565. s.s1a.x += 2
  566. assert s1ac.contents.x == 56
  567. assert sc.contents.s1a.x == 56
  568. sc.contents.s1a.x += 3
  569. assert s1ac.contents.x == 59
  570. assert s.s1a.x == 59
  571. t = ctypes2lltype(lltype.Ptr(BIG), sc)
  572. assert t == s
  573. assert t.s1a == s.s1a
  574. assert t.s1a.x == 59
  575. s.s1b.x = 8888
  576. assert t.s1b == s.s1b
  577. assert t.s1b.x == 8888
  578. t1 = ctypes2lltype(lltype.Ptr(S1), s1ac)
  579. assert t.s1a == t1
  580. assert t1.x == 59
  581. t1.x += 1
  582. assert sc.contents.s1a.x == 60
  583. lltype.free(s, flavor='raw')
  584. assert not ALLOCATED # detects memory leaks in the test
  585. def test_recursive_struct(self):
  586. SX = lltype.ForwardReference()
  587. S1 = lltype.Struct('S1', ('p', lltype.Ptr(SX)), ('x', lltype.Signed))
  588. SX.become(S1)
  589. # a chained list
  590. s1 = lltype.malloc(S1, flavor='raw')
  591. s2 = lltype.malloc(S1, flavor='raw')
  592. s3 = lltype.malloc(S1, flavor='raw')
  593. s1.x = 111
  594. s2.x = 222
  595. s3.x = 333
  596. s1.p = s2
  597. s2.p = s3
  598. s3.p = lltype.nullptr(S1)
  599. sc1 = lltype2ctypes(s1)
  600. sc2 = sc1.contents.p
  601. sc3 = sc2.contents.p
  602. assert not sc3.contents.p
  603. assert sc1.contents.x == 111
  604. assert sc2.contents.x == 222
  605. assert sc3.contents.x == 333
  606. sc3.contents.x += 1
  607. assert s3.x == 334
  608. s3.x += 2
  609. assert sc3.contents.x == 336
  610. lltype.free(s1, flavor='raw')
  611. lltype.free(s2, flavor='raw')
  612. lltype.free(s3, flavor='raw')
  613. # a self-cycle
  614. s1 = lltype.malloc(S1, flavor='raw')
  615. s1.x = 12
  616. s1.p = s1
  617. sc1 = lltype2ctypes(s1)
  618. assert sc1.contents.x == 12
  619. assert (ctypes.addressof(sc1.contents.p.contents) ==
  620. ctypes.addressof(sc1.contents))
  621. s1.x *= 5
  622. assert sc1.contents.p.contents.p.contents.p.contents.x == 60
  623. lltype.free(s1, flavor='raw')
  624. # a longer cycle
  625. s1 = lltype.malloc(S1, flavor='raw')
  626. s2 = lltype.malloc(S1, flavor='raw')
  627. s1.x = 111
  628. s1.p = s2
  629. s2.x = 222
  630. s2.p = s1
  631. sc1 = lltype2ctypes(s1)
  632. assert sc1.contents.x == 111
  633. assert sc1.contents.p.contents.x == 222
  634. assert (ctypes.addressof(sc1.contents.p.contents) !=
  635. ctypes.addressof(sc1.contents))
  636. assert (ctypes.addressof(sc1.contents.p.contents.p.contents) ==
  637. ctypes.addressof(sc1.contents))
  638. lltype.free(s1, flavor='raw')
  639. lltype.free(s2, flavor='raw')
  640. assert not ALLOCATED # detects memory leaks in the test
  641. def test_indirect_recursive_struct(self):
  642. S2Forward = lltype.ForwardReference()
  643. S1 = lltype.Struct('S1', ('p', lltype.Ptr(S2Forward)))
  644. A2 = lltype.Array(lltype.Ptr(S1), hints={'nolength': True})
  645. S2 = lltype.Struct('S2', ('a', lltype.Ptr(A2)))
  646. S2Forward.become(S2)
  647. s1 = lltype.malloc(S1, flavor='raw')
  648. a2 = lltype.malloc(A2, 10, flavor='raw')
  649. s2 = lltype.malloc(S2, flavor='raw')
  650. s2.a = a2
  651. a2[5] = s1
  652. s1.p = s2
  653. ac2 = lltype2ctypes(a2, normalize=False)
  654. sc1 = ac2.contents.items[5]
  655. sc2 = sc1.contents.p
  656. assert (ctypes.addressof(sc2.contents.a.contents) ==
  657. ctypes.addressof(ac2.contents))
  658. lltype.free(s1, flavor='raw')
  659. lltype.free(a2, flavor='raw')
  660. lltype.free(s2, flavor='raw')
  661. assert not ALLOCATED # detects memory leaks in the test
  662. def test_arrayofstruct(self):
  663. S1 = lltype.Struct('S2', ('x', lltype.Signed))
  664. A = lltype.Array(S1, hints={'nolength': True})
  665. a = lltype.malloc(A, 5, flavor='raw')
  666. a[0].x = 100
  667. a[1].x = 101
  668. a[2].x = 102
  669. a[3].x = 103
  670. a[4].x = 104
  671. ac = lltype2ctypes(a, normalize=False)
  672. assert ac.contents.items[0].x == 100
  673. assert ac.contents.items[2].x == 102
  674. ac.contents.items[3].x += 500
  675. assert a[3].x == 603
  676. a[4].x += 600
  677. assert ac.contents.items[4].x == 704
  678. a1 = ctypes2lltype(lltype.Ptr(A), ac)
  679. assert a1 == a
  680. assert a1[2].x == 102
  681. aitem1 = ctypes2lltype(lltype.Ptr(S1),
  682. ctypes.pointer(ac.contents.items[1]))
  683. assert aitem1.x == 101
  684. assert aitem1 == a1[1]
  685. lltype.free(a, flavor='raw')
  686. assert not ALLOCATED # detects memory leaks in the test
  687. def test_get_errno(self):
  688. eci = ExternalCompilationInfo(includes=['string.h'])
  689. if sys.platform.startswith('win'):
  690. py.test.skip('writing to invalid fd on windows crashes the process')
  691. # Note that cpython before 2.7 installs an _invalid_parameter_handler,
  692. # which is why the test passes there, but this is no longer
  693. # accepted practice.
  694. import ctypes
  695. SEM_NOGPFAULTERRORBOX = 0x0002 # From MSDN
  696. old_err_mode = ctypes.windll.kernel32.GetErrorMode()
  697. new_err_mode = old_err_mode | SEM_NOGPFAULTERRORBOX
  698. ctypes.windll.kernel32.SetErrorMode(new_err_mode)
  699. os_write_no_errno = rffi.llexternal(UNDERSCORE_ON_WIN32 + 'write',
  700. [rffi.INT, rffi.CCHARP, rffi.SIZE_T],
  701. rffi.SIZE_T, save_err=rffi.RFFI_ERR_NONE)
  702. os_write = rffi.llexternal(UNDERSCORE_ON_WIN32 + 'write',
  703. [rffi.INT, rffi.CCHARP, rffi.SIZE_T],
  704. rffi.SIZE_T, save_err=rffi.RFFI_SAVE_ERRNO)
  705. buffer = lltype.malloc(rffi.CCHARP.TO, 5, flavor='raw')
  706. written = os_write(12312312, buffer, 5)
  707. if sys.platform.startswith('win'):
  708. ctypes.windll.kernel32.SetErrorMode(old_err_mode)
  709. assert rffi.cast(rffi.LONG, written) < 0
  710. # the next line is a different external function call
  711. # without RFFI_SAVE_ERRNO, to check that it doesn't reset errno
  712. buffer[0] = '\n'
  713. os_write_no_errno(2, buffer, 1)
  714. lltype.free(buffer, flavor='raw')
  715. err = rposix.get_saved_errno()
  716. import errno
  717. assert err == errno.EBADF
  718. assert not ALLOCATED # detects memory leaks in the test
  719. def test_call_with_struct_argument(self):
  720. # XXX is there such a function in the standard C headers?
  721. from rpython.rlib import _rsocket_rffi
  722. buf = rffi.make(_rsocket_rffi.in_addr)
  723. rffi.cast(rffi.CCHARP, buf)[0] = '\x01'
  724. rffi.cast(rffi.CCHARP, buf)[1] = '\x02'
  725. rffi.cast(rffi.CCHARP, buf)[2] = '\x03'
  726. rffi.cast(rffi.CCHARP, buf)[3] = '\x04'
  727. p = _rsocket_rffi.inet_ntoa(buf)
  728. assert rffi.charp2str(p) == '1.2.3.4'
  729. lltype.free(buf, flavor='raw')
  730. assert not ALLOCATED # detects memory leaks in the test
  731. def test_storage_stays_around(self):
  732. data = "hello, world!" * 100
  733. A = lltype.Array(rffi.CHAR, hints={'nolength': True})
  734. S = lltype.Struct('S', ('a', lltype.Ptr(A)))
  735. s = lltype.malloc(S, flavor='raw')
  736. lltype2ctypes(s) # force it to escape
  737. s.a = lltype.malloc(A, len(data), flavor='raw')
  738. # the storage for the array should not be freed by lltype even
  739. # though the _ptr object appears to go away here
  740. for i in xrange(len(data)):
  741. s.a[i] = data[i]
  742. for i in xrange(len(data)):
  743. assert s.a[i] == data[i]
  744. lltype.free(s.a, flavor='raw')
  745. lltype.free(s, flavor='raw')
  746. assert not ALLOCATED # detects memory leaks in the test
  747. def test_arrayoffloat(self):
  748. a = lltype.malloc(rffi.FLOATP.TO, 3, flavor='raw')
  749. a[0] = rffi.r_singlefloat(0.0)
  750. a[1] = rffi.r_singlefloat(1.1)
  751. a[2] = rffi.r_singlefloat(2.2)
  752. ac = lltype2ctypes(a, normalize=False)
  753. assert ac.contents.items[0] == 0.0
  754. assert abs(ac.contents.items[1] - 1.1) < 1E-6
  755. assert abs(ac.contents.items[2] - 2.2) < 1E-6
  756. b = ctypes2lltype(rffi.FLOATP, ac)
  757. assert isinstance(b[0], rffi.r_singlefloat)
  758. assert float(b[0]) == 0.0
  759. assert isinstance(b[1], rffi.r_singlefloat)
  760. assert abs(float(b[1]) - 1.1) < 1E-6
  761. assert isinstance(b[2], rffi.r_singlefloat)
  762. assert abs(float(b[2]) - 2.2) < 1E-6
  763. lltype.free(a, flavor='raw')
  764. def test_different_signatures(self):
  765. if sys.platform=='win32':
  766. py.test.skip("No fcntl on win32")
  767. fcntl_int = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.INT],
  768. rffi.INT)
  769. fcntl_str = rffi.llexternal('fcntl', [rffi.INT, rffi.INT, rffi.CCHARP],
  770. rffi.INT)
  771. fcntl_int(12345, 1, 0)
  772. fcntl_str(12345, 3, "xxx")
  773. fcntl_int(12345, 1, 0)
  774. def test_llexternal_source(self):
  775. eci = ExternalCompilationInfo(
  776. include_dirs = [cdir],
  777. separate_module_sources = ["""
  778. #include "src/precommondefs.h"
  779. RPY_EXPORTED int fn() { return 42; }
  780. """],
  781. )
  782. fn = rffi.llexternal('fn', [], rffi.INT, compilation_info=eci)
  783. res = fn()
  784. assert res == 42
  785. def test_llexternal_macro(self):
  786. eci = ExternalCompilationInfo(
  787. post_include_bits = ["#define fn(x) (42 + x)"],
  788. )
  789. fn1 = rffi.llexternal('fn', [rffi.INT], rffi.INT,
  790. compilation_info=eci, macro=True)
  791. fn2 = rffi.llexternal('fn2', [rffi.DOUBLE], rffi.DOUBLE,
  792. compilation_info=eci, macro='fn')
  793. res = fn1(10)
  794. assert res == 52
  795. res = fn2(10.5)
  796. assert res == 52.5
  797. def test_prebuilt_constant(self):
  798. header = py.code.Source("""
  799. #ifndef _SOME_H
  800. #define _SOME_H
  801. #include <stdlib.h>
  802. static long x = 3;
  803. static int y = 5;
  804. char **z = NULL;
  805. #endif /* _SOME_H */
  806. """)
  807. h_file = udir.join("some_h.h")
  808. h_file.write(header)
  809. eci = ExternalCompilationInfo(includes=['stdio.h', str(h_file.basename)],
  810. include_dirs=[str(udir)])
  811. get_x, set_x = rffi.CExternVariable(rffi.LONG, 'x', eci, c_type='long')
  812. get_y, set_y = rffi.CExternVariable(rffi.INT, 'y', eci, c_type='int')
  813. get_z, set_z = rffi.CExternVariable(rffi.CCHARPP, 'z', eci)
  814. def f():
  815. one = get_x()
  816. set_x(13)
  817. return one + get_x()
  818. def fy():
  819. one = rffi.cast(rffi.LONG, get_y())
  820. set_y(rffi.cast(rffi.INT, 13))
  821. return one + rffi.cast(rffi.LONG, get_y())
  822. def g():
  823. l = rffi.liststr2charpp(["a", "b", "c"])
  824. try:
  825. set_z(l)
  826. return rffi.charp2str(get_z()[2])
  827. finally:
  828. rffi.free_charpp(l)
  829. res = f()
  830. assert res == 16
  831. res = fy()
  832. assert res == 18
  833. res = g()
  834. assert res == "c"
  835. def test_c_callback(self):
  836. c_source = py.code.Source("""
  837. #include "src/precommondefs.h"
  838. RPY_EXPORTED
  839. int eating_callback(int arg, int(*call)(int))
  840. {
  841. return call(arg);
  842. }
  843. """)
  844. eci = ExternalCompilationInfo(include_dirs=[cdir],
  845. separate_module_sources=[c_source])
  846. args = [rffi.INT, rffi.CCallback([rffi.INT], rffi.INT)]
  847. eating_callback = rffi.llexternal('eating_callback', args, rffi.INT,
  848. compilation_info=eci)
  849. def g(i):
  850. return i + 3
  851. def f():
  852. return eating_callback(3, g)
  853. assert f() == 6
  854. def test_qsort_callback(self):
  855. TP = rffi.CArrayPtr(rffi.INT)
  856. a = lltype.malloc(TP.TO, 5, flavor='raw')
  857. a[0] = rffi.r_int(5)
  858. a[1] = rffi.r_int(3)
  859. a[2] = rffi.r_int(2)
  860. a[3] = rffi.r_int(1)
  861. a[4] = rffi.r_int(4)
  862. def compare(a, b):
  863. # do not use a,b directly! on a big endian machine
  864. # ((void*)ptr)[0] will return 0x0 if the 32 bit value
  865. # ptr points to is 0x1
  866. a = rffi.cast(rffi.INTP, a)
  867. b = rffi.cast(rffi.INTP, b)
  868. if a[0] > b[0]:
  869. return rffi.r_int(1)
  870. else:
  871. return rffi.r_int(-1)
  872. CALLBACK = rffi.CCallback([rffi.VOIDP, rffi.VOIDP], rffi.INT)
  873. qsort = rffi.llexternal('qsort', [rffi.VOIDP, rffi.SIZE_T,
  874. rffi.SIZE_T, CALLBACK], lltype.Void)
  875. qsort(rffi.cast(rffi.VOIDP, a), 5, rffi.sizeof(rffi.INT), compare)
  876. for i in range(5):
  877. assert a[i] == i + 1
  878. lltype.free(a, flavor='raw')
  879. def test_array_type_bug(self):
  880. A = lltype.Array(rffi.LONG)
  881. a1 = lltype.malloc(A, 0, flavor='raw')
  882. a2 = lltype.malloc(A, 0, flavor='raw')
  883. c1 = lltype2ctypes(a1)
  884. c2 = lltype2ctypes(a2)
  885. assert type(c1) is type(c2)
  886. lltype.free(a1, flavor='raw')
  887. lltype.free(a2, flavor='raw')
  888. assert not ALLOCATED # detects memory leaks in the test
  889. def test_varsized_struct(self):
  890. S = lltype.Struct('S', ('x', lltype.Signed),
  891. ('a', lltype.Array(lltype.Char)))
  892. s1 = lltype.malloc(S, 6, flavor='raw')
  893. s1.x = 5
  894. s1.a[2] = 'F'
  895. sc = lltype2ctypes(s1, normalize=False)
  896. assert isinstance(sc.contents, ctypes.Structure)
  897. assert sc.contents.x == 5
  898. assert sc.contents.a.length == 6
  899. assert sc.contents.a.items[2] == ord('F')
  900. sc.contents.a.items[3] = ord('P')
  901. assert s1.a[3] == 'P'
  902. s1.a[1] = 'y'
  903. assert sc.contents.a.items[1] == ord('y')
  904. # now go back to lltype...
  905. res = ctypes2lltype(lltype.Ptr(S), sc)
  906. assert res == s1
  907. assert res.x == 5
  908. assert len(res.a) == 6
  909. lltype.free(s1, flavor='raw')
  910. assert not ALLOCATED # detects memory leaks in the test
  911. def test_with_explicit_length(self):
  912. A = lltype.Array(lltype.Signed)
  913. a1 = lltype.malloc(A, 5, flavor='raw')
  914. a1[0] = 42
  915. c1 = lltype2ctypes(a1, normalize=False)
  916. assert c1.contents.length == 5
  917. assert c1.contents.items[0] == 42
  918. res = ctypes2lltype(lltype.Ptr(A), c1)
  919. assert res == a1
  920. assert len(res) == 5
  921. assert res[0] == 42
  922. res[0] += 1
  923. assert c1.contents.items[0] == 43
  924. assert a1[0] == 43
  925. a1[0] += 2
  926. assert c1.contents.items[0] == 45
  927. assert a1[0] == 45
  928. c1.contents.items[0] += 3
  929. assert res[0] == 48
  930. assert a1[0] == 48
  931. lltype.free(a1, flavor='raw')
  932. assert not ALLOCATED # detects memory leaks in the test
  933. def test_c_callback_with_void_arg_2(self):
  934. ftest = []
  935. def f(x):
  936. ftest.append(x)
  937. F = lltype.FuncType([lltype.Void], lltype.Void)
  938. fn = lltype.functionptr(F, 'askjh', _callable=f, _void0=-5)
  939. fn(-5)
  940. assert ftest == [-5]
  941. fn2 = lltype2ctypes(fn)
  942. fn2()
  943. assert ftest == [-5, -5]
  944. fn3 = ctypes2lltype(lltype.Ptr(F), fn2)
  945. fn3(-5)
  946. assert ftest == [-5, -5, -5]
  947. def test_c_callback_with_void_arg_3(self):
  948. from rpython.rtyper.lltypesystem.rstr import LLHelpers
  949. def f(i):
  950. x = 'X' * i
  951. return x[-2]
  952. a = RPythonAnnotator()
  953. r = a.build_types(f, [int])
  954. rtyper = RPythonTyper(a)
  955. rtyper.specialize()
  956. a.translator.rtyper = rtyper
  957. graph = a.translator.graphs[0]
  958. op = graph.startblock.operations[-1]
  959. assert op.opname == 'direct_call'
  960. assert op.args[0].value._obj._callable == LLHelpers.ll_stritem.im_func
  961. assert op.args[1].value == LLHelpers
  962. assert op.args[3].value == -2
  963. def test_recursive_struct_more(self):
  964. NODE = lltype.ForwardReference()
  965. NODE.become(lltype.Struct('NODE', ('value', rffi.LONG),
  966. ('next', lltype.Ptr(NODE))))
  967. CNODEPTR = get_ctypes_type(NODE)
  968. pc = CNODEPTR()
  969. pc.value = 42
  970. pc.next = ctypes.pointer(pc)
  971. p = ctypes2lltype(lltype.Ptr(NODE), ctypes.pointer(pc))
  972. assert p.value == 42
  973. assert p.next == p
  974. pc2 = lltype2ctypes(p)
  975. assert pc2.contents.value == 42
  976. assert pc2.contents.next.contents.value == 42
  977. def test_indirect_recursive_struct_more(self):
  978. NODE = lltype.ForwardReference()
  979. NODE2 = lltype.Struct('NODE2', ('ping', lltype.Ptr(NODE)))
  980. NODE.become(lltype.Struct('NODE', ('pong', NODE2)))
  981. # Building NODE2 first used to fail.
  982. get_ctypes_type(NODE2)
  983. CNODEPTR = get_ctypes_type(NODE)
  984. pc = CNODEPTR()
  985. pc.pong.ping = ctypes.pointer(pc)
  986. p = ctypes2lltype(lltype.Ptr(NODE), ctypes.pointer(pc))
  987. assert p.pong.ping == p
  988. def test_typedef(self):
  989. assert ctypes2lltype(lltype.Typedef(rffi.LONG, 'test'), 6) == 6
  990. assert ctypes2lltype(lltype.Typedef(lltype.Float, 'test2'), 3.4) == 3.4
  991. assert get_ctypes_type(rffi.LONG) == get_ctypes_type(
  992. lltype.Typedef(rffi.LONG, 'test3'))
  993. def test_cast_adr_to_int(self):
  994. class someaddr(object):
  995. def _cast_to_int(self):
  996. return sys.maxint/2 * 3
  997. res = cast_adr_to_int(someaddr())
  998. assert is_valid_int(res)
  999. assert res == -sys.maxint/2 - 3
  1000. def test_cast_gcref_back_and_forth(self):
  1001. NODE = lltype.GcStruct('NODE')
  1002. node = lltype.malloc(NODE)
  1003. ref = lltype.cast_opaque_ptr(llmemory.GCREF, node)
  1004. back = rffi.cast(llmemory.GCREF, rffi.cast(lltype.Signed, ref))
  1005. assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), back) == node
  1006. def test_gcref_forth_and_back(self):
  1007. cp = ctypes.c_void_p(1234)
  1008. v = ctypes2lltype(llmemory.GCREF, cp)
  1009. assert lltype2ctypes(v).value == cp.value
  1010. v1 = ctypes2lltype(llmemory.GCREF, cp)
  1011. assert v == v1
  1012. assert v
  1013. v2 = ctypes2lltype(llmemory.GCREF, ctypes.c_void_p(1235))
  1014. assert v2 != v
  1015. def test_gcref_type(self):
  1016. NODE = lltype.GcStruct('NODE')
  1017. node = lltype.malloc(NODE)
  1018. ref = lltype.cast_opaque_ptr(llmemory.GCREF, node)
  1019. v = lltype2ctypes(ref)
  1020. assert isinstance(v, ctypes.c_void_p)
  1021. def test_gcref_null(self):
  1022. ref = lltype.nullptr(llmemory.GCREF.TO)
  1023. v = lltype2ctypes(ref)
  1024. assert isinstance(v, ctypes.c_void_p)
  1025. def test_cast_null_gcref(self):
  1026. ref = lltype.nullptr(llmemory.GCREF.TO)
  1027. value = rffi.cast(lltype.Signed, ref)
  1028. assert value == 0
  1029. def test_cast_null_fakeaddr(self):
  1030. ref = llmemory.NULL
  1031. value = rffi.cast(lltype.Signed, ref)
  1032. assert value == 0
  1033. def test_gcref_truth(self):
  1034. p0 = ctypes.c_void_p(0)
  1035. ref0 = ctypes2lltype(llmemory.GCREF, p0)
  1036. assert not ref0
  1037. p1234 = ctypes.c_void_p(1234)
  1038. ref1234 = ctypes2lltype(llmemory.GCREF, p1234)
  1039. assert p1234
  1040. def test_gcref_casts(self):
  1041. p0 = ctypes.c_void_p(0)
  1042. ref0 = ctypes2lltype(llmemory.GCREF, p0)
  1043. assert lltype.cast_ptr_to_int(ref0) == 0
  1044. assert llmemory.cast_ptr_to_adr(ref0) == llmemory.NULL
  1045. NODE = lltype.GcStruct('NODE')
  1046. assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), ref0) == lltype.nullptr(NODE)
  1047. node = lltype.malloc(NODE)
  1048. ref1 = lltype.cast_opaque_ptr(llmemory.GCREF, node)
  1049. intval = rffi.cast(lltype.Signed, node)
  1050. intval1 = rffi.cast(lltype.Signed, ref1)
  1051. assert intval == intval1
  1052. ref2 = ctypes2lltype(llmemory.GCREF, intval1)
  1053. assert lltype.cast_opaque_ptr(lltype.Ptr(NODE), ref2) == node
  1054. #addr = llmemory.cast_ptr_to_adr(ref1)
  1055. #assert llmemory.cast_adr_to_int(addr) == intval
  1056. #assert lltype.cast_ptr_to_int(ref1) == intval
  1057. x = rffi.cast(llmemory.GCREF, -17)
  1058. assert lltype.cast_ptr_to_int(x) == -17
  1059. def test_ptr_truth(self):
  1060. abc = rffi.cast(lltype.Ptr(lltype.FuncType([], lltype.Void)), 0)
  1061. assert not abc
  1062. def test_mixed_gcref_comparison(self):
  1063. NODE = lltype.GcStruct('NODE')
  1064. node = lltype.malloc(NODE)
  1065. ref1 = lltype.cast_opaque_ptr(llmemory.GCREF, node)
  1066. ref2 = rffi.cast(llmemory.GCREF, 123)
  1067. assert ref1 != ref2
  1068. assert not (ref1 == ref2)
  1069. assert ref2 != ref1
  1070. assert not (ref2 == ref1)
  1071. assert node._obj._storage is True
  1072. # forced!
  1073. rffi.cast(lltype.Signed, ref1)
  1074. assert node._obj._storage not in (True, None)
  1075. assert ref1 != ref2
  1076. assert not (ref1 == ref2)
  1077. assert ref2 != ref1
  1078. assert not (ref2 == ref1)
  1079. def test_gcref_comparisons_back_and_forth(self):
  1080. NODE = lltype.GcStruct('NODE')
  1081. node = lltype.malloc(NODE)
  1082. ref1 = lltype.cast_opaque_ptr(llmemory.GCREF, node)
  1083. numb = rffi.cast(lltype.Signed, ref1)
  1084. ref2 = rffi.cast(llmemory.GCREF, numb)
  1085. assert ref1 == ref2
  1086. assert ref2 == ref1
  1087. assert not (ref1 != ref2)
  1088. assert not (ref2 != ref1)
  1089. def test_convert_subarray(self):
  1090. A = lltype.GcArray(lltype.Signed)
  1091. a = lltype.malloc(A, 20)
  1092. inside = lltype.direct_ptradd(lltype.direct_arrayitems(a), 3)
  1093. lltype2ctypes(inside)
  1094. start = rffi.cast(lltype.Signed, lltype.direct_arrayitems(a))
  1095. inside_int = rffi.cast(lltype.Signed, inside)
  1096. assert inside_int == start+rffi.sizeof(lltype.Signed)*3
  1097. def test_gcref_comparisons_through_addresses(self):
  1098. NODE = lltype.GcStruct('NODE')
  1099. n0 = lltype.malloc(NODE)
  1100. adr0 = llmemory.cast_ptr_to_adr(n0)
  1101. n1 = lltype.malloc(NODE)
  1102. i1 = rffi.cast(lltype.Signed, n1)
  1103. ref1 = rffi.cast(llmemory.GCREF, i1)
  1104. adr1 = llmemory.cast_ptr_to_adr(ref1)
  1105. assert adr1 != adr0
  1106. assert adr0 != adr1
  1107. adr1_2 = llmemory.cast_ptr_to_adr(n1)
  1108. #import pdb; pdb.set_trace()
  1109. assert adr1_2 == adr1
  1110. assert adr1 == adr1_2
  1111. def test_object_subclass(self):
  1112. from rpython.rtyper import rclass
  1113. from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
  1114. from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
  1115. class S:
  1116. pass
  1117. def f(n):
  1118. s = S()
  1119. s.x = n
  1120. ls = cast_instance_to_base_ptr(s)
  1121. as_num = rffi.cast(lltype.Signed, ls)
  1122. # --- around this point, only 'as_num' is passed
  1123. t = rffi.cast(rclass.OBJECTPTR, as_num)
  1124. u = cast_base_ptr_to_instance(S, t)
  1125. return u.x
  1126. res = interpret(f, [123])
  1127. assert res == 123
  1128. def test_object_subclass_2(self):
  1129. from rpython.rtyper import rclass
  1130. SCLASS = lltype.GcStruct('SCLASS',
  1131. ('parent', rclass.OBJECT),
  1132. ('n', lltype.Signed))
  1133. sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True,
  1134. immortal=True)
  1135. sclass_vtable.name = rclass.alloc_array_name('SClass')
  1136. def f(n):
  1137. rclass.declare_type_for_typeptr(sclass_vtable, SCLASS)
  1138. s = lltype.malloc(SCLASS)
  1139. s.parent.typeptr = sclass_vtable
  1140. s.n = n
  1141. as_num = rffi.cast(lltype.Signed, s)
  1142. # --- around this point, only 'as_num' is passed
  1143. t = rffi.cast(lltype.Ptr(SCLASS), as_num)
  1144. return t.n
  1145. res = interpret(f, [123])
  1146. assert res == 123
  1147. def test_object_subclass_3(self):
  1148. from rpython.rtyper import rclass
  1149. from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
  1150. from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
  1151. class S:
  1152. pass
  1153. def f(n):
  1154. s = S()
  1155. s.x = n
  1156. ls = cast_instance_to_base_ptr(s)
  1157. as_num = rffi.cast(lltype.Signed, ls)
  1158. # --- around this point, only 'as_num' is passed
  1159. r = rffi.cast(llmemory.GCREF, as_num)
  1160. t = lltype.cast_opaque_ptr(rclass.OBJECTPTR, r)
  1161. u = cast_base_ptr_to_instance(S, t)
  1162. return u.x
  1163. res = interpret(f, [123])
  1164. assert res == 123
  1165. def test_object_subclass_4(self):
  1166. from rpython.rtyper import rclass
  1167. SCLASS = lltype.GcStruct('SCLASS',
  1168. ('parent', rclass.OBJECT),
  1169. ('n', lltype.Signed))
  1170. sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True,
  1171. immortal=True)
  1172. sclass_vtable.name = rclass.alloc_array_name('SClass')
  1173. def f(n):
  1174. rclass.declare_type_for_typeptr(sclass_vtable, SCLASS)
  1175. s = lltype.malloc(SCLASS)
  1176. s.parent.typeptr = sclass_vtable
  1177. s.n = n
  1178. as_num = rffi.cast(lltype.Signed, s)
  1179. # --- around this point, only 'as_num' is passed
  1180. r = rffi.cast(llmemory.GCREF, as_num)
  1181. t = lltype.cast_opaque_ptr(lltype.Ptr(SCLASS), r)
  1182. return t.n
  1183. res = interpret(f, [123])
  1184. assert res == 123
  1185. def test_object_subclass_5(self):
  1186. from rpython.rtyper import rclass
  1187. from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
  1188. from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
  1189. class S:
  1190. x = 5 # entry in the vtable
  1191. class T(S):
  1192. x = 6
  1193. def f():
  1194. s = T()
  1195. ls = cast_instance_to_base_ptr(s)
  1196. as_num = rffi.cast(lltype.Signed, ls)
  1197. # --- around this point, only 'as_num' is passed
  1198. t = rffi.cast(rclass.OBJECTPTR, as_num)
  1199. u = cast_base_ptr_to_instance(S, t)
  1200. return u.x
  1201. res = interpret(f, [])
  1202. assert res == 6
  1203. def test_force_to_int(self):
  1204. S = lltype.Struct('S')
  1205. p = lltype.malloc(S, flavor='raw')
  1206. a = llmemory.cast_ptr_to_adr(p)
  1207. i = llmemory.cast_adr_to_int(a, "forced")
  1208. assert is_valid_int(i)
  1209. assert i == llmemory.cast_adr_to_int(a, "forced")
  1210. lltype.free(p, flavor='raw')
  1211. def test_freelist(self):
  1212. S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed))
  1213. SP = lltype.Ptr(S)
  1214. chunk = lltype.malloc(rffi.CArrayPtr(S).TO, 10, flavor='raw')
  1215. assert lltype.typeOf(chunk) == rffi.CArrayPtr(S)
  1216. free_list = lltype.nullptr(rffi.VOIDP.TO)
  1217. # build list
  1218. current = chunk
  1219. for i in range(10):
  1220. rffi.cast(rffi.VOIDPP, current)[0] = free_list
  1221. free_list = rffi.cast(rffi.VOIDP, current)
  1222. current = rffi.ptradd(current, 1)
  1223. # get one
  1224. p = free_list
  1225. free_list = rffi.cast(rffi.VOIDPP, p)[0]
  1226. rffi.cast(SP, p).x = 0
  1227. # get two
  1228. p = free_list
  1229. free_list = rffi.cast(rffi.VOIDPP, p)[0]
  1230. rffi.cast(SP, p).x = 0
  1231. # get three
  1232. p = free_list
  1233. free_list = rffi.cast(rffi.VOIDPP, p)[0]
  1234. rffi.cast(SP, p).x = 0
  1235. lltype.free(chunk, flavor='raw')
  1236. def test_opaque_tagged_pointers(self):
  1237. from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
  1238. from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
  1239. from rpython.rtyper import rclass
  1240. class Opaque(object):
  1241. llopaque = True
  1242. def hide(self):
  1243. ptr = cast_instance_to_base_ptr(self)
  1244. return lltype.cast_opaque_ptr(llmemory.GCREF, ptr)
  1245. @staticmethod
  1246. def show(gcref):
  1247. ptr = lltype.cast_opaque_ptr(lltype.Ptr(rclass.OBJECT), gcref)
  1248. return cast_base_ptr_to_instance(Opaque, ptr)
  1249. opaque = Opaque()
  1250. round = ctypes2lltype(llmemory.GCREF, lltype2ctypes(opaque.hide()))
  1251. assert Opaque.show(round) is opaque
  1252. def test_array_of_structs(self):
  1253. A = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed)))
  1254. a = lltype.malloc(A, 5)
  1255. a2 = ctypes2lltype(lltype.Ptr(A), lltype2ctypes(a))
  1256. assert a2._obj.getitem(0)._obj._parentstructure() is a2._obj
  1257. def test_array_of_function_pointers(self):
  1258. c_source = py.code.Source(r"""
  1259. #include "src/precommondefs.h"
  1260. #include <stdio.h>
  1261. typedef int(*funcptr_t)(void);
  1262. static int forty_two(void) { return 42; }
  1263. static int forty_three(void) { return 43; }
  1264. static funcptr_t testarray[2];
  1265. RPY_EXPORTED void runtest(void cb(funcptr_t *)) {
  1266. testarray[0] = &forty_two;
  1267. testarray[1] = &forty_three;
  1268. fprintf(stderr, "&forty_two = %p\n", testarray[0]);
  1269. fprintf(stderr, "&forty_three = %p\n", testarray[1]);
  1270. cb(testarray);
  1271. testarray[0] = 0;
  1272. testarray[1] = 0;
  1273. }
  1274. """)
  1275. eci = ExternalCompilationInfo(include_dirs=[cdir],
  1276. separate_module_sources=[c_source])
  1277. PtrF = lltype.Ptr(lltype.FuncType([], rffi.INT))
  1278. ArrayPtrF = rffi.CArrayPtr(PtrF)
  1279. CALLBACK = rffi.CCallback([ArrayPtrF], lltype.Void)
  1280. runtest = rffi.llexternal('runtest', [CALLBACK], lltype.Void,
  1281. compilation_info=eci)
  1282. seen = []
  1283. def callback(testarray):
  1284. seen.append(testarray[0]) # read a PtrF out of testarray
  1285. seen.append(testarray[1])
  1286. runtest(callback)
  1287. assert seen[0]() == 42
  1288. assert seen[1]() == 43
  1289. class TestPlatform(object):
  1290. def test_lib_on_libpaths(self):
  1291. from rpython.translator.platform import platform
  1292. tmpdir = udir.join('lib_on_libppaths')
  1293. tmpdir.ensure(dir=1)
  1294. c_file = tmpdir.join('c_file.c')
  1295. c_file.write('''
  1296. #include "src/precommondefs.h"
  1297. RPY_EXPORTED int f(int a, int b) { return (a + b); }
  1298. ''')
  1299. eci = ExternalCompilationInfo(include_dirs=[cdir])
  1300. so = platform.compile([c_file], eci, standalone=False)
  1301. eci = ExternalCompilationInfo(
  1302. libraries = ['c_file'],
  1303. library_dirs = [str(so.dirpath())]
  1304. )
  1305. f = rffi.llexternal('f', [rffi.INT, rffi.INT], rffi.INT,
  1306. compilation_info=eci)
  1307. assert f(3, 4) == 7
  1308. def test_prefix(self):
  1309. if not sys.platform.startswith('linux'):
  1310. py.test.skip("Not supported")
  1311. from rpython.translator.platform import platform
  1312. tmpdir = udir.join('lib_on_libppaths_prefix')
  1313. tmpdir.ensure(dir=1)
  1314. c_file = tmpdir.join('c_file.c')
  1315. c_file.write('''
  1316. #include "src/precommondefs.h"
  1317. RPY_EXPORTED int f(int a, int b) { return (a + b); }
  1318. ''')
  1319. eci = ExternalCompilationInfo(include_dirs=[cdir])
  1320. so = platform.compile([c_file], eci, standalone=False)
  1321. sopath = py.path.local(so)
  1322. sopath.move(sopath.dirpath().join('libc_file.so'))
  1323. eci = ExternalCompilationInfo(
  1324. libraries = ['c_file'],
  1325. library_dirs = [str(so.dirpath())]
  1326. )
  1327. f = rffi.llexternal('f', [rffi.INT, rffi.INT], rffi.INT,
  1328. compilation_info=eci)
  1329. assert f(3, 4) == 7
  1330. def test_llgcopaque_eq(self):
  1331. assert _llgcopaque(1) != None
  1332. assert _llgcopaque(0) == None
  1333. def test_array_of_struct(self):
  1334. A2 = lltype.Array(('a', lltype.Signed), ('b', lltype.Signed))
  1335. a = lltype.malloc(A2, 10, flavor='raw')
  1336. a[3].b = 42
  1337. ac = lltype2ctypes(a[3])
  1338. assert ac.contents.b == 42
  1339. ac.contents.a = 17
  1340. assert a[3].a == 17
  1341. #lltype.free(a, flavor='raw')
  1342. py.test.skip("free() not working correctly here...")
  1343. def test_fixedsizedarray_to_ctypes(self):
  1344. T = lltype.Ptr(rffi.CFixedArray(rffi.INT, 1))
  1345. inst = lltype.malloc(T.TO, flavor='raw')
  1346. inst[0] = rffi.cast(rffi.INT, 42)
  1347. assert inst[0] == 42
  1348. cinst = lltype2ctypes(inst)
  1349. assert rffi.cast(lltype.Signed, inst[0]) == 42
  1350. assert cinst.contents.item0 == 42
  1351. lltype.free(inst, flavor='raw')
  1352. def test_fixedsizedarray_to_ctypes(self):
  1353. T = lltype.Ptr(rffi.CFixedArray(rffi.CHAR, 123))
  1354. inst = lltype.malloc(T.TO, flavor='raw', zero=True)
  1355. cinst = lltype2ctypes(inst)
  1356. assert cinst.contents.item0 == 0
  1357. lltype.free(inst, flavor='raw')