PageRenderTime 37ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/translator/sandbox/test/test_sandbox.py

https://bitbucket.org/pypy/pypy/
Python | 354 lines | 345 code | 9 blank | 0 comment | 5 complexity | 1447dba6e3f98bdcc5ac471f5dd55696 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. import sys, os, time
  3. import struct
  4. import subprocess
  5. import signal
  6. from rpython.rtyper.lltypesystem import rffi
  7. from rpython.translator.interactive import Translation
  8. from rpython.translator.sandbox.sandlib import read_message, write_message
  9. from rpython.translator.sandbox.sandlib import write_exception
  10. if hasattr(signal, 'alarm'):
  11. _orig_read_message = read_message
  12. def _timed_out(*args):
  13. raise EOFError("timed out waiting for data")
  14. def read_message(f):
  15. signal.signal(signal.SIGALRM, _timed_out)
  16. signal.alarm(20)
  17. try:
  18. return _orig_read_message(f)
  19. finally:
  20. signal.alarm(0)
  21. signal.signal(signal.SIGALRM, signal.SIG_DFL)
  22. def expect(f, g, fnname, args, result, resulttype=None):
  23. msg = read_message(f)
  24. assert msg == fnname
  25. msg = read_message(f)
  26. assert msg == args
  27. if isinstance(result, Exception):
  28. write_exception(g, result)
  29. else:
  30. write_message(g, 0)
  31. write_message(g, result, resulttype)
  32. g.flush()
  33. def compile(f, gc='ref'):
  34. t = Translation(f, backend='c', sandbox=True, gc=gc,
  35. check_str_without_nul=True)
  36. return str(t.compile())
  37. def run_in_subprocess(exe):
  38. popen = subprocess.Popen(exe, stdin=subprocess.PIPE,
  39. stdout=subprocess.PIPE,
  40. stderr=subprocess.STDOUT)
  41. return popen.stdin, popen.stdout
  42. def test_open_dup():
  43. def entry_point(argv):
  44. fd = os.open("/tmp/foobar", os.O_RDONLY, 0777)
  45. assert fd == 77
  46. fd2 = os.dup(fd)
  47. assert fd2 == 78
  48. return 0
  49. exe = compile(entry_point)
  50. g, f = run_in_subprocess(exe)
  51. expect(f, g, "ll_os.ll_os_open", ("/tmp/foobar", os.O_RDONLY, 0777), 77)
  52. expect(f, g, "ll_os.ll_os_dup", (77,), 78)
  53. g.close()
  54. tail = f.read()
  55. f.close()
  56. assert tail == ""
  57. def test_read_write():
  58. def entry_point(argv):
  59. fd = os.open("/tmp/foobar", os.O_RDONLY, 0777)
  60. assert fd == 77
  61. res = os.read(fd, 123)
  62. assert res == "he\x00llo"
  63. count = os.write(fd, "world\x00!\x00")
  64. assert count == 42
  65. os.close(fd)
  66. return 0
  67. exe = compile(entry_point)
  68. g, f = run_in_subprocess(exe)
  69. expect(f, g, "ll_os.ll_os_open", ("/tmp/foobar", os.O_RDONLY, 0777), 77)
  70. expect(f, g, "ll_os.ll_os_read", (77, 123), "he\x00llo")
  71. expect(f, g, "ll_os.ll_os_write", (77, "world\x00!\x00"), 42)
  72. expect(f, g, "ll_os.ll_os_close", (77,), None)
  73. g.close()
  74. tail = f.read()
  75. f.close()
  76. assert tail == ""
  77. def test_dup2_access():
  78. def entry_point(argv):
  79. os.dup2(34, 56)
  80. y = os.access("spam", 77)
  81. return 1 - y
  82. exe = compile(entry_point)
  83. g, f = run_in_subprocess(exe)
  84. expect(f, g, "ll_os.ll_os_dup2", (34, 56), None)
  85. expect(f, g, "ll_os.ll_os_access", ("spam", 77), True)
  86. g.close()
  87. tail = f.read()
  88. f.close()
  89. assert tail == ""
  90. def test_stat_ftruncate():
  91. from rpython.translator.sandbox.sandlib import RESULTTYPE_STATRESULT
  92. from rpython.rlib.rarithmetic import r_longlong
  93. r0x12380000007 = r_longlong(0x12380000007)
  94. if not hasattr(os, 'ftruncate'):
  95. py.test.skip("posix only")
  96. def entry_point(argv):
  97. st = os.stat("somewhere")
  98. os.ftruncate(st.st_mode, st.st_size) # nonsense, just to see outside
  99. return 0
  100. exe = compile(entry_point)
  101. g, f = run_in_subprocess(exe)
  102. st = os.stat_result((55, 0, 0, 0, 0, 0, 0x12380000007, 0, 0, 0))
  103. expect(f, g, "ll_os.ll_os_stat", ("somewhere",), st,
  104. resulttype = RESULTTYPE_STATRESULT)
  105. expect(f, g, "ll_os.ll_os_ftruncate", (55, 0x12380000007), None)
  106. g.close()
  107. tail = f.read()
  108. f.close()
  109. assert tail == ""
  110. def test_time():
  111. def entry_point(argv):
  112. t = time.time()
  113. os.dup(int(t*1000))
  114. return 0
  115. exe = compile(entry_point)
  116. g, f = run_in_subprocess(exe)
  117. expect(f, g, "ll_time.ll_time_time", (), 3.141592)
  118. expect(f, g, "ll_os.ll_os_dup", (3141,), 3)
  119. g.close()
  120. tail = f.read()
  121. f.close()
  122. assert tail == ""
  123. def test_getcwd():
  124. def entry_point(argv):
  125. t = os.getcwd()
  126. os.dup(len(t))
  127. return 0
  128. exe = compile(entry_point)
  129. g, f = run_in_subprocess(exe)
  130. expect(f, g, "ll_os.ll_os_getcwd", (), "/tmp/foo/bar")
  131. expect(f, g, "ll_os.ll_os_dup", (len("/tmp/foo/bar"),), 3)
  132. g.close()
  133. tail = f.read()
  134. f.close()
  135. assert tail == ""
  136. def test_oserror():
  137. def entry_point(argv):
  138. try:
  139. os.stat("somewhere")
  140. except OSError as e:
  141. os.close(e.errno) # nonsense, just to see outside
  142. return 0
  143. exe = compile(entry_point)
  144. g, f = run_in_subprocess(exe)
  145. expect(f, g, "ll_os.ll_os_stat", ("somewhere",), OSError(6321, "egg"))
  146. expect(f, g, "ll_os.ll_os_close", (6321,), None)
  147. g.close()
  148. tail = f.read()
  149. f.close()
  150. assert tail == ""
  151. def test_hybrid_gc():
  152. def entry_point(argv):
  153. l = []
  154. for i in range(int(argv[1])):
  155. l.append("x" * int(argv[2]))
  156. return int(len(l) > 1000)
  157. exe = compile(entry_point, gc='hybrid')
  158. pipe = subprocess.Popen([exe, '10', '10000'], stdout=subprocess.PIPE,
  159. stdin=subprocess.PIPE)
  160. g = pipe.stdin
  161. f = pipe.stdout
  162. expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GENERATIONGC_NURSERY",), None)
  163. #if sys.platform.startswith('linux'):
  164. # expect(f, g, "ll_os.ll_os_open", ("/proc/cpuinfo", 0, 420),
  165. # OSError(5232, "xyz"))
  166. expect(f, g, "ll_os.ll_os_getenv", ("PYPY_GC_DEBUG",), None)
  167. g.close()
  168. tail = f.read()
  169. f.close()
  170. assert tail == ""
  171. rescode = pipe.wait()
  172. assert rescode == 0
  173. def test_segfault_1():
  174. class A:
  175. def __init__(self, m):
  176. self.m = m
  177. def g(m):
  178. if m < 10:
  179. return None
  180. return A(m)
  181. def entry_point(argv):
  182. x = g(len(argv))
  183. return int(x.m)
  184. exe = compile(entry_point)
  185. g, f = run_in_subprocess(exe)
  186. g.close()
  187. tail = f.read()
  188. f.close()
  189. assert 'Invalid RPython operation' in tail
  190. def test_segfault_2():
  191. py.test.skip("hum, this is one example, but we need to be very careful")
  192. class Base:
  193. pass
  194. class A(Base):
  195. def __init__(self, m):
  196. self.m = m
  197. def getm(self):
  198. return self.m
  199. class B(Base):
  200. def __init__(self, a):
  201. self.a = a
  202. def g(m):
  203. a = A(m)
  204. if m < 10:
  205. a = B(a)
  206. return a
  207. def entry_point(argv):
  208. x = g(len(argv))
  209. os.write(2, str(x.getm()))
  210. return 0
  211. exe = compile(entry_point)
  212. g, f, e = os.popen3(exe, "t", 0)
  213. g.close()
  214. tail = f.read(23)
  215. f.close()
  216. assert tail == "" # and not ll_os.ll_os_write
  217. errors = e.read()
  218. e.close()
  219. assert '...think what kind of errors to get...' in errors
  220. def test_safe_alloc():
  221. from rpython.rlib.rmmap import alloc, free
  222. def entry_point(argv):
  223. one = alloc(1024)
  224. free(one, 1024)
  225. return 0
  226. exe = compile(entry_point)
  227. pipe = subprocess.Popen([exe], stdout=subprocess.PIPE,
  228. stdin=subprocess.PIPE)
  229. g = pipe.stdin
  230. f = pipe.stdout
  231. g.close()
  232. tail = f.read()
  233. f.close()
  234. assert tail == ""
  235. rescode = pipe.wait()
  236. assert rescode == 0
  237. def test_unsafe_mmap():
  238. py.test.skip("Since this stuff is unimplemented, it won't work anyway "
  239. "however, the day it starts working, it should pass test")
  240. from rpython.rlib.rmmap import mmap
  241. def entry_point(argv):
  242. try:
  243. res = mmap(0, 1024)
  244. except OSError:
  245. return 0
  246. return 1
  247. exe = compile(entry_point)
  248. pipe = subprocess.Popen([exe], stdout=subprocess.PIPE,
  249. stdin=subprocess.PIPE)
  250. g = pipe.stdin
  251. f = pipe.stdout
  252. expect(f, g, "mmap", ARGS, OSError(1, "xyz"))
  253. g.close()
  254. tail = f.read()
  255. f.close()
  256. assert tail == ""
  257. rescode = pipe.wait()
  258. assert rescode == 0
  259. def test_environ_items():
  260. def entry_point(argv):
  261. print os.environ.items()
  262. return 0
  263. exe = compile(entry_point)
  264. g, f = run_in_subprocess(exe)
  265. expect(f, g, "ll_os.ll_os_envitems", (), [])
  266. expect(f, g, "ll_os.ll_os_write", (1, "[]\n"), 3)
  267. g.close()
  268. tail = f.read()
  269. f.close()
  270. assert tail == ""
  271. class TestPrintedResults:
  272. def run(self, entry_point, args, expected):
  273. exe = compile(entry_point)
  274. from rpython.translator.sandbox.sandlib import SimpleIOSandboxedProc
  275. proc = SimpleIOSandboxedProc([exe] + args)
  276. output, error = proc.communicate()
  277. assert error == ''
  278. assert output == expected
  279. def test_safefuncs(self):
  280. import math
  281. def entry_point(argv):
  282. a = float(argv[1])
  283. print int(math.floor(a - 0.2)),
  284. print int(math.ceil(a)),
  285. print int(100.0 * math.sin(a)),
  286. mantissa, exponent = math.frexp(a)
  287. print int(100.0 * mantissa), exponent,
  288. fracpart, intpart = math.modf(a)
  289. print int(100.0 * fracpart), int(intpart),
  290. print
  291. return 0
  292. self.run(entry_point, ["3.011"], "2 4 13 75 2 1 3\n")
  293. def test_safefuncs_exception(self):
  294. import math
  295. def entry_point(argv):
  296. a = float(argv[1])
  297. x = math.log(a)
  298. print int(x * 100.0)
  299. try:
  300. math.log(-a)
  301. except ValueError:
  302. print 'as expected, got a ValueError'
  303. else:
  304. print 'did not get a ValueError!'
  305. return 0
  306. self.run(entry_point, ["3.011"], "110\nas expected, got a ValueError\n")
  307. def test_os_path_safe(self):
  308. def entry_point(argv):
  309. print os.path.join('tmp', argv[1])
  310. return 0
  311. self.run(entry_point, ["spam"], os.path.join("tmp", "spam")+'\n')