Skip to content

Commit 9b4111f

Browse files
Copilotignoramous
andcommitted
Add comprehensive test coverage for WaitGroup fix
Co-authored-by: ignoramous <[email protected]>
1 parent b75e62f commit 9b4111f

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

intra/netstack/waitgroup_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,78 @@ func TestWaitGroupRaceCondition(t *testing.T) {
9696
}
9797
}
9898

99+
// TestStackTraceScenario tests the specific scenario from the original stack trace
100+
// where magiclink.Wait() is called during endpoint swapping.
101+
func TestStackTraceScenario(t *testing.T) {
102+
// Create a temp file to simulate a TUN device
103+
tmpFile, err := os.CreateTemp("", "test_tun")
104+
if err != nil {
105+
t.Skip("Cannot create temp file for test")
106+
}
107+
defer os.Remove(tmpFile.Name())
108+
defer tmpFile.Close()
109+
110+
fd := int(tmpFile.Fd())
111+
112+
// Create a magiclink endpoint
113+
endpoint, err := NewEndpoint(fd, 1500, &testSink{})
114+
if err != nil {
115+
t.Fatalf("Failed to create endpoint: %v", err)
116+
}
117+
defer endpoint.Dispose()
118+
119+
magicLink, ok := endpoint.(*magiclink)
120+
if !ok {
121+
t.Fatalf("Expected magiclink, got %T", endpoint)
122+
}
123+
124+
// Simulate the exact scenario from the stack trace:
125+
// seamless.go:312>fdbased.go:413 - magiclink.Wait() calls endpoint.Wait()
126+
panicked := false
127+
done := make(chan struct{})
128+
129+
// Start a goroutine that continuously calls Wait() like the tunnel waiter
130+
go func() {
131+
defer func() {
132+
if r := recover(); r != nil {
133+
panicked = true
134+
}
135+
close(done)
136+
}()
137+
138+
for i := 0; i < 100; i++ {
139+
magicLink.Wait()
140+
time.Sleep(time.Millisecond)
141+
}
142+
}()
143+
144+
// Concurrently perform rapid endpoint swaps
145+
for i := 0; i < 10; i++ {
146+
tmpFile2, err := os.CreateTemp("", "test_tun2")
147+
if err != nil {
148+
continue
149+
}
150+
fd2 := int(tmpFile2.Fd())
151+
152+
// Rapid swap - this should not cause WaitGroup reuse panic
153+
magicLink.Swap(fd2, 1500)
154+
155+
tmpFile2.Close()
156+
os.Remove(tmpFile2.Name())
157+
time.Sleep(time.Millisecond * 2)
158+
}
159+
160+
// Wait for the wait goroutine to complete
161+
select {
162+
case <-done:
163+
if panicked {
164+
t.Fatal("WaitGroup reuse panic occurred in stack trace scenario")
165+
}
166+
case <-time.After(time.Second * 15):
167+
t.Fatal("Test timed out")
168+
}
169+
}
170+
99171
// testSink is a simple implementation of io.WriteCloser for testing
100172
type testSink struct{}
101173

0 commit comments

Comments
 (0)