pico

created pr with 92.1 on 2025-12-16T04:16:16Z · by c8ef7d19
cmds
checkout latest patchset:
ssh pr.pico.sh print 92 | git am -3
checkout any patchset in a patch request:
ssh pr.pico.sh print 92.[rev] | git am -3
add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 92

Patchset 92.1 on 2025-12-16T04:16:16Z · commit 32424cd

fix: tunkit memory leaks
Eric Bower 2025-12-16T04:13:11Z
- Context leak: Added defer cancel() immediately after creating the context to ensure it's always cancelled when the function returns
- Goroutine coordination: Removed the outer goroutine wrapper - the handler now runs synchronously, waiting for io.Copy goroutines to complete via wg.Wait() before calling handler.Close()
- Simplified cleanup: Moved connection closing to after wg.Wait() to ensure both copy operations complete before closing resources
- Removed dead code: The <-ctx.Done() was waiting forever since nothing called cancel() - now the function naturally completes when the io.Copy operations finish (when either side closes the connection)
Semantic diff summary
0 added, 1 modified, 0 signature changed, 0 removed across 1 analyzed file
+30 -41 pkg/tunkit/ptun.go #
......@@ -53,6 +53,8 @@ func LocalForwardHandler(handler Tunnel) pssh.SSHServerChannelMiddleware {
5353 }
5454
5555 origCtx, cancel := context.WithCancel(context.Background())
56+ defer cancel()
57+
5658 ctx := &pssh.SSHServerConnSession{
5759 Channel: ch,
5860 SSHServerConn: sc,
......@@ -62,51 +64,38 @@ func LocalForwardHandler(handler Tunnel) pssh.SSHServerChannelMiddleware {
6264
6365 go ssh.DiscardRequests(reqs)
6466
67+ downConn, err := handler.CreateConn(ctx)
68+ if err != nil {
69+ log.Error("unable to connect to conn", "err", err)
70+ _ = ch.Close()
71+ return err
72+ }
73+
74+ var wg sync.WaitGroup
75+ wg.Add(2)
76+
6577 go func() {
66- downConn, err := handler.CreateConn(ctx)
67- if err != nil {
68- log.Error("unable to connect to conn", "err", err)
69- _ = ch.Close()
70- return
78+ defer wg.Done()
79+ _, err := io.Copy(ch, downConn)
80+ if err != nil && !errors.Is(err, net.ErrClosed) {
81+ log.Error("io copy", "err", err)
7182 }
72- defer func() {
73- _ = downConn.Close()
74- }()
75-
76- var wg sync.WaitGroup
77- wg.Add(2)
78-
79- go func() {
80- defer wg.Done()
81- defer func() {
82- _ = ch.CloseWrite()
83- _ = downConn.Close()
84- }()
85- _, err := io.Copy(ch, downConn)
86- if err != nil {
87- if !errors.Is(err, net.ErrClosed) {
88- log.Error("io copy", "err", err)
89- }
90- }
91- }()
92- go func() {
93- defer wg.Done()
94- defer func() {
95- _ = ch.Close()
96- _ = downConn.Close()
97- }()
98- _, err := io.Copy(downConn, ch)
99- if err != nil {
100- if !errors.Is(err, net.ErrClosed) {
101- log.Error("io copy", "err", err)
102- }
103- }
104- }()
105-
106- wg.Wait()
83+ _ = ch.CloseWrite()
10784 }()
10885
109- <-ctx.Done()
86+ go func() {
87+ defer wg.Done()
88+ _, err := io.Copy(downConn, ch)
89+ if err != nil && !errors.Is(err, net.ErrClosed) {
90+ log.Error("io copy", "err", err)
91+ }
92+ _ = downConn.Close()
93+ }()
94+
95+ wg.Wait()
96+ _ = ch.Close()
97+ _ = downConn.Close()
98+
11099 err = handler.Close(ctx)
111100 if err != nil {
112101 log.Error("tunnel handler error", "err", err)
Back to top