diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2015-12-29 13:29:00 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2015-12-29 13:29:00 +0100 |
| commit | d40104b8a35f01d31cad1f11e312e76e034ffc4a (patch) | |
| tree | 7670efd663a3c1a140b985f9bf01a7146603fd44 /fileutil/fileutil_test.go | |
| parent | b17c5726f6dc911ac0d4c9be02c2a0d9a7dee393 (diff) | |
fileutil: fix race in ProcessTempDir
One goroutine decides that it needs to clean up an instance,
but before it tries to delete pid file it is preempted.
Then another goroutine cleans up this instances and creates
a new instances in the same dir.
Then first goroutine removes already new pid file and removes
the used dir.
Fix this by using flock on a lock file.
Add a test.
Diffstat (limited to 'fileutil/fileutil_test.go')
| -rw-r--r-- | fileutil/fileutil_test.go | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/fileutil/fileutil_test.go b/fileutil/fileutil_test.go new file mode 100644 index 000000000..1084cc98d --- /dev/null +++ b/fileutil/fileutil_test.go @@ -0,0 +1,80 @@ +// Copyright 2015 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package fileutil + +import ( + "bytes" + "io/ioutil" + "os" + "strconv" + "sync" + "testing" + "path/filepath" +) + +func TestProcessTempDir(t *testing.T) { + for try := 0; try < 10; try++ { + func() { + tmp, err := ioutil.TempDir("", "syz") + if err != nil { + t.Fatalf("failed to create a temp dir: %v", err) + } + defer os.RemoveAll(tmp) + const P = 16 + // Pre-create half of the instances with stale pid. + var dirs []string + for i := 0; i < P/2; i++ { + dir, idx, err := ProcessTempDir(tmp) + if err != nil { + t.Fatalf("failed to create process temp dir") + } + if idx != i { + t.Fatalf("unexpected index: want %v, got %v", i, idx) + } + dirs = append(dirs, dir) + } + for _, dir := range dirs { + if err := ioutil.WriteFile(filepath.Join(dir, ".pid"), []byte(strconv.Itoa(999999999)), 0600); err != nil { + t.Fatalf("failed to write pid file: %v", err) + } + } + // Now request a bunch of instances concurrently. + done := make(chan bool) + indices := make(map[int]bool) + var mu sync.Mutex + for p := 0; p < P; p++ { + go func() { + defer func() { + done <- true + }() + dir, idx, err := ProcessTempDir(tmp) + if err != nil { + t.Fatalf("failed to create process temp dir") + } + mu.Lock() + present := indices[idx] + indices[idx] = true + mu.Unlock() + if present { + t.Fatalf("duplicate index %v", idx) + } + data := []byte(strconv.Itoa(idx)) + if err := ioutil.WriteFile(filepath.Join(dir, "data"), data, 0600); err != nil { + t.Fatalf("failed to write data file: %v", err) + } + data1, err := ioutil.ReadFile(filepath.Join(dir, "data")) + if err != nil { + t.Fatalf("failed to read data file: %v", err) + } + if bytes.Compare(data, data1) != 0 { + t.Fatalf("corrupted data file") + } + }() + } + for p := 0; p < P; p++ { + <-done + } + }() + } +} |
