[lldb][test] Skip TestRerunAndExprDylib on Ubuntu 18.04
[llvm-project.git] / lldb / test / API / functionalities / rerun_and_expr_dylib / TestRerunAndExprDylib.py
blob1a6944e6fd9bb7f736a2379565643607f1e9db25
1 """
2 Test that re-running a process from within the same target
3 after rebuilding the a dynamic library flushes the scratch
4 TypeSystems tied to that process.
5 """
7 import lldb
8 from lldbsuite.test.lldbtest import *
9 from lldbsuite.test import lldbutil
10 from lldbsuite.test.decorators import *
13 def isUbuntu18_04():
14 """
15 Check if the host OS is Ubuntu 18.04.
16 Derived from `platform.freedesktop_os_release` in Python 3.10.
17 """
18 for path in ("/etc/os-release", "/usr/lib/os-release"):
19 if os.path.exists(path):
20 with open(path) as f:
21 contents = f.read()
22 if "Ubuntu 18.04" in contents:
23 return True
25 return False
28 class TestRerunExprDylib(TestBase):
29 @skipTestIfFn(isUbuntu18_04, bugnumber="rdar://103831050")
30 @skipIfWindows
31 def test(self):
32 """
33 Tests whether re-launching a process without destroying
34 the owning target keeps invalid ASTContexts in the
35 scratch AST's importer.
37 We test this by:
38 1. Evaluating an expression to import 'struct Foo' into
39 the scratch AST
40 2. Change the definition of 'struct Foo' and rebuild the dylib
41 3. Re-launch the process
42 4. Evaluate the same expression in (1). We expect to have only
43 the latest definition of 'struct Foo' in the scratch AST.
44 """
46 DYLIB_NAME = 'foo'
47 FULL_DYLIB_NAME = 'libfoo.dylib' if self.platformIsDarwin() else 'libfoo.so'
49 # Build libfoo.dylib
50 self.build(dictionary={'DYLIB_CXX_SOURCES':'lib.cpp',
51 'DYLIB_ONLY':'YES',
52 'DYLIB_NAME':DYLIB_NAME,
53 'USE_LIBDL':'1',
54 'LD_EXTRAS':'-L.'})
56 # Build a.out
57 self.build(dictionary={'EXE':'a.out',
58 'CXX_SOURCES':'main.cpp',
59 'USE_LIBDL':'1',
60 'CXXFLAGS_EXTRAS':f'-DLIB_NAME=\\"{FULL_DYLIB_NAME}\\"',
61 'LD_EXTRAS':'-L.'})
63 exe = self.getBuildArtifact("a.out")
64 target = self.dbg.CreateTarget(exe)
65 target.BreakpointCreateBySourceRegex('dlclose', lldb.SBFileSpec('main.cpp'))
66 target.BreakpointCreateBySourceRegex('return', lldb.SBFileSpec('main.cpp'))
67 process = target.LaunchSimple(None, None, self.get_process_working_directory())
69 self.expect_expr('*foo', result_type='Foo', result_children=[
70 ValueCheck(name='m_val', value='42')
73 # Delete the dylib to force make to rebuild it.
74 remove_file(self.getBuildArtifact(FULL_DYLIB_NAME))
76 # Re-build libfoo.dylib
77 self.build(dictionary={'DYLIB_CXX_SOURCES':'rebuild.cpp',
78 'DYLIB_ONLY':'YES',
79 'DYLIB_NAME':DYLIB_NAME,
80 'USE_LIBDL':'1',
81 'LD_EXTRAS':'-L.'})
83 # Rerun program within the same target
84 process.Continue()
85 process.Destroy()
86 process = target.LaunchSimple(None, None, self.get_process_working_directory())
88 self.expect_expr('*foo', result_type='Foo', result_children=[
89 ValueCheck(name='Base', children=[
90 ValueCheck(name='m_base_val', value='42')
91 ]),
92 ValueCheck(name='m_derived_val', value='137')
95 self.filecheck("target module dump ast", __file__)
97 # The new definition 'struct Foo' is in the scratch AST
98 # CHECK: |-CXXRecordDecl {{.*}} struct Foo definition
99 # CHECK: | |-public 'Base'
100 # CHECK-NEXT: | `-FieldDecl {{.*}} m_derived_val 'int'
101 # CHECK-NEXT: `-CXXRecordDecl {{.*}} struct Base definition
102 # CHECK: `-FieldDecl {{.*}} m_base_val 'int'
104 # ...but the original definition of 'struct Foo' is not in the scratch AST anymore
105 # CHECK-NOT: FieldDecl {{.*}} m_val 'int'