Skip to content

Commit fc58318

Browse files
authored
fix(orchestrator): bug fix in pkg/nfsproxy/recovery (#2606)
`pkg/nfsproxy/recovery` had a real defect that surfaced on every platform but was masked because the package's tests were the only thing exercising the panic path; on darwin the test harness ran but still crashed with `panic: Mount [recovered, repanicked]`. Bug fix in pkg/nfsproxy/recovery `Handler.Mount`, `Change`, `ToHandle` and `HandleLimit` deferred a *method* `h.tryRecovery(ctx, name)` whose body simply called the package-level `tryRecovery(ctx, name)`. Because `recover()` only returns non-nil when invoked directly inside the deferred function frame, the indirection meant `recover()` always returned nil and panics propagated out of `Handler.Mount` & friends — defeating the whole point of the recovery wrapper. `TestHandler_Mount_Panic_NoCrash` was written to assert exactly this property and consequently failed on every platform. Replaced the pass-through method with a direct `defer tryRecovery(ctx, name)` call at every call site and removed the now-redundant `(Handler).tryRecovery` method. Added a comment to the package-level `tryRecovery` explaining why it must be called via `defer` directly.
1 parent cbcd91b commit fc58318

1 file changed

Lines changed: 8 additions & 9 deletions

File tree

  • packages/orchestrator/pkg/nfsproxy/recovery

packages/orchestrator/pkg/nfsproxy/recovery/main.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ func WrapWithRecovery(ctx context.Context, h nfs.Handler) *Handler {
2525
}
2626

2727
func (h Handler) Mount(ctx context.Context, conn net.Conn, request nfs.MountRequest) (nfs.MountStatus, billy.Filesystem, []nfs.AuthFlavor) {
28-
defer h.tryRecovery(ctx, "Mount")
28+
defer tryRecovery(ctx, "Mount")
2929
s, fs, auth := h.inner.Mount(ctx, conn, request)
3030
fs = wrapFS(ctx, fs)
3131

3232
return s, fs, auth
3333
}
3434

3535
func (h Handler) Change(ctx context.Context, filesystem billy.Filesystem) billy.Change {
36-
defer h.tryRecovery(ctx, "Change")
36+
defer tryRecovery(ctx, "Change")
3737
c := h.inner.Change(ctx, filesystem)
3838

3939
return wrapChange(ctx, c)
@@ -46,7 +46,7 @@ func (h Handler) FSStat(ctx context.Context, filesystem billy.Filesystem, stat *
4646
}
4747

4848
func (h Handler) ToHandle(ctx context.Context, fs billy.Filesystem, path []string) []byte {
49-
defer h.tryRecovery(ctx, "ToHandle")
49+
defer tryRecovery(ctx, "ToHandle")
5050

5151
return h.inner.ToHandle(ctx, fs, path)
5252
}
@@ -64,17 +64,16 @@ func (h Handler) InvalidateHandle(ctx context.Context, filesystem billy.Filesyst
6464
}
6565

6666
func (h Handler) HandleLimit() int {
67-
defer h.tryRecovery(h.ctx, "HandleLimit")
67+
defer tryRecovery(h.ctx, "HandleLimit")
6868

6969
return h.inner.HandleLimit()
7070
}
7171

72-
func (h Handler) tryRecovery(ctx context.Context, name string) {
73-
tryRecovery(ctx, name)
74-
}
75-
72+
// tryRecovery must be called via `defer` directly so that recover() runs in
73+
// the deferred function frame. Nesting it inside another helper would cause
74+
// recover() to return nil and the panic would propagate.
7675
func tryRecovery(ctx context.Context, name string) {
77-
if r := recover(); r != nil { //nolint:revive // tryRecovery is always called via defer
76+
if r := recover(); r != nil { //nolint:revive // always called via defer
7877
logger.L().Error(ctx, fmt.Sprintf("panic in %q nfs handler", name),
7978
zap.Any("panic", r),
8079
zap.Stack("stack"),

0 commit comments

Comments
 (0)