Files
Jing Chen ff3425ac1f Fix crash and resource-leak bugs in the containerd shim
- 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.
2026-08-26 22:47:36 +00:00

56 lines
1.6 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 runsc
import (
"strings"
"testing"
"time"
)
// TestDumpStacksTerminates verifies that a stack dump returns rather than
// looping forever, which would spin a core and flood the log on every SIGUSR2.
func TestDumpStacksTerminates(t *testing.T) {
done := make(chan []byte, 1)
go func() {
done <- dumpStacks()
}()
select {
case buf := <-done:
if len(buf) == 0 {
t.Fatal("dumpStacks() returned no data")
}
if got := string(buf); !strings.Contains(got, "goroutine ") {
t.Errorf("dumpStacks() = %q, want a goroutine dump", got)
}
case <-time.After(30 * time.Second):
t.Fatal("dumpStacks() did not return; it is looping")
}
}
// TestDumpStacksRepeatable verifies that consecutive dumps do not share a
// buffer.
func TestDumpStacksRepeatable(t *testing.T) {
first := dumpStacks()
second := dumpStacks()
if len(first) == 0 || len(second) == 0 {
t.Fatalf("dumpStacks() returned empty: %d, %d bytes", len(first), len(second))
}
if &first[0] == &second[0] {
t.Error("consecutive dumpStacks() calls returned aliasing buffers")
}
}