PageRenderTime 56ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/translator/c/test/test_standalone.py

https://bitbucket.org/evelyn559/pypy
Python | 1152 lines | 1141 code | 11 blank | 0 comment | 10 complexity | a48a46c0c9ccf50e6b4062b321e27613 MD5 | raw file
  1. import py
  2. import sys, os, re
  3. from pypy.rlib.objectmodel import keepalive_until_here
  4. from pypy.rlib.rarithmetic import r_longlong
  5. from pypy.rlib.debug import ll_assert, have_debug_prints, debug_flush
  6. from pypy.rlib.debug import debug_print, debug_start, debug_stop, debug_offset
  7. from pypy.translator.translator import TranslationContext
  8. from pypy.translator.backendopt import all
  9. from pypy.translator.c.genc import CStandaloneBuilder, ExternalCompilationInfo
  10. from pypy.annotation.listdef import s_list_of_strings
  11. from pypy.tool.udir import udir
  12. from pypy.tool.autopath import pypydir
  13. from pypy.conftest import option
  14. class StandaloneTests(object):
  15. config = None
  16. def compile(self, entry_point, debug=True, shared=False,
  17. stackcheck=False):
  18. t = TranslationContext(self.config)
  19. t.buildannotator().build_types(entry_point, [s_list_of_strings])
  20. t.buildrtyper().specialize()
  21. if stackcheck:
  22. from pypy.translator.transform import insert_ll_stackcheck
  23. insert_ll_stackcheck(t)
  24. t.config.translation.shared = shared
  25. cbuilder = CStandaloneBuilder(t, entry_point, t.config)
  26. if debug:
  27. cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES)
  28. else:
  29. cbuilder.generate_source()
  30. cbuilder.compile()
  31. if option.view:
  32. t.view()
  33. return t, cbuilder
  34. class TestStandalone(StandaloneTests):
  35. def test_hello_world(self):
  36. def entry_point(argv):
  37. os.write(1, "hello world\n")
  38. argv = argv[1:]
  39. os.write(1, "argument count: " + str(len(argv)) + "\n")
  40. for s in argv:
  41. os.write(1, " '" + str(s) + "'\n")
  42. return 0
  43. t, cbuilder = self.compile(entry_point)
  44. data = cbuilder.cmdexec('hi there')
  45. assert data.startswith('''hello world\nargument count: 2\n 'hi'\n 'there'\n''')
  46. # Verify that the generated C files have sane names:
  47. gen_c_files = [str(f) for f in cbuilder.extrafiles]
  48. for expfile in ('rlib_rposix.c',
  49. 'rpython_lltypesystem_rstr.c',
  50. 'translator_c_test_test_standalone.c'):
  51. assert cbuilder.targetdir.join(expfile) in gen_c_files
  52. def test_print(self):
  53. def entry_point(argv):
  54. print "hello simpler world"
  55. argv = argv[1:]
  56. print "argument count:", len(argv)
  57. print "arguments:", argv
  58. print "argument lengths:",
  59. print [len(s) for s in argv]
  60. return 0
  61. t, cbuilder = self.compile(entry_point)
  62. data = cbuilder.cmdexec('hi there')
  63. assert data.startswith('''hello simpler world\n'''
  64. '''argument count: 2\n'''
  65. '''arguments: [hi, there]\n'''
  66. '''argument lengths: [2, 5]\n''')
  67. # NB. RPython has only str, not repr, so str() on a list of strings
  68. # gives the strings unquoted in the list
  69. def test_counters(self):
  70. from pypy.rpython.lltypesystem import lltype
  71. from pypy.rpython.lltypesystem.lloperation import llop
  72. def entry_point(argv):
  73. llop.instrument_count(lltype.Void, 'test', 2)
  74. llop.instrument_count(lltype.Void, 'test', 1)
  75. llop.instrument_count(lltype.Void, 'test', 1)
  76. llop.instrument_count(lltype.Void, 'test', 2)
  77. llop.instrument_count(lltype.Void, 'test', 1)
  78. return 0
  79. t = TranslationContext(self.config)
  80. t.config.translation.instrument = True
  81. t.buildannotator().build_types(entry_point, [s_list_of_strings])
  82. t.buildrtyper().specialize()
  83. cbuilder = CStandaloneBuilder(t, entry_point, config=t.config) # xxx
  84. cbuilder.generate_source()
  85. cbuilder.compile()
  86. counters_fname = udir.join("_counters_")
  87. os.environ['_INSTRUMENT_COUNTERS'] = str(counters_fname)
  88. try:
  89. data = cbuilder.cmdexec()
  90. finally:
  91. del os.environ['_INSTRUMENT_COUNTERS']
  92. f = counters_fname.open('rb')
  93. counters_data = f.read()
  94. f.close()
  95. import struct
  96. counters = struct.unpack("LLL", counters_data)
  97. assert counters == (0,3,2)
  98. def test_prof_inline(self):
  99. py.test.skip("broken by 5b0e029514d4, but we don't use it any more")
  100. if sys.platform == 'win32':
  101. py.test.skip("instrumentation support is unix only for now")
  102. def add(a,b):
  103. return a + b - b + b - b + b - b + b - b + b - b + b - b + b
  104. def entry_point(argv):
  105. tot = 0
  106. x = int(argv[1])
  107. while x > 0:
  108. tot = add(tot, x)
  109. x -= 1
  110. os.write(1, str(tot))
  111. return 0
  112. from pypy.translator.interactive import Translation
  113. t = Translation(entry_point, backend='c', standalone=True)
  114. # no counters
  115. t.backendopt(inline_threshold=100, profile_based_inline="500")
  116. exe = t.compile()
  117. out = py.process.cmdexec("%s 500" % exe)
  118. assert int(out) == 500*501/2
  119. t = Translation(entry_point, backend='c', standalone=True)
  120. # counters
  121. t.backendopt(inline_threshold=all.INLINE_THRESHOLD_FOR_TEST*0.5,
  122. profile_based_inline="500")
  123. exe = t.compile()
  124. out = py.process.cmdexec("%s 500" % exe)
  125. assert int(out) == 500*501/2
  126. def test_frexp(self):
  127. import math
  128. def entry_point(argv):
  129. m, e = math.frexp(0)
  130. x, y = math.frexp(0)
  131. print m, x
  132. return 0
  133. t, cbuilder = self.compile(entry_point)
  134. data = cbuilder.cmdexec('hi there')
  135. assert map(float, data.split()) == [0.0, 0.0]
  136. def test_profopt(self):
  137. def add(a,b):
  138. return a + b - b + b - b + b - b + b - b + b - b + b - b + b
  139. def entry_point(argv):
  140. tot = 0
  141. x = int(argv[1])
  142. while x > 0:
  143. tot = add(tot, x)
  144. x -= 1
  145. os.write(1, str(tot))
  146. return 0
  147. from pypy.translator.interactive import Translation
  148. # XXX this is mostly a "does not crash option"
  149. t = Translation(entry_point, backend='c', standalone=True, profopt="100")
  150. # no counters
  151. t.backendopt()
  152. exe = t.compile()
  153. out = py.process.cmdexec("%s 500" % exe)
  154. assert int(out) == 500*501/2
  155. t = Translation(entry_point, backend='c', standalone=True, profopt="100",
  156. noprofopt=True)
  157. # no counters
  158. t.backendopt()
  159. exe = t.compile()
  160. out = py.process.cmdexec("%s 500" % exe)
  161. assert int(out) == 500*501/2
  162. if hasattr(os, 'setpgrp'):
  163. def test_os_setpgrp(self):
  164. def entry_point(argv):
  165. os.setpgrp()
  166. return 0
  167. t, cbuilder = self.compile(entry_point)
  168. cbuilder.cmdexec("")
  169. def test_profopt_mac_osx_bug(self):
  170. if sys.platform == 'win32':
  171. py.test.skip("no profopt on win32")
  172. def entry_point(argv):
  173. import os
  174. pid = os.fork()
  175. if pid:
  176. os.waitpid(pid, 0)
  177. else:
  178. os._exit(0)
  179. return 0
  180. from pypy.translator.interactive import Translation
  181. # XXX this is mostly a "does not crash option"
  182. t = Translation(entry_point, backend='c', standalone=True, profopt="")
  183. # no counters
  184. t.backendopt()
  185. exe = t.compile()
  186. #py.process.cmdexec(exe)
  187. t = Translation(entry_point, backend='c', standalone=True, profopt="",
  188. noprofopt=True)
  189. # no counters
  190. t.backendopt()
  191. exe = t.compile()
  192. #py.process.cmdexec(exe)
  193. def test_standalone_large_files(self):
  194. filename = str(udir.join('test_standalone_largefile'))
  195. r4800000000 = r_longlong(4800000000L)
  196. def entry_point(argv):
  197. assert str(r4800000000 + r_longlong(len(argv))) == '4800000003'
  198. fd = os.open(filename, os.O_RDWR | os.O_CREAT, 0644)
  199. os.lseek(fd, r4800000000, 0)
  200. newpos = os.lseek(fd, 0, 1)
  201. if newpos == r4800000000:
  202. print "OK"
  203. else:
  204. print "BAD POS"
  205. os.close(fd)
  206. return 0
  207. t, cbuilder = self.compile(entry_point)
  208. data = cbuilder.cmdexec('hi there')
  209. assert data.strip() == "OK"
  210. def test_separate_files(self):
  211. # One file in translator/c/src
  212. fname = py.path.local(pypydir).join(
  213. 'translator', 'c', 'src', 'll_strtod.h')
  214. # One file in (another) subdir of the temp directory
  215. dirname = udir.join("test_dir").ensure(dir=1)
  216. fname2 = dirname.join("test_genc.c")
  217. fname2.write("""
  218. void f() {
  219. LL_strtod_formatd(12.3, 'f', 5);
  220. }""")
  221. files = [fname, fname2]
  222. def entry_point(argv):
  223. return 0
  224. t = TranslationContext(self.config)
  225. t.buildannotator().build_types(entry_point, [s_list_of_strings])
  226. t.buildrtyper().specialize()
  227. cbuilder = CStandaloneBuilder(t, entry_point, t.config)
  228. cbuilder.eci = cbuilder.eci.merge(
  229. ExternalCompilationInfo(separate_module_files=files))
  230. cbuilder.generate_source()
  231. makefile = udir.join(cbuilder.modulename, 'Makefile').read()
  232. # generated files are compiled in the same directory
  233. assert " ../test_dir/test_genc.c" in makefile
  234. assert " ../test_dir/test_genc.o" in makefile
  235. # but files from pypy source dir must be copied
  236. assert "translator/c/src" not in makefile
  237. assert " ll_strtod.h" in makefile
  238. assert " ll_strtod.o" in makefile
  239. def test_debug_print_start_stop(self):
  240. def entry_point(argv):
  241. x = "got:"
  242. debug_start ("mycat")
  243. if have_debug_prints(): x += "b"
  244. debug_print ("foo", r_longlong(2), "bar", 3)
  245. debug_start ("cat2")
  246. if have_debug_prints(): x += "c"
  247. debug_print ("baz")
  248. debug_stop ("cat2")
  249. if have_debug_prints(): x += "d"
  250. debug_print ("bok")
  251. debug_stop ("mycat")
  252. if have_debug_prints(): x += "a"
  253. debug_print("toplevel")
  254. debug_flush()
  255. os.write(1, x + "." + str(debug_offset()) + '.\n')
  256. return 0
  257. t, cbuilder = self.compile(entry_point)
  258. # check with PYPYLOG undefined
  259. out, err = cbuilder.cmdexec("", err=True, env={})
  260. assert out.strip() == 'got:a.-1.'
  261. assert 'toplevel' in err
  262. assert 'mycat' not in err
  263. assert 'foo 2 bar 3' not in err
  264. assert 'cat2' not in err
  265. assert 'baz' not in err
  266. assert 'bok' not in err
  267. # check with PYPYLOG defined to an empty string (same as undefined)
  268. out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ''})
  269. assert out.strip() == 'got:a.-1.'
  270. assert 'toplevel' in err
  271. assert 'mycat' not in err
  272. assert 'foo 2 bar 3' not in err
  273. assert 'cat2' not in err
  274. assert 'baz' not in err
  275. assert 'bok' not in err
  276. # check with PYPYLOG=:- (means print to stderr)
  277. out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': ':-'})
  278. assert out.strip() == 'got:bcda.-1.'
  279. assert 'toplevel' in err
  280. assert '{mycat' in err
  281. assert 'mycat}' in err
  282. assert 'foo 2 bar 3' in err
  283. assert '{cat2' in err
  284. assert 'cat2}' in err
  285. assert 'baz' in err
  286. assert 'bok' in err
  287. # check with PYPYLOG=:somefilename
  288. path = udir.join('test_debug_xxx.log')
  289. out, err = cbuilder.cmdexec("", err=True,
  290. env={'PYPYLOG': ':%s' % path})
  291. size = os.stat(str(path)).st_size
  292. assert out.strip() == 'got:bcda.' + str(size) + '.'
  293. assert not err
  294. assert path.check(file=1)
  295. data = path.read()
  296. assert 'toplevel' in data
  297. assert '{mycat' in data
  298. assert 'mycat}' in data
  299. assert 'foo 2 bar 3' in data
  300. assert '{cat2' in data
  301. assert 'cat2}' in data
  302. assert 'baz' in data
  303. assert 'bok' in data
  304. # check with PYPYLOG=somefilename
  305. path = udir.join('test_debug_xxx_prof.log')
  306. out, err = cbuilder.cmdexec("", err=True, env={'PYPYLOG': str(path)})
  307. size = os.stat(str(path)).st_size
  308. assert out.strip() == 'got:a.' + str(size) + '.'
  309. assert not err
  310. assert path.check(file=1)
  311. data = path.read()
  312. assert 'toplevel' in data
  313. assert '{mycat' in data
  314. assert 'mycat}' in data
  315. assert 'foo 2 bar 3' not in data
  316. assert '{cat2' in data
  317. assert 'cat2}' in data
  318. assert 'baz' not in data
  319. assert 'bok' not in data
  320. # check with PYPYLOG=myc:somefilename (includes mycat but not cat2)
  321. path = udir.join('test_debug_xxx_myc.log')
  322. out, err = cbuilder.cmdexec("", err=True,
  323. env={'PYPYLOG': 'myc:%s' % path})
  324. size = os.stat(str(path)).st_size
  325. assert out.strip() == 'got:bda.' + str(size) + '.'
  326. assert not err
  327. assert path.check(file=1)
  328. data = path.read()
  329. assert 'toplevel' in data
  330. assert '{mycat' in data
  331. assert 'mycat}' in data
  332. assert 'foo 2 bar 3' in data
  333. assert 'cat2' not in data
  334. assert 'baz' not in data
  335. assert 'bok' in data
  336. # check with PYPYLOG=cat:somefilename (includes cat2 but not mycat)
  337. path = udir.join('test_debug_xxx_cat.log')
  338. out, err = cbuilder.cmdexec("", err=True,
  339. env={'PYPYLOG': 'cat:%s' % path})
  340. size = os.stat(str(path)).st_size
  341. assert out.strip() == 'got:ca.' + str(size) + '.'
  342. assert not err
  343. assert path.check(file=1)
  344. data = path.read()
  345. assert 'toplevel' in data
  346. assert 'mycat' not in data
  347. assert 'foo 2 bar 3' not in data
  348. assert 'cat2' in data
  349. assert 'baz' in data
  350. assert 'bok' not in data
  351. # check with PYPYLOG=myc,cat2:somefilename (includes mycat and cat2)
  352. path = udir.join('test_debug_xxx_myc_cat2.log')
  353. out, err = cbuilder.cmdexec("", err=True,
  354. env={'PYPYLOG': 'myc,cat2:%s' % path})
  355. size = os.stat(str(path)).st_size
  356. assert out.strip() == 'got:bcda.' + str(size) + '.'
  357. assert not err
  358. assert path.check(file=1)
  359. data = path.read()
  360. assert 'toplevel' in data
  361. assert '{mycat' in data
  362. assert 'mycat}' in data
  363. assert 'foo 2 bar 3' in data
  364. assert 'cat2' in data
  365. assert 'baz' in data
  366. assert 'bok' in data
  367. #
  368. # finally, check compiling with logging disabled
  369. from pypy.config.pypyoption import get_pypy_config
  370. config = get_pypy_config(translating=True)
  371. config.translation.log = False
  372. self.config = config
  373. t, cbuilder = self.compile(entry_point)
  374. path = udir.join('test_debug_does_not_show_up.log')
  375. out, err = cbuilder.cmdexec("", err=True,
  376. env={'PYPYLOG': ':%s' % path})
  377. assert out.strip() == 'got:.-1.'
  378. assert not err
  379. assert path.check(file=0)
  380. def test_debug_print_start_stop_nonconst(self):
  381. def entry_point(argv):
  382. debug_start(argv[1])
  383. debug_print(argv[2])
  384. debug_stop(argv[1])
  385. return 0
  386. t, cbuilder = self.compile(entry_point)
  387. out, err = cbuilder.cmdexec("foo bar", err=True, env={'PYPYLOG': ':-'})
  388. lines = err.splitlines()
  389. assert '{foo' in lines[0]
  390. assert 'bar' == lines[1]
  391. assert 'foo}' in lines[2]
  392. def test_fatal_error(self):
  393. def g(x):
  394. if x == 1:
  395. raise ValueError
  396. else:
  397. raise KeyError
  398. def entry_point(argv):
  399. if len(argv) < 3:
  400. g(len(argv))
  401. return 0
  402. t, cbuilder = self.compile(entry_point)
  403. #
  404. out, err = cbuilder.cmdexec("", expect_crash=True)
  405. assert out.strip() == ''
  406. lines = err.strip().splitlines()
  407. idx = lines.index('Fatal RPython error: ValueError') # assert found
  408. lines = lines[:idx+1]
  409. assert len(lines) >= 4
  410. l0, l1, l2 = lines[-4:-1]
  411. assert l0 == 'RPython traceback:'
  412. assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
  413. assert re.match(r' File "\w+.c", line \d+, in g', l2)
  414. #
  415. out2, err2 = cbuilder.cmdexec("x", expect_crash=True)
  416. assert out2.strip() == ''
  417. lines2 = err2.strip().splitlines()
  418. idx = lines2.index('Fatal RPython error: KeyError') # assert found
  419. lines2 = lines2[:idx+1]
  420. l0, l1, l2 = lines2[-4:-1]
  421. assert l0 == 'RPython traceback:'
  422. assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
  423. assert re.match(r' File "\w+.c", line \d+, in g', l2)
  424. assert lines2[-2] != lines[-2] # different line number
  425. assert lines2[-3] == lines[-3] # same line number
  426. def test_fatal_error_finally_1(self):
  427. # a simple case of try:finally:
  428. def g(x):
  429. if x == 1:
  430. raise KeyError
  431. def h(x):
  432. try:
  433. g(x)
  434. finally:
  435. os.write(1, 'done.\n')
  436. def entry_point(argv):
  437. if len(argv) < 3:
  438. h(len(argv))
  439. return 0
  440. t, cbuilder = self.compile(entry_point)
  441. #
  442. out, err = cbuilder.cmdexec("", expect_crash=True)
  443. assert out.strip() == 'done.'
  444. lines = err.strip().splitlines()
  445. idx = lines.index('Fatal RPython error: KeyError') # assert found
  446. lines = lines[:idx+1]
  447. assert len(lines) >= 5
  448. l0, l1, l2, l3 = lines[-5:-1]
  449. assert l0 == 'RPython traceback:'
  450. assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
  451. assert re.match(r' File "\w+.c", line \d+, in h', l2)
  452. assert re.match(r' File "\w+.c", line \d+, in g', l3)
  453. def test_fatal_error_finally_2(self):
  454. # a try:finally: in which we raise and catch another exception
  455. def raiseme(x):
  456. if x == 1:
  457. raise ValueError
  458. def raise_and_catch(x):
  459. try:
  460. raiseme(x)
  461. except ValueError:
  462. pass
  463. def g(x):
  464. if x == 1:
  465. raise KeyError
  466. def h(x):
  467. try:
  468. g(x)
  469. finally:
  470. raise_and_catch(x)
  471. os.write(1, 'done.\n')
  472. def entry_point(argv):
  473. if len(argv) < 3:
  474. h(len(argv))
  475. return 0
  476. t, cbuilder = self.compile(entry_point)
  477. #
  478. out, err = cbuilder.cmdexec("", expect_crash=True)
  479. assert out.strip() == 'done.'
  480. lines = err.strip().splitlines()
  481. idx = lines.index('Fatal RPython error: KeyError') # assert found
  482. lines = lines[:idx+1]
  483. assert len(lines) >= 5
  484. l0, l1, l2, l3 = lines[-5:-1]
  485. assert l0 == 'RPython traceback:'
  486. assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
  487. assert re.match(r' File "\w+.c", line \d+, in h', l2)
  488. assert re.match(r' File "\w+.c", line \d+, in g', l3)
  489. def test_fatal_error_finally_3(self):
  490. py.test.skip("not implemented: "
  491. "a try:finally: in which we raise the *same* exception")
  492. def test_fatal_error_finally_4(self):
  493. # a try:finally: in which we raise (and don't catch) an exception
  494. def raiseme(x):
  495. if x == 1:
  496. raise ValueError
  497. def g(x):
  498. if x == 1:
  499. raise KeyError
  500. def h(x):
  501. try:
  502. g(x)
  503. finally:
  504. raiseme(x)
  505. os.write(1, 'done.\n')
  506. def entry_point(argv):
  507. if len(argv) < 3:
  508. h(len(argv))
  509. return 0
  510. t, cbuilder = self.compile(entry_point)
  511. #
  512. out, err = cbuilder.cmdexec("", expect_crash=True)
  513. assert out.strip() == ''
  514. lines = err.strip().splitlines()
  515. idx = lines.index('Fatal RPython error: ValueError') # assert found
  516. lines = lines[:idx+1]
  517. assert len(lines) >= 5
  518. l0, l1, l2, l3 = lines[-5:-1]
  519. assert l0 == 'RPython traceback:'
  520. assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
  521. assert re.match(r' File "\w+.c", line \d+, in h', l2)
  522. assert re.match(r' File "\w+.c", line \d+, in raiseme', l3)
  523. def test_assertion_error_debug(self):
  524. def entry_point(argv):
  525. assert len(argv) != 1
  526. return 0
  527. t, cbuilder = self.compile(entry_point, debug=True)
  528. out, err = cbuilder.cmdexec("", expect_crash=True)
  529. assert out.strip() == ''
  530. lines = err.strip().splitlines()
  531. assert 'in pypy_g_RPyRaiseException: AssertionError' in lines
  532. def test_assertion_error_nondebug(self):
  533. def g(x):
  534. assert x != 1
  535. def f(argv):
  536. try:
  537. g(len(argv))
  538. finally:
  539. print 'done'
  540. def entry_point(argv):
  541. f(argv)
  542. return 0
  543. t, cbuilder = self.compile(entry_point, debug=False)
  544. out, err = cbuilder.cmdexec("", expect_crash=True)
  545. assert out.strip() == ''
  546. lines = err.strip().splitlines()
  547. idx = lines.index('Fatal RPython error: AssertionError') # assert found
  548. lines = lines[:idx+1]
  549. assert len(lines) >= 4
  550. l0, l1, l2 = lines[-4:-1]
  551. assert l0 == 'RPython traceback:'
  552. assert re.match(r' File "\w+.c", line \d+, in f', l1)
  553. assert re.match(r' File "\w+.c", line \d+, in g', l2)
  554. # The traceback stops at f() because it's the first function that
  555. # captures the AssertionError, which makes the program abort.
  556. def test_int_lshift_too_large(self):
  557. from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT
  558. def entry_point(argv):
  559. a = int(argv[1])
  560. b = int(argv[2])
  561. print a << b
  562. return 0
  563. t, cbuilder = self.compile(entry_point, debug=True)
  564. out = cbuilder.cmdexec("10 2", expect_crash=False)
  565. assert out.strip() == str(10 << 2)
  566. cases = [-4, LONG_BIT, LONGLONG_BIT]
  567. for x in cases:
  568. out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True)
  569. lines = err.strip()
  570. assert 'The shift count is outside of the supported range' in lines
  571. def test_llong_rshift_too_large(self):
  572. from pypy.rlib.rarithmetic import LONG_BIT, LONGLONG_BIT
  573. def entry_point(argv):
  574. a = r_longlong(int(argv[1]))
  575. b = r_longlong(int(argv[2]))
  576. print a >> b
  577. return 0
  578. t, cbuilder = self.compile(entry_point, debug=True)
  579. out = cbuilder.cmdexec("10 2", expect_crash=False)
  580. assert out.strip() == str(10 >> 2)
  581. out = cbuilder.cmdexec("%s %s" % (-42, LONGLONG_BIT - 1), expect_crash=False)
  582. assert out.strip() == '-1'
  583. cases = [-4, LONGLONG_BIT]
  584. for x in cases:
  585. out, err = cbuilder.cmdexec("%s %s" % (1, x), expect_crash=True)
  586. lines = err.strip()
  587. assert 'The shift count is outside of the supported range' in lines
  588. def test_ll_assert_error_debug(self):
  589. def entry_point(argv):
  590. ll_assert(len(argv) != 1, "foobar")
  591. return 0
  592. t, cbuilder = self.compile(entry_point, debug=True)
  593. out, err = cbuilder.cmdexec("", expect_crash=True)
  594. assert out.strip() == ''
  595. lines = err.strip().splitlines()
  596. assert 'in pypy_g_entry_point: foobar' in lines
  597. def test_ll_assert_error_nondebug(self):
  598. py.test.skip("implement later, maybe: tracebacks even with ll_assert")
  599. def g(x):
  600. ll_assert(x != 1, "foobar")
  601. def f(argv):
  602. try:
  603. g(len(argv))
  604. finally:
  605. print 'done'
  606. def entry_point(argv):
  607. f(argv)
  608. return 0
  609. t, cbuilder = self.compile(entry_point)
  610. out, err = cbuilder.cmdexec("", expect_crash=True)
  611. assert out.strip() == ''
  612. lines = err.strip().splitlines()
  613. idx = lines.index('PyPy assertion failed: foobar') # assert found
  614. lines = lines[:idx+1]
  615. assert len(lines) >= 4
  616. l0, l1, l2 = lines[-4:-1]
  617. assert l0 == 'RPython traceback:'
  618. assert re.match(r' File "\w+.c", line \d+, in f', l1)
  619. assert re.match(r' File "\w+.c", line \d+, in g', l2)
  620. # The traceback stops at f() because it's the first function that
  621. # captures the AssertionError, which makes the program abort.
  622. def test_shared(self, monkeypatch):
  623. def f(argv):
  624. print len(argv)
  625. def entry_point(argv):
  626. f(argv)
  627. return 0
  628. t, cbuilder = self.compile(entry_point, shared=True)
  629. assert cbuilder.shared_library_name is not None
  630. assert cbuilder.shared_library_name != cbuilder.executable_name
  631. monkeypatch.setenv('LD_LIBRARY_PATH',
  632. cbuilder.shared_library_name.dirpath())
  633. out, err = cbuilder.cmdexec("a b")
  634. assert out == "3"
  635. def test_gcc_options(self):
  636. # check that the env var CC is correctly interpreted, even if
  637. # it contains the compiler name followed by some options.
  638. if sys.platform == 'win32':
  639. py.test.skip("only for gcc")
  640. from pypy.rpython.lltypesystem import lltype, rffi
  641. dir = udir.ensure('test_gcc_options', dir=1)
  642. dir.join('someextraheader.h').write('#define someextrafunc() 42\n')
  643. eci = ExternalCompilationInfo(includes=['someextraheader.h'])
  644. someextrafunc = rffi.llexternal('someextrafunc', [], lltype.Signed,
  645. compilation_info=eci)
  646. def entry_point(argv):
  647. return someextrafunc()
  648. old_cc = os.environ.get('CC')
  649. try:
  650. os.environ['CC'] = 'gcc -I%s' % dir
  651. t, cbuilder = self.compile(entry_point)
  652. finally:
  653. if old_cc is None:
  654. del os.environ['CC']
  655. else:
  656. os.environ['CC'] = old_cc
  657. def test_inhibit_tail_call(self):
  658. # the point is to check that the f()->f() recursion stops
  659. from pypy.rlib.rstackovf import StackOverflow
  660. def f(n):
  661. if n <= 0:
  662. return 42
  663. return f(n+1)
  664. def entry_point(argv):
  665. try:
  666. return f(1)
  667. except StackOverflow:
  668. print 'hi!'
  669. return 0
  670. t, cbuilder = self.compile(entry_point, stackcheck=True)
  671. out = cbuilder.cmdexec("")
  672. assert out.strip() == "hi!"
  673. def test_set_length_fraction(self):
  674. # check for pypy.rlib.rstack._stack_set_length_fraction()
  675. from pypy.rlib.rstack import _stack_set_length_fraction
  676. from pypy.rlib.rstackovf import StackOverflow
  677. class A:
  678. n = 0
  679. glob = A()
  680. def f(n):
  681. glob.n += 1
  682. if n <= 0:
  683. return 42
  684. return f(n+1)
  685. def entry_point(argv):
  686. _stack_set_length_fraction(0.1)
  687. try:
  688. return f(1)
  689. except StackOverflow:
  690. glob.n = 0
  691. _stack_set_length_fraction(float(argv[1]))
  692. try:
  693. return f(1)
  694. except StackOverflow:
  695. print glob.n
  696. return 0
  697. t, cbuilder = self.compile(entry_point, stackcheck=True)
  698. counts = {}
  699. for fraction in [0.1, 0.4, 1.0]:
  700. out = cbuilder.cmdexec(str(fraction))
  701. print 'counts[%s]: %r' % (fraction, out)
  702. counts[fraction] = int(out.strip())
  703. #
  704. assert counts[1.0] >= 1000
  705. # ^^^ should actually be much more than 1000 for this small test
  706. assert counts[0.1] < counts[0.4] / 3
  707. assert counts[0.4] < counts[1.0] / 2
  708. assert counts[0.1] > counts[0.4] / 7
  709. assert counts[0.4] > counts[1.0] / 4
  710. def test_stack_criticalcode(self):
  711. # check for pypy.rlib.rstack._stack_criticalcode_start/stop()
  712. from pypy.rlib.rstack import _stack_criticalcode_start
  713. from pypy.rlib.rstack import _stack_criticalcode_stop
  714. from pypy.rlib.rstackovf import StackOverflow
  715. class A:
  716. pass
  717. glob = A()
  718. def f(n):
  719. if n <= 0:
  720. return 42
  721. try:
  722. return f(n+1)
  723. except StackOverflow:
  724. if glob.caught:
  725. print 'Oups! already caught!'
  726. glob.caught = True
  727. _stack_criticalcode_start()
  728. critical(100) # recurse another 100 times here
  729. _stack_criticalcode_stop()
  730. return 789
  731. def critical(n):
  732. if n > 0:
  733. n = critical(n - 1)
  734. return n - 42
  735. def entry_point(argv):
  736. glob.caught = False
  737. print f(1)
  738. return 0
  739. t, cbuilder = self.compile(entry_point, stackcheck=True)
  740. out = cbuilder.cmdexec('')
  741. assert out.strip() == '789'
  742. class TestMaemo(TestStandalone):
  743. def setup_class(cls):
  744. py.test.skip("TestMaemo: tests skipped for now")
  745. from pypy.translator.platform.maemo import check_scratchbox
  746. check_scratchbox()
  747. from pypy.config.pypyoption import get_pypy_config
  748. config = get_pypy_config(translating=True)
  749. config.translation.platform = 'maemo'
  750. cls.config = config
  751. def test_profopt(self):
  752. py.test.skip("Unsupported")
  753. def test_prof_inline(self):
  754. py.test.skip("Unsupported")
  755. class TestThread(object):
  756. gcrootfinder = 'shadowstack'
  757. config = None
  758. def compile(self, entry_point):
  759. t = TranslationContext(self.config)
  760. t.config.translation.gc = "semispace"
  761. t.config.translation.gcrootfinder = self.gcrootfinder
  762. t.config.translation.thread = True
  763. t.buildannotator().build_types(entry_point, [s_list_of_strings])
  764. t.buildrtyper().specialize()
  765. #
  766. cbuilder = CStandaloneBuilder(t, entry_point, t.config)
  767. cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES)
  768. cbuilder.compile()
  769. #
  770. return t, cbuilder
  771. def test_stack_size(self):
  772. import time
  773. from pypy.module.thread import ll_thread
  774. from pypy.rpython.lltypesystem import lltype
  775. from pypy.rlib.objectmodel import invoke_around_extcall
  776. class State:
  777. pass
  778. state = State()
  779. def before():
  780. debug_print("releasing...")
  781. ll_assert(not ll_thread.acquire_NOAUTO(state.ll_lock, False),
  782. "lock not held!")
  783. ll_thread.release_NOAUTO(state.ll_lock)
  784. debug_print("released")
  785. def after():
  786. debug_print("waiting...")
  787. ll_thread.acquire_NOAUTO(state.ll_lock, True)
  788. debug_print("acquired")
  789. def recurse(n):
  790. if n > 0:
  791. return recurse(n-1)+1
  792. else:
  793. time.sleep(0.2) # invokes before/after
  794. return 0
  795. # recurse a lot
  796. RECURSION = 19500
  797. if sys.platform == 'win32':
  798. # If I understand it correctly:
  799. # - The stack size "reserved" for a new thread is a compile-time
  800. # option (by default: 1Mb). This is a minimum that user code
  801. # cannot control.
  802. # - set_stacksize() only sets the initially "committed" size,
  803. # which eventually requires a larger "reserved" size.
  804. # - The limit below is large enough to exceed the "reserved" size,
  805. # for small values of set_stacksize().
  806. RECURSION = 150 * 1000
  807. def bootstrap():
  808. recurse(RECURSION)
  809. state.count += 1
  810. def entry_point(argv):
  811. os.write(1, "hello world\n")
  812. error = ll_thread.set_stacksize(int(argv[1]))
  813. if error != 0:
  814. os.write(2, "set_stacksize(%d) returned %d\n" % (
  815. int(argv[1]), error))
  816. raise AssertionError
  817. # malloc a bit
  818. s1 = State(); s2 = State(); s3 = State()
  819. s1.x = 0x11111111; s2.x = 0x22222222; s3.x = 0x33333333
  820. # start 3 new threads
  821. state.ll_lock = ll_thread.allocate_ll_lock()
  822. after()
  823. state.count = 0
  824. invoke_around_extcall(before, after)
  825. ident1 = ll_thread.start_new_thread(bootstrap, ())
  826. ident2 = ll_thread.start_new_thread(bootstrap, ())
  827. ident3 = ll_thread.start_new_thread(bootstrap, ())
  828. # wait for the 3 threads to finish
  829. while True:
  830. if state.count == 3:
  831. break
  832. time.sleep(0.1) # invokes before/after
  833. # check that the malloced structures were not overwritten
  834. assert s1.x == 0x11111111
  835. assert s2.x == 0x22222222
  836. assert s3.x == 0x33333333
  837. os.write(1, "done\n")
  838. return 0
  839. t, cbuilder = self.compile(entry_point)
  840. # recursing should crash with only 32 KB of stack,
  841. # and it should eventually work with more stack
  842. for test_kb in [32, 128, 512, 1024, 2048, 4096, 8192, 16384,
  843. 32768, 65536]:
  844. print >> sys.stderr, 'Trying with %d KB of stack...' % (test_kb,),
  845. try:
  846. data = cbuilder.cmdexec(str(test_kb * 1024))
  847. except Exception, e:
  848. if e.__class__ is not Exception:
  849. raise
  850. print >> sys.stderr, 'segfault'
  851. # got a segfault! try with the next stack size...
  852. else:
  853. # it worked
  854. print >> sys.stderr, 'ok'
  855. assert data == 'hello world\ndone\n'
  856. assert test_kb > 32 # it cannot work with just 32 KB of stack
  857. break # finish
  858. else:
  859. py.test.fail("none of the stack sizes worked")
  860. def test_thread_and_gc(self):
  861. import time, gc
  862. from pypy.module.thread import ll_thread
  863. from pypy.rpython.lltypesystem import lltype
  864. from pypy.rlib.objectmodel import invoke_around_extcall
  865. class State:
  866. pass
  867. state = State()
  868. def before():
  869. ll_assert(not ll_thread.acquire_NOAUTO(state.ll_lock, False),
  870. "lock not held!")
  871. ll_thread.release_NOAUTO(state.ll_lock)
  872. def after():
  873. ll_thread.acquire_NOAUTO(state.ll_lock, True)
  874. ll_thread.gc_thread_run()
  875. class Cons:
  876. def __init__(self, head, tail):
  877. self.head = head
  878. self.tail = tail
  879. def bootstrap():
  880. ll_thread.gc_thread_start()
  881. state.xlist.append(Cons(123, Cons(456, None)))
  882. gc.collect()
  883. ll_thread.gc_thread_die()
  884. def new_thread():
  885. ll_thread.gc_thread_prepare()
  886. ident = ll_thread.start_new_thread(bootstrap, ())
  887. time.sleep(0.5) # enough time to start, hopefully
  888. return ident
  889. def entry_point(argv):
  890. os.write(1, "hello world\n")
  891. state.xlist = []
  892. x2 = Cons(51, Cons(62, Cons(74, None)))
  893. # start 5 new threads
  894. state.ll_lock = ll_thread.allocate_ll_lock()
  895. after()
  896. invoke_around_extcall(before, after)
  897. ident1 = new_thread()
  898. ident2 = new_thread()
  899. #
  900. gc.collect()
  901. #
  902. ident3 = new_thread()
  903. ident4 = new_thread()
  904. ident5 = new_thread()
  905. # wait for the 5 threads to finish
  906. while True:
  907. gc.collect()
  908. if len(state.xlist) == 5:
  909. break
  910. time.sleep(0.1) # invokes before/after
  911. # check that the malloced structures were not overwritten
  912. assert x2.head == 51
  913. assert x2.tail.head == 62
  914. assert x2.tail.tail.head == 74
  915. assert x2.tail.tail.tail is None
  916. # check the structures produced by the threads
  917. for i in range(5):
  918. assert state.xlist[i].head == 123
  919. assert state.xlist[i].tail.head == 456
  920. assert state.xlist[i].tail.tail is None
  921. os.write(1, "%d ok\n" % (i+1))
  922. return 0
  923. t, cbuilder = self.compile(entry_point)
  924. data = cbuilder.cmdexec('')
  925. assert data.splitlines() == ['hello world',
  926. '1 ok',
  927. '2 ok',
  928. '3 ok',
  929. '4 ok',
  930. '5 ok']
  931. def test_gc_with_fork_without_threads(self):
  932. from pypy.rlib.objectmodel import invoke_around_extcall
  933. if not hasattr(os, 'fork'):
  934. py.test.skip("requires fork()")
  935. def entry_point(argv):
  936. childpid = os.fork()
  937. if childpid == 0:
  938. print "Testing..."
  939. else:
  940. pid, status = os.waitpid(childpid, 0)
  941. assert pid == childpid
  942. assert status == 0
  943. print "OK."
  944. return 0
  945. t, cbuilder = self.compile(entry_point)
  946. data = cbuilder.cmdexec('')
  947. print repr(data)
  948. assert data.startswith('Testing...\nOK.')
  949. def test_thread_and_gc_with_fork(self):
  950. # This checks that memory allocated for the shadow stacks of the
  951. # other threads is really released when doing a fork() -- or at
  952. # least that the object referenced from stacks that are no longer
  953. # alive are really freed.
  954. import time, gc, os
  955. from pypy.module.thread import ll_thread
  956. from pypy.rlib.objectmodel import invoke_around_extcall
  957. if not hasattr(os, 'fork'):
  958. py.test.skip("requires fork()")
  959. class State:
  960. pass
  961. state = State()
  962. def before():
  963. ll_assert(not ll_thread.acquire_NOAUTO(state.ll_lock, False),
  964. "lock not held!")
  965. ll_thread.release_NOAUTO(state.ll_lock)
  966. def after():
  967. ll_thread.acquire_NOAUTO(state.ll_lock, True)
  968. ll_thread.gc_thread_run()
  969. class Cons:
  970. def __init__(self, head, tail):
  971. self.head = head
  972. self.tail = tail
  973. class Stuff:
  974. def __del__(self):
  975. os.write(state.write_end, 'd')
  976. def allocate_stuff():
  977. s = Stuff()
  978. os.write(state.write_end, 'a')
  979. return s
  980. def run_in_thread():
  981. for i in range(10):
  982. state.xlist.append(Cons(123, Cons(456, None)))
  983. time.sleep(0.01)
  984. childpid = os.fork()
  985. return childpid
  986. def bootstrap():
  987. ll_thread.gc_thread_start()
  988. childpid = run_in_thread()
  989. gc.collect() # collect both in the child and in the parent
  990. gc.collect()
  991. gc.collect()
  992. if childpid == 0:
  993. os.write(state.write_end, 'c') # "I did not die!" from child
  994. else:
  995. os.write(state.write_end, 'p') # "I did not die!" from parent
  996. ll_thread.gc_thread_die()
  997. def new_thread():
  998. ll_thread.gc_thread_prepare()
  999. ident = ll_thread.start_new_thread(bootstrap, ())
  1000. time.sleep(0.5) # enough time to start, hopefully
  1001. return ident
  1002. def start_all_threads():
  1003. s = allocate_stuff()
  1004. ident1 = new_thread()
  1005. ident2 = new_thread()
  1006. ident3 = new_thread()
  1007. ident4 = new_thread()
  1008. ident5 = new_thread()
  1009. # wait for 4 more seconds, which should be plenty of time
  1010. time.sleep(4)
  1011. keepalive_until_here(s)
  1012. def entry_point(argv):
  1013. os.write(1, "hello world\n")
  1014. state.xlist = []
  1015. state.deleted = 0
  1016. state.read_end, state.write_end = os.pipe()
  1017. x2 = Cons(51, Cons(62, Cons(74, None)))
  1018. # start 5 new threads
  1019. state.ll_lock = ll_thread.allocate_ll_lock()
  1020. after()
  1021. invoke_around_extcall(before, after)
  1022. start_all_threads()
  1023. # force freeing
  1024. gc.collect()
  1025. gc.collect()
  1026. gc.collect()
  1027. # return everything that was written to the pipe so far,
  1028. # followed by the final dot.
  1029. os.write(state.write_end, '.')
  1030. result = os.read(state.read_end, 256)
  1031. os.write(1, "got: %s\n" % result)
  1032. return 0
  1033. t, cbuilder = self.compile(entry_point)
  1034. data = cbuilder.cmdexec('')
  1035. print repr(data)
  1036. header, footer = data.splitlines()
  1037. assert header == 'hello world'
  1038. assert footer.startswith('got: ')
  1039. result = footer[5:]
  1040. # check that all 5 threads and 5 forked processes
  1041. # finished successfully, that we did 1 allocation,
  1042. # and that it was freed 6 times -- once in the parent
  1043. # process and once in every child process.
  1044. assert (result[-1] == '.'
  1045. and result.count('c') == result.count('p') == 5
  1046. and result.count('a') == 1
  1047. and result.count('d') == 6)