Hi,

I think you need to restructure your code, because what you're actually 
doing is checking whether the pid is valid or not.
Since the pid is made invalid inside the Wait call (in the kernel), before 
ProcessState is set, there's no way to do that safely.

Instead, you should avoid calling Wait until you're done using the pid. 
You'll have to use some other method for detecting if the process has 
exited. On newer Linux versions, the preferred way would be a pidfd 
obtained via pidfd_open.

Regards,
Per Johansson
On Saturday, July 23, 2022 at 10:39:17 PM UTC+2 harald....@gmx.net wrote:

> In my open source file descriptor leak checker (Linux only) for Gomega, 
> Go's race detector flags a race condition in my code where I need to 
> check whether a Cmd.Process already has terminated 
> <https://github.com/thediveo/fdooze/blob/05aae68770fd287e51aea8dd55ff336164cb3f49/session/session_fds.go#L21>
>  
> as its ProcessState has been set.
>
> if session.Command.ProcessState != nil {
>     return nil, errors.New("session has already ended")
> }
>
> Now, this check might be called be called from a different Goroutine than 
> another Goroutine waiting for the command to exit. In particular, this is 
> the (what I consider to be the relevant) output of the race detector:
>
> WARNING: DATA RACE
> Write at 0x00c0002e8208 by goroutine 16:
>   os/exec.(*Cmd).Wait()
>       /home/.../sdk/go1.19rc2/src/os/exec/exec.go:598 +0x1eb
>   github.com/onsi/gomega/gexec.(*Session).monitorForExit()
>       /home/.../go/pkg/mod/
> github.com/onsi/gom...@v1.20.0/gexec/session.go:197 
> <http://github.com/onsi/gomega@v1.20.0/gexec/session.go:197> +0x44
>   github.com/onsi/gomega/gexec.Start.func1()
>       /home/.../go/pkg/mod/
> github.com/onsi/gom...@v1.20.0/gexec/session.go:96 
> <http://github.com/onsi/gomega@v1.20.0/gexec/session.go:96> +0x47
>
> Previous read at 0x00c0002e8208 by goroutine 12:
>   github.com/thediveo/fdooze/session.FiledescriptorsFor()
>       /home/.../github/fdooze/session/session_fds.go:21 +0x1b7
>   github.com/thediveo/fdooze/session.glob..func1.1.1()
>       /home/.../github/fdooze/session/session_fds_test.go:45 +0x30
>   runtime.call16()
>       /home/.../sdk/go1.19rc2/src/runtime/asm_amd64.s:724 +0x48
>   reflect.Value.Call()
>       /home/.../sdk/go1.19rc2/src/reflect/value.go:368 +0xc7
>   github.com/onsi/gomega/internal.NewAsyncAssertion.func1()
>       /home/.../go/pkg/mod/
> github.com/onsi/gom...@v1.20.0/internal/async_assertion.go:48 
> <http://github.com/onsi/gomega@v1.20.0/internal/async_assertion.go:48> 
> +0x16e
>   github.com/onsi/gomega/internal.(*AsyncAssertion).pollActual()
>       /home/.../go/pkg/mod/
> github.com/onsi/gom...@v1.20.0/internal/async_assertion.go:132 
> <http://github.com/onsi/gomega@v1.20.0/internal/async_assertion.go:132> 
> +0x82
>   github.com/onsi/gomega/internal.(*AsyncAssertion).match()
>       /home/.../go/pkg/mod/
> github.com/onsi/gom...@v1.20.0/internal/async_assertion.go:162 
> <http://github.com/onsi/gomega@v1.20.0/internal/async_assertion.go:162> 
> +0xe4
>   github.com/onsi/gomega/internal.(*AsyncAssertion).ShouldNot()
>       /home/.../go/pkg/mod/
> github.com/onsi/gom...@v1.20.0/internal/async_assertion.go:112 
> <http://github.com/onsi/gomega@v1.20.0/internal/async_assertion.go:112> 
> +0xa9
>   github.com/thediveo/fdooze/session.glob..func1.1()
>       /home/.../github/fdooze/session/session_fds_test.go:65 +0xf41
>   github.com/onsi/ginkgo/v2/internal.(*Suite).runNode.func2()
>       /home/.../go/pkg/mod/
> github.com/onsi/ginkgo/v...@v2.1.4/internal/suite.go:596 
> <http://github.com/onsi/ginkgo/v2@v2.1.4/internal/suite.go:596> +0xea
>
> Is there actually any way to check use Cmd.ProcessState at all from a 
> thread different from the one doing a Cmd.Wait? Might this be a design 
> "weakness" of the Cmd type in that it doesn't cover such use cases?
>
> Any idea for a work around to find if the command might already have 
> (prematurely) finished by the time I try to check for its open file 
> descriptors?
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/64d8618c-63a8-4cb1-879e-a28aec93da0cn%40googlegroups.com.

Reply via email to