• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2023 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build windows
6
7package os_test
8
9import (
10	"internal/testenv"
11	"io"
12	. "os"
13	"path/filepath"
14	"sync"
15	"testing"
16)
17
18func TestRemoveAllWithExecutedProcess(t *testing.T) {
19	// Regression test for golang.org/issue/25965.
20	if testing.Short() {
21		t.Skip("slow test; skipping")
22	}
23	testenv.MustHaveExec(t)
24
25	name, err := Executable()
26	if err != nil {
27		t.Fatal(err)
28	}
29	r, err := Open(name)
30	if err != nil {
31		t.Fatal(err)
32	}
33	defer r.Close()
34	const n = 100
35	var execs [n]string
36	// First create n executables.
37	for i := 0; i < n; i++ {
38		// Rewind r.
39		if _, err := r.Seek(0, io.SeekStart); err != nil {
40			t.Fatal(err)
41		}
42		name := filepath.Join(t.TempDir(), "test.exe")
43		execs[i] = name
44		w, err := Create(name)
45		if err != nil {
46			t.Fatal(err)
47		}
48		if _, err = io.Copy(w, r); err != nil {
49			w.Close()
50			t.Fatal(err)
51		}
52		if err := w.Sync(); err != nil {
53			w.Close()
54			t.Fatal(err)
55		}
56		if err = w.Close(); err != nil {
57			t.Fatal(err)
58		}
59	}
60	// Then run each executable and remove its directory.
61	// Run each executable in a separate goroutine to add some load
62	// and increase the chance of triggering the bug.
63	var wg sync.WaitGroup
64	wg.Add(n)
65	for i := 0; i < n; i++ {
66		go func(i int) {
67			defer wg.Done()
68			name := execs[i]
69			dir := filepath.Dir(name)
70			// Run test.exe without executing any test, just to make it do something.
71			cmd := testenv.Command(t, name, "-test.run=^$")
72			if err := cmd.Run(); err != nil {
73				t.Errorf("exec failed: %v", err)
74			}
75			// Remove dir and check that it doesn't return `ERROR_ACCESS_DENIED`.
76			err = RemoveAll(dir)
77			if err != nil {
78				t.Errorf("RemoveAll failed: %v", err)
79			}
80		}(i)
81	}
82	wg.Wait()
83}
84