Skip to content

Commit 87f45cc

Browse files
[LLDB][swift] Add test demonstrating failed async variable inspection
1 parent bffca2b commit 87f45cc

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
SWIFTFLAGS_EXTRAS := -parse-as-library
3+
include Makefile.rules
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
import lldbsuite.test.lldbtest as lldbtest
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
7+
class TestCase(lldbtest.TestBase):
8+
9+
mydir = lldbtest.TestBase.compute_mydir(__file__)
10+
11+
# Check that the CFA chain is correctly built
12+
def check_cfas(self, async_frames, process):
13+
async_cfas = list(map(lambda frame: frame.GetCFA(), async_frames))
14+
expected_cfas = [async_cfas[0]]
15+
# The CFA chain ends in nullptr.
16+
while expected_cfas[-1] != 0:
17+
error = lldb.SBError()
18+
expected_cfas.append(
19+
process.ReadPointerFromMemory(expected_cfas[-1], error)
20+
)
21+
self.assertSuccess(error, "Managed to read cfa memory")
22+
23+
self.assertEqual(async_cfas, expected_cfas[:-1])
24+
25+
def check_pcs(self, async_frames, process, target):
26+
for idx, frame in enumerate(async_frames[:-1]):
27+
# Read the continuation pointer from the second field of the CFA.
28+
error = lldb.SBError()
29+
continuation_ptr = process.ReadPointerFromMemory(
30+
frame.GetCFA() + target.addr_size, error
31+
)
32+
self.assertSuccess(error, "Managed to read context memory")
33+
34+
# The PC of the previous frame should be the continuation pointer
35+
# with the funclet's prologue skipped.
36+
parent_frame = async_frames[idx + 1]
37+
prologue_to_skip = parent_frame.GetFunction().GetPrologueByteSize()
38+
self.assertEqual(continuation_ptr + prologue_to_skip, parent_frame.GetPC())
39+
40+
41+
def check_variables(self, async_frames, expected_values):
42+
for (frame, expected_value) in zip(async_frames, expected_values):
43+
myvar = frame.FindVariable("myvar")
44+
lldbutil.check_variable(self, myvar, False, value=expected_value)
45+
46+
@swiftTest
47+
@skipIf(oslist=["windows", "linux", "macos"])
48+
def test(self):
49+
"""Test `frame variable` in async functions"""
50+
self.build()
51+
52+
source_file = lldb.SBFileSpec("main.swift")
53+
target, process, _, _ = lldbutil.run_to_source_breakpoint(
54+
self, "breakpoint1", source_file
55+
)
56+
57+
async_frames = process.GetSelectedThread().frames
58+
self.check_cfas(async_frames, process)
59+
self.check_pcs(async_frames, process, target)
60+
self.check_variables(async_frames, ["222", "333", "444", "555"])
61+
62+
target.DeleteAllBreakpoints()
63+
target.BreakpointCreateBySourceRegex("breakpoint2", source_file)
64+
process.Continue()
65+
# First frame is from a synchronous function
66+
frames = process.GetSelectedThread().frames
67+
async_frames = frames[1:]
68+
self.check_cfas(async_frames, process)
69+
self.check_pcs(async_frames, process, target)
70+
self.check_variables(async_frames, ["111", "222", "333", "444", "555"])
71+
72+
target.DeleteAllBreakpoints()
73+
target.BreakpointCreateBySourceRegex("breakpoint3", source_file)
74+
process.Continue()
75+
async_frames = process.GetSelectedThread().frames
76+
self.check_cfas(async_frames, process)
77+
self.check_pcs(async_frames, process, target)
78+
self.check_variables(async_frames, ["222", "333", "444", "555"])
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
func work() {
2+
print("working") // breakpoint2
3+
}
4+
5+
func ASYNC___1___() async -> Int {
6+
var myvar = 111;
7+
work()
8+
myvar += 1;
9+
return myvar
10+
}
11+
12+
func ASYNC___2___() async -> Int {
13+
var myvar = 222;
14+
let result = await ASYNC___1___() //breakpoint1
15+
work() // breakpoint3
16+
myvar += result;
17+
return myvar
18+
}
19+
20+
func ASYNC___3___() async -> Int {
21+
var myvar = 333;
22+
let result = await ASYNC___2___()
23+
work()
24+
myvar += result
25+
return myvar
26+
}
27+
28+
func ASYNC___4___() async -> Int {
29+
var myvar = 444;
30+
let result = await ASYNC___3___()
31+
work()
32+
myvar += result
33+
return myvar
34+
}
35+
36+
func ASYNC___5___() async -> Int {
37+
var myvar = 555;
38+
let result = await ASYNC___4___()
39+
work()
40+
myvar += result
41+
return myvar
42+
}
43+
44+
@main struct Main {
45+
static func main() async {
46+
let result = await ASYNC___5___()
47+
print(result)
48+
}
49+
}

0 commit comments

Comments
 (0)