-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd/go: go test leaves temp directory behind #2866
Labels
Milestone
Comments
I would if I could, but I do not know why it is happening. Yet. Alex Owner changed to builder@golang.org. |
C:\...\Temp\go-build932562370\runtime\_test\runtime.test.exe is left. Nothing else. I suspect it is a variation of https://golang.org/issue/1899. Please, create "Too Hard" label, and we'll mark this one. :-) Alex |
I am far from clear about what is happening here. I have been debugging it, but I have no clear picture yet. I plan to continue. As far as guessing goes, I have 2 possibilities in mind. 1) It could be variation of something we have seen before. http://golang.org/cl/4978047 If you look at hector comment: " ... It is impossible to know when the binary has been unmapped from memory. Waiting on the process handle doesn't work because the handle gets signalled as soon as ExitProcess() is called, and the binary will still be mapped at that time. ..." I could not find reference to that fact anywhere. But, perhaps, hector saw it happens while debugging program. 2) Our *os.Process has Release function, that is NOP on unix, but closes process handle on windows. Release function is set to be called by finallizer, and most of the time it is good enough. But os/exec.Command does not call Release explicitly, and relies on finalizer to do it. Perhaps, we delete test binary, but process handle is still opened, because finalizer didn't run yet. Perhaps it is the cause. These are not even theories, just hints. Perhaps, there is something else - something much simpler. Alex |
It looks like not Releasing finished process handle does not affect our ability to delete process binary. This program runs with no error. package main import ( "os/exec" "io/ioutil" "log" "os" "path/filepath" ) func main() { const prog = "ipconfig" tmpexe := filepath.Join(os.TempDir(), "tmp.exe") progpath, err := exec.LookPath(prog) if err != nil { log.Fatalf("LookPath(%s): %v", prog, err) } os.Remove(tmpexe) f, err := os.Create(tmpexe) if err != nil { log.Fatalf("Create(%s): %v", tmpexe, err) } buf, err := ioutil.ReadFile(progpath) if err != nil { log.Fatalf("ReadFile(%s): %v", progpath, err) } _, err = f.Write(buf) if err != nil { log.Fatalf("Write(%s): %v", tmpexe, err) } f.Close() cmd := exec.Command(prog) out, err := cmd.CombinedOutput() if err != nil { log.Fatalf("%s failed: %s: %s\n", prog, err, out) } err = os.Remove(tmpexe) if err != nil { log.Fatalf("Remove(%s): %v", tmpexe, err) } // keep cmd around until after os.Remove _ = cmd.Path } This is just a test. This one worked. Other variations might not. Alex |
I tried inserting call to os/exec.Command.Process.Release into go command, because otherwise it never gets called: diff -r 1e3137b41422 src/cmd/go/test.go --- a/src/cmd/go/test.go Fri Feb 17 14:39:50 2012 +1100 +++ b/src/cmd/go/test.go Fri Feb 17 16:34:07 2012 +1100 @@ -586,6 +586,7 @@ fmt.Fprintf(&buf, "*** Test killed: ran too long.\n") } tick.Stop() + cmd.Process.Release() } out := buf.Bytes() t1 := time.Now() @@ -614,7 +615,10 @@ func (b *builder) cleanTest(a *action) error { run := a.deps[0] testDir := filepath.Join(b.work, filepath.FromSlash(run.p.ImportPath+"/_test")) - os.RemoveAll(testDir) + e := os.RemoveAll(testDir) + if e != nil { + fmt.Printf("cleanTest: %s %s\n", testDir, e) + } return nil } $ hg id 1e3137b41422+ tip but it does not make any difference - os.RemoveAll still fails. I can see all events in correct order: create process, wait for it to finish, close process handle, delete /tmp, but still no go. Alex |
I made a mistake in https://golang.org/issue/2866?c=9 - my program is buggy. I intended to do: package main import ( "os/exec" "io/ioutil" "log" "os" "path/filepath" ) func main() { log.SetFlags(0) const prog = "ipconfig" progpath, err := exec.LookPath(prog) if err != nil { log.Fatalf("LookPath(%s): %v", prog, err) } tmpexe := filepath.Join(os.TempDir(), "tmp.exe") os.Remove(tmpexe) f, err := os.Create(tmpexe) if err != nil { log.Fatalf("Create(%s): %v", tmpexe, err) } buf, err := ioutil.ReadFile(progpath) if err != nil { log.Fatalf("ReadFile(%s): %v", progpath, err) } _, err = f.Write(buf) if err != nil { log.Fatalf("Write(%s): %v", tmpexe, err) } f.Close() cmd := exec.Command(tmpexe) out, err := cmd.CombinedOutput() if err != nil { log.Fatalf("%s failed: %s: %s\n", tmpexe, err, out) } err = cmd.Process.Release() if err != nil { log.Fatalf("cmd.Process.Release(%s): %v", tmpexe, err) } err = os.Remove(tmpexe) if err != nil { log.Fatalf("Remove(%s): %v", tmpexe, err) } } This program specifically closes process handle before attempting to delete binary of just finished process. The program fails on my windows xp computer with: Remove(C:\DOCUME~1\brainman\LOCALS~1\Temp\tmp.exe): remove C:\DOCUME~1\brainman\LOCALS~1\Temp\tmp.exe: Access is denied. so it is in line with originally reported issue. On the other hand - this program runs fine on other computers windows 2000 and windows 7. I tend to agree more and more that return from syscall.WaitForSingleObject for process handle is sometimes too early to be able to remove process binary. Alex |
Can you try putting in a sleep for 5 seconds and then remove? Does that work? If the sleep works then I agree we're in trouble and can't do much. If the sleep is not enough then I wonder if some library is still not quite releasing a handle. Also, after a command finishes (which you know by calling Wait or by calling any function that wraps it, like CombinedOutput), it should not be necessary to call cmd.Process.Release explicitly. Wait should do that. |
Even time.Sleep(5 * time.Millisecond) helps - the "Access is denied" message disappear and file gets deleted successfully. I changed os/exec to close process handle as you suggested: http://golang.org/cl/5699081/ Alex |
This issue was closed by revision d1bd332. Status changed to Fixed. |
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
The text was updated successfully, but these errors were encountered: