mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
- runsc/debug.go: the SIGUSR2 stack dumper never exited its loop, so one signal pinned a core for the life of the shim. - proc/init_state.go: the start-failure path closed p.io unconditionally, but Init.Create leaves it nil for terminal containers. The nil deref killed the shim, and with it the pod. - proc/utils.go: getLastRuntimeError leaked the log file it opened, on every failed runsc command. - utils/volumes.go: configureShm wrote into a nil annotation map, which IsSandbox permits. - runsc/epoll.go: the cgroups v1 OOM watcher panicked on the first publish failure, which is normal under CRI-O. Reuse forward's leniency check; the panic under containerd is kept. - runsccmd/runsc.go: cmdOutput returned slices aliasing sync.Pool buffers that putBuf immediately recycled.
106 lines
3.2 KiB
Go
106 lines
3.2 KiB
Go
// Copyright 2026 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package proc
|
|
|
|
import (
|
|
"context"
|
|
"os/exec"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/containerd/console"
|
|
"github.com/containerd/containerd/v2/pkg/stdio"
|
|
runc "github.com/containerd/go-runc"
|
|
"gvisor.dev/gvisor/pkg/shim/v1/runsccmd"
|
|
)
|
|
|
|
// fakePlatform is a no-op stdio.Platform.
|
|
type fakePlatform struct{}
|
|
|
|
func (fakePlatform) CopyConsole(ctx context.Context, con console.Console, id, stdin, stdout, stderr string, wg *sync.WaitGroup) (console.Console, error) {
|
|
return con, nil
|
|
}
|
|
|
|
func (fakePlatform) ShutdownConsole(context.Context, console.Console) error { return nil }
|
|
|
|
func (fakePlatform) Close() error { return nil }
|
|
|
|
// closerIO records whether it was closed. The embedded interface is nil; only
|
|
// the methods below are called.
|
|
type closerIO struct {
|
|
runc.IO
|
|
closed bool
|
|
}
|
|
|
|
func (c *closerIO) Close() error {
|
|
c.closed = true
|
|
return nil
|
|
}
|
|
|
|
func (c *closerIO) Set(*exec.Cmd) {}
|
|
|
|
// TestCreatedStateStartFailureWithoutIO verifies that a failed start does not
|
|
// panic when p.io is nil, as Init.Create leaves it for a terminal.
|
|
func TestCreatedStateStartFailureWithoutIO(t *testing.T) {
|
|
p := New("id", &runsccmd.Runsc{Command: "/nonexistent-runsc"}, stdio.Stdio{Terminal: true})
|
|
p.Platform = fakePlatform{}
|
|
p.Sandbox = false
|
|
|
|
if err := p.Start(t.Context()); err == nil {
|
|
t.Fatal("Start() succeeded, want error")
|
|
}
|
|
if _, ok := p.initState.(*stoppedState); !ok {
|
|
t.Errorf("initState = %T, want *stoppedState", p.initState)
|
|
}
|
|
if got := p.ExitStatus(); got != internalErrorCode {
|
|
t.Errorf("ExitStatus() = %d, want %d", got, internalErrorCode)
|
|
}
|
|
}
|
|
|
|
// TestCreatedStateStartFailureClosesIO verifies that the failure path still
|
|
// closes the IO when it exists.
|
|
func TestCreatedStateStartFailureClosesIO(t *testing.T) {
|
|
p := New("id", &runsccmd.Runsc{Command: "/nonexistent-runsc"}, stdio.Stdio{})
|
|
p.Platform = fakePlatform{}
|
|
p.Sandbox = false
|
|
cio := &closerIO{}
|
|
p.io = cio
|
|
|
|
if err := p.Start(t.Context()); err == nil {
|
|
t.Fatal("Start() succeeded, want error")
|
|
}
|
|
if !cio.closed {
|
|
t.Error("process IO was not closed on start failure")
|
|
}
|
|
if _, ok := p.initState.(*stoppedState); !ok {
|
|
t.Errorf("initState = %T, want *stoppedState", p.initState)
|
|
}
|
|
}
|
|
|
|
// TestCreatedStateStartFailureSandbox verifies that a sandbox is left in the
|
|
// created state on start failure, so that it can still be deleted.
|
|
func TestCreatedStateStartFailureSandbox(t *testing.T) {
|
|
p := New("id", &runsccmd.Runsc{Command: "/nonexistent-runsc"}, stdio.Stdio{Terminal: true})
|
|
p.Platform = fakePlatform{}
|
|
p.Sandbox = true
|
|
|
|
if err := p.Start(t.Context()); err == nil {
|
|
t.Fatal("Start() succeeded, want error")
|
|
}
|
|
if _, ok := p.initState.(*createdState); !ok {
|
|
t.Errorf("initState = %T, want *createdState", p.initState)
|
|
}
|
|
}
|