17db96d56Sopenharmony_ciimport dis 27db96d56Sopenharmony_ciimport sys 37db96d56Sopenharmony_ciimport textwrap 47db96d56Sopenharmony_ciimport unittest 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_cifrom test.support import os_helper, verbose 77db96d56Sopenharmony_cifrom test.support.script_helper import assert_python_ok 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_cidef example(): 107db96d56Sopenharmony_ci x = [] 117db96d56Sopenharmony_ci for i in range(1): 127db96d56Sopenharmony_ci x.append(i) 137db96d56Sopenharmony_ci x = "this is" 147db96d56Sopenharmony_ci y = "an example" 157db96d56Sopenharmony_ci print(x, y) 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciPy_DEBUG = hasattr(sys, 'gettotalrefcount') 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ci@unittest.skipUnless(Py_DEBUG, "lltrace requires Py_DEBUG") 207db96d56Sopenharmony_ciclass TestLLTrace(unittest.TestCase): 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_ci def run_code(self, code): 237db96d56Sopenharmony_ci code = textwrap.dedent(code).strip() 247db96d56Sopenharmony_ci with open(os_helper.TESTFN, 'w', encoding='utf-8') as fd: 257db96d56Sopenharmony_ci self.addCleanup(os_helper.unlink, os_helper.TESTFN) 267db96d56Sopenharmony_ci fd.write(code) 277db96d56Sopenharmony_ci status, stdout, stderr = assert_python_ok(os_helper.TESTFN) 287db96d56Sopenharmony_ci self.assertEqual(stderr, b"") 297db96d56Sopenharmony_ci self.assertEqual(status, 0) 307db96d56Sopenharmony_ci result = stdout.decode('utf-8') 317db96d56Sopenharmony_ci if verbose: 327db96d56Sopenharmony_ci print("\n\n--- code ---") 337db96d56Sopenharmony_ci print(code) 347db96d56Sopenharmony_ci print("\n--- stdout ---") 357db96d56Sopenharmony_ci print(result) 367db96d56Sopenharmony_ci print() 377db96d56Sopenharmony_ci return result 387db96d56Sopenharmony_ci 397db96d56Sopenharmony_ci def test_lltrace(self): 407db96d56Sopenharmony_ci stdout = self.run_code(""" 417db96d56Sopenharmony_ci def dont_trace_1(): 427db96d56Sopenharmony_ci a = "a" 437db96d56Sopenharmony_ci a = 10 * a 447db96d56Sopenharmony_ci def trace_me(): 457db96d56Sopenharmony_ci for i in range(3): 467db96d56Sopenharmony_ci +i 477db96d56Sopenharmony_ci def dont_trace_2(): 487db96d56Sopenharmony_ci x = 42 497db96d56Sopenharmony_ci y = -x 507db96d56Sopenharmony_ci dont_trace_1() 517db96d56Sopenharmony_ci __lltrace__ = 1 527db96d56Sopenharmony_ci trace_me() 537db96d56Sopenharmony_ci del __lltrace__ 547db96d56Sopenharmony_ci dont_trace_2() 557db96d56Sopenharmony_ci """) 567db96d56Sopenharmony_ci self.assertIn("GET_ITER", stdout) 577db96d56Sopenharmony_ci self.assertIn("FOR_ITER", stdout) 587db96d56Sopenharmony_ci self.assertIn("UNARY_POSITIVE", stdout) 597db96d56Sopenharmony_ci self.assertIn("POP_TOP", stdout) 607db96d56Sopenharmony_ci self.assertNotIn("BINARY_OP", stdout) 617db96d56Sopenharmony_ci self.assertNotIn("UNARY_NEGATIVE", stdout) 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci self.assertIn("'trace_me' in module '__main__'", stdout) 647db96d56Sopenharmony_ci self.assertNotIn("dont_trace_1", stdout) 657db96d56Sopenharmony_ci self.assertNotIn("'dont_trace_2' in module", stdout) 667db96d56Sopenharmony_ci 677db96d56Sopenharmony_ci def test_lltrace_different_module(self): 687db96d56Sopenharmony_ci stdout = self.run_code(""" 697db96d56Sopenharmony_ci from test import test_lltrace 707db96d56Sopenharmony_ci test_lltrace.__lltrace__ = 1 717db96d56Sopenharmony_ci test_lltrace.example() 727db96d56Sopenharmony_ci """) 737db96d56Sopenharmony_ci self.assertIn("'example' in module 'test.test_lltrace'", stdout) 747db96d56Sopenharmony_ci self.assertIn('LOAD_CONST', stdout) 757db96d56Sopenharmony_ci self.assertIn('FOR_ITER', stdout) 767db96d56Sopenharmony_ci self.assertIn('this is an example', stdout) 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci # check that offsets match the output of dis.dis() 797db96d56Sopenharmony_ci instr_map = {i.offset: i for i in dis.get_instructions(example)} 807db96d56Sopenharmony_ci for line in stdout.splitlines(): 817db96d56Sopenharmony_ci offset, colon, opname_oparg = line.partition(":") 827db96d56Sopenharmony_ci if not colon: 837db96d56Sopenharmony_ci continue 847db96d56Sopenharmony_ci offset = int(offset) 857db96d56Sopenharmony_ci opname_oparg = opname_oparg.split() 867db96d56Sopenharmony_ci if len(opname_oparg) == 2: 877db96d56Sopenharmony_ci opname, oparg = opname_oparg 887db96d56Sopenharmony_ci oparg = int(oparg) 897db96d56Sopenharmony_ci else: 907db96d56Sopenharmony_ci (opname,) = opname_oparg 917db96d56Sopenharmony_ci oparg = None 927db96d56Sopenharmony_ci self.assertEqual(instr_map[offset].opname, opname) 937db96d56Sopenharmony_ci self.assertEqual(instr_map[offset].arg, oparg) 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci def test_lltrace_does_not_crash_on_subscript_operator(self): 967db96d56Sopenharmony_ci # If this test fails, it will reproduce a crash reported as 977db96d56Sopenharmony_ci # bpo-34113. The crash happened at the command line console of 987db96d56Sopenharmony_ci # debug Python builds with __lltrace__ enabled (only possible in console), 997db96d56Sopenharmony_ci # when the internal Python stack was negatively adjusted 1007db96d56Sopenharmony_ci stdout = self.run_code(""" 1017db96d56Sopenharmony_ci import code 1027db96d56Sopenharmony_ci 1037db96d56Sopenharmony_ci console = code.InteractiveConsole() 1047db96d56Sopenharmony_ci console.push('__lltrace__ = 1') 1057db96d56Sopenharmony_ci console.push('a = [1, 2, 3]') 1067db96d56Sopenharmony_ci console.push('a[0] = 1') 1077db96d56Sopenharmony_ci print('unreachable if bug exists') 1087db96d56Sopenharmony_ci """) 1097db96d56Sopenharmony_ci self.assertIn("unreachable if bug exists", stdout) 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ciif __name__ == "__main__": 1127db96d56Sopenharmony_ci unittest.main() 113