Skip to content

os: data race between Process.Wait and Kill #9382

Closed
@pmezard

Description

@pmezard

go version go1.4 windows/amd64

Looks like there is a data race between os.Process.Wait() and os.Process.Kill(). The documentation does not state these operations can be run concurrently, but if they cannot, can you suggest a way to implement some kind of timeout on started process? Like "kill it if it runs more than N seconds".

The following code triggers the issue:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "strconv"
    "sync"
    "time"
)

func spawnAndKill(exePath string, counter int) error {
    cmd := exec.Command(exePath, fmt.Sprintf("%d", counter))
    err := cmd.Start()
    if err != nil {
        return err
    }
    go func() {
        time.Sleep(1000 * time.Millisecond)
        cmd.Process.Kill()
    }()
    cmd.Wait()
    return nil
}

func main() {
    args := os.Args[1:]
    if len(args) > 0 {
        delay, err := strconv.ParseInt(args[0], 10, 32)
        if err != nil {
            panic("invalid input: " + args[0])
        }
        time.Sleep(time.Duration(delay) * time.Millisecond)
        return
    }
    exePath := os.Args[0]
    fmt.Printf("exe: %s\n", exePath)

    jobs := &sync.WaitGroup{}
    for j := 0; j < 100; j++ {
        jobs.Add(1)
        go func(id int) {
            defer jobs.Done()
            counter := 0
            for {
                err := spawnAndKill(exePath, counter%2000)
                if err != nil {
                    fmt.Printf("spawn error: %s\n", err)
                    return
                }
                counter += 1
            }
        }(j)
    }
    jobs.Wait()
}

when run with:

go install -race race && GOMAXPROCS=100 GORACE="halt_on_error=1" bin/race.exe

and triggers:

exe: F:\dev\master\sword2\bin\race.exe
==================
WARNING: DATA RACE
Read by goroutine 106:
  os.(*Process).signal()
      c:/go/src/os/exec_windows.go:56 +0x5a
  os.(*Process).Signal()
      c:/go/src/os/doc.go:51 +0x62
  os.(*Process).kill()
      c:/go/src/os/exec_posix.go:53 +0x76
  os.(*Process).Kill()
      c:/go/src/os/doc.go:36 +0x4e
  main.func·001()
      F:/dev/master/sword2/src/race/race.go:20 +0x83

Previous write by goroutine 6:
  os.(*Process).release()
      c:/go/src/os/exec_windows.go:77 +0x2c2
  os.(*Process).Release()
      c:/go/src/os/doc.go:31 +0x4e
  os.(*Process).wait()
      c:/go/src/os/exec_windows.go:42 +0x64c
  os.(*Process).Wait()
      c:/go/src/os/doc.go:45 +0x4e
  os/exec.(*Cmd).Wait()
      c:/go/src/os/exec/exec.go:364 +0x315
  main.spawnAndKill()
      F:/dev/master/sword2/src/race/race.go:22 +0x360
  main.func·002()
      F:/dev/master/sword2/src/race/race.go:46 +0xe1

Goroutine 106 (running) created at:
  main.spawnAndKill()
      F:/dev/master/sword2/src/race/race.go:21 +0x340
  main.func·002()
      F:/dev/master/sword2/src/race/race.go:46 +0xe1

Goroutine 6 (running) created at:
  main.main()
      F:/dev/master/sword2/src/race/race.go:53 +0x539
==================

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions