Skip to content
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

Context.Reborn fails with "write |1: broken pipe" due to a race condition in writing to Context.wpipe #86

Open
avoronkov opened this issue Oct 17, 2022 · 0 comments

Comments

@avoronkov
Copy link

Platform, version

  • Almalinux 9, x86_64 on Virtuozzo 7 virtualization.

  • go-daemon v0.1.6

  • go 1.19.2

Problem statement

Method Context.parent() in daemon_unix.go contains the following code:

        encoder := json.NewEncoder(d.wpipe)
        if err = encoder.Encode(d); err != nil {
                return
        }
        _, err = fmt.Fprint(d.wpipe, "\n\n")

In some cases the following happens:

  1. parent writes json into d.wpipe with encoder.Encode(d);
  2. child reads json with corresponding call to decoder.Decode(d);
  3. child executes some code, finishes and close the pipe;
  4. parent tries to performs fmt.Fprint(d.wpipe, "\n\n").

As a result Context.Reborn() fails with write |1: broken pipe though the child process is successfully started.

Impact

In some cases Context.Reborn() can fail with write |1: broken pipe though the child process is successfully started.

Steps to reproduce

Compile and run the following program on Almalinux 9 x86_64, Virtuozzo 7:

package main
import (
        "log"
        daemon "github.com/avoronkov/go-daemon"
)
func main() {
        cntxt := &daemon.Context{
                LogFileName: "sample.log",
                LogFilePerm: 0640,
        }
        d, err := cntxt.Reborn()
        if err != nil {
                log.Fatal("Unable to run: ", err)
        }
        if d != nil {
                // Parent process
                log.Printf("Parent: OK")
                return
        }
        defer cntxt.Release()
        log.Print("Child: OK")
}

Actual result

The program fails with the following error:

$ ./prog 
2022/10/17 20:29:30 Unable to run: write |1: broken pipe

Expected result

  • Program finishes successfully.

  • Parent writes message Parent: OK

  • Child writes message Child: OK into "sample.log"

Additional information

The problem was found when I tried to run existing application which uses go-daemon on Almalinux 9 (which is quite new RedHat-based OS).

Possible fix

Apply the following patch:

--- a/daemon_unix.go
+++ b/daemon_unix.go
@@ -113,7 +113,6 @@ func (d *Context) parent() (child *os.Process, err error) {
        if err = encoder.Encode(d); err != nil {
                return
        }
-       _, err = fmt.Fprint(d.wpipe, "\n\n")
        return
 }
 

Looks like writing "\n\n" into a pipe after encoding json is redundant.
At least I was not able to find the problem it fixes.

avoronkov pushed a commit to avoronkov/go-daemon that referenced this issue Oct 17, 2022
@deniszh deniszh mentioned this issue Jan 30, 2023
deniszh added a commit that referenced this issue Jan 30, 2023
fix race condition on writing in wpipe (write |1: broken pipe) (#86)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant