mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-25 14:00:40 +00:00
48c3ca066c
* fix(test): template and fixture temp dirs no longer leak into /tmp (BUG-3412) The store test templates are named for the owning pid, and each build first removes the template dirs of processes that are gone (and pid-less legacy dirs over a day old), so a test binary killed before TestMain's Cleanup no longer leaves its template on the tmpfs for good. The fence source tests remove their fixture dirs when the file finishes. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(test): never sweep pid-less template dirs; age proves no owner gone (codex r1 on BUG-3412) Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
60 lines
1.8 KiB
Go
60 lines
1.8 KiB
Go
// Package testtmp makes the process-wide temp directories test binaries
|
|
// share (BUG-3412) without leaking them when a binary dies before its
|
|
// cleanup runs.
|
|
//
|
|
// A test binary killed by a timeout, a signal or the harness's memory reaper
|
|
// never reaches TestMain's Cleanup, so its template directory stayed in /tmp
|
|
// for good; /tmp is a tmpfs here, so every leaked template is RAM. The
|
|
// directory name now carries the owning process id, and each new build first
|
|
// removes the directories of processes that are gone.
|
|
package testtmp
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// MkdirTemp is os.MkdirTemp("", prefix+"<pid>-*") after a sweep of earlier
|
|
// prefix directories whose process is dead. prefix must end in "-".
|
|
func MkdirTemp(prefix string) (string, error) {
|
|
Sweep(os.TempDir(), prefix)
|
|
return os.MkdirTemp("", fmt.Sprintf("%s%d-*", prefix, os.Getpid()))
|
|
}
|
|
|
|
// Sweep removes dir/prefix<pid>-* directories owned by this user whose
|
|
// process is no longer running. A directory without a pid (made before
|
|
// BUG-3412) is never removed: its age cannot prove its owner gone, since a
|
|
// stopped or suspended process can outlive any bound (codex r1). Errors are
|
|
// ignored: a sweep that cannot remove something leaves it as it was.
|
|
func Sweep(dir, prefix string) {
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return
|
|
}
|
|
self := os.Getpid()
|
|
for _, e := range entries {
|
|
name := e.Name()
|
|
if !e.IsDir() || !strings.HasPrefix(name, prefix) {
|
|
continue
|
|
}
|
|
path := filepath.Join(dir, name)
|
|
info, err := e.Info()
|
|
if err != nil || !ownedByMe(info) {
|
|
continue
|
|
}
|
|
rest := name[len(prefix):]
|
|
pidPart, _, hasDash := strings.Cut(rest, "-")
|
|
pid, perr := strconv.Atoi(pidPart)
|
|
if !hasDash || perr != nil || pid <= 0 {
|
|
continue
|
|
}
|
|
if pid == self || processAlive(pid) {
|
|
continue
|
|
}
|
|
_ = os.RemoveAll(path)
|
|
}
|
|
}
|