test_lltrace.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import dis
  2. import sys
  3. import textwrap
  4. import unittest
  5. from test.support import os_helper, verbose
  6. from test.support.script_helper import assert_python_ok
  7. def example():
  8. x = []
  9. for i in range(1):
  10. x.append(i)
  11. x = "this is"
  12. y = "an example"
  13. print(x, y)
  14. Py_DEBUG = hasattr(sys, 'gettotalrefcount')
  15. @unittest.skipUnless(Py_DEBUG, "lltrace requires Py_DEBUG")
  16. class TestLLTrace(unittest.TestCase):
  17. def run_code(self, code):
  18. code = textwrap.dedent(code).strip()
  19. with open(os_helper.TESTFN, 'w', encoding='utf-8') as fd:
  20. self.addCleanup(os_helper.unlink, os_helper.TESTFN)
  21. fd.write(code)
  22. status, stdout, stderr = assert_python_ok(os_helper.TESTFN)
  23. self.assertEqual(stderr, b"")
  24. self.assertEqual(status, 0)
  25. result = stdout.decode('utf-8')
  26. if verbose:
  27. print("\n\n--- code ---")
  28. print(code)
  29. print("\n--- stdout ---")
  30. print(result)
  31. print()
  32. return result
  33. def test_lltrace(self):
  34. stdout = self.run_code("""
  35. def dont_trace_1():
  36. a = "a"
  37. a = 10 * a
  38. def trace_me():
  39. for i in range(3):
  40. +i
  41. def dont_trace_2():
  42. x = 42
  43. y = -x
  44. dont_trace_1()
  45. __lltrace__ = 1
  46. trace_me()
  47. del __lltrace__
  48. dont_trace_2()
  49. """)
  50. self.assertIn("GET_ITER", stdout)
  51. self.assertIn("FOR_ITER", stdout)
  52. self.assertIn("UNARY_POSITIVE", stdout)
  53. self.assertIn("POP_TOP", stdout)
  54. self.assertNotIn("BINARY_OP", stdout)
  55. self.assertNotIn("UNARY_NEGATIVE", stdout)
  56. self.assertIn("'trace_me' in module '__main__'", stdout)
  57. self.assertNotIn("dont_trace_1", stdout)
  58. self.assertNotIn("'dont_trace_2' in module", stdout)
  59. def test_lltrace_different_module(self):
  60. stdout = self.run_code("""
  61. from test import test_lltrace
  62. test_lltrace.__lltrace__ = 1
  63. test_lltrace.example()
  64. """)
  65. self.assertIn("'example' in module 'test.test_lltrace'", stdout)
  66. self.assertIn('LOAD_CONST', stdout)
  67. self.assertIn('FOR_ITER', stdout)
  68. self.assertIn('this is an example', stdout)
  69. # check that offsets match the output of dis.dis()
  70. instr_map = {i.offset: i for i in dis.get_instructions(example)}
  71. for line in stdout.splitlines():
  72. offset, colon, opname_oparg = line.partition(":")
  73. if not colon:
  74. continue
  75. offset = int(offset)
  76. opname_oparg = opname_oparg.split()
  77. if len(opname_oparg) == 2:
  78. opname, oparg = opname_oparg
  79. oparg = int(oparg)
  80. else:
  81. (opname,) = opname_oparg
  82. oparg = None
  83. self.assertEqual(instr_map[offset].opname, opname)
  84. self.assertEqual(instr_map[offset].arg, oparg)
  85. def test_lltrace_does_not_crash_on_subscript_operator(self):
  86. # If this test fails, it will reproduce a crash reported as
  87. # bpo-34113. The crash happened at the command line console of
  88. # debug Python builds with __lltrace__ enabled (only possible in console),
  89. # when the internal Python stack was negatively adjusted
  90. stdout = self.run_code("""
  91. import code
  92. console = code.InteractiveConsole()
  93. console.push('__lltrace__ = 1')
  94. console.push('a = [1, 2, 3]')
  95. console.push('a[0] = 1')
  96. print('unreachable if bug exists')
  97. """)
  98. self.assertIn("unreachable if bug exists", stdout)
  99. if __name__ == "__main__":
  100. unittest.main()