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

panic in exec #971

Closed
BenTheElder opened this issue Oct 20, 2019 · 7 comments · Fixed by #972
Closed

panic in exec #971

BenTheElder opened this issue Oct 20, 2019 · 7 comments · Fixed by #972
Assignees
Labels
kind/bug Categorizes issue or PR as related to a bug. lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor. priority/critical-urgent Highest priority. Must be actively worked on as someone's top priority right now.

Comments

@BenTheElder
Copy link
Member

kubernetes/kubernetes#84122 (comment)

/priority critical-urgent
/assign

@BenTheElder BenTheElder added the kind/bug Categorizes issue or PR as related to a bug. label Oct 20, 2019
@k8s-ci-robot k8s-ci-robot added the priority/critical-urgent Highest priority. Must be actively worked on as someone's top priority right now. label Oct 20, 2019
@BenTheElder
Copy link
Member Author

/lifecycle active

@k8s-ci-robot k8s-ci-robot added the lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor. label Oct 20, 2019
@BenTheElder
Copy link
Member Author

kind/pkg/exec/local.go

Lines 75 to 76 in 7dd62cd

// TODO(BenTheElder): adding bytes.Buffer to both multiwriters might need
// to be wrapped with a mutex

🤦‍♂ 🤦‍♂

@BenTheElder
Copy link
Member Author

BenTheElder commented Oct 20, 2019

Go's standard library has:

// CombinedOutput runs the command and returns its combined standard
// output and standard error.
func (c *Cmd) CombinedOutput() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	if c.Stderr != nil {
		return nil, errors.New("exec: Stderr already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	err := c.Run()
	return b.Bytes(), err
}

however, presumably this is a bit safer than a pair of MultiWriters.

@BenTheElder
Copy link
Member Author

BenTheElder commented Oct 20, 2019

on the plus side, digging into what's going on here ... i think there's a good chance fixing this fixes #949

@BenTheElder
Copy link
Member Author

So if cmd.Stdout and cmd.Stderr are identical, then Go will set up the actual fd for stdout and then set stderr to the same fd.

https://golang.org/src/os/exec/exec.go

func (c *Cmd) stdout() (f *os.File, err error) {
	return c.writerDescriptor(c.Stdout)
}

func (c *Cmd) stderr() (f *os.File, err error) {
	if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
		return c.childFiles[1], nil
	}
	return c.writerDescriptor(c.Stderr)
}

This is why CombinedOuput in the stdlib is safe.

When we set up an io.MultiWriter they are not the same, and get different fds.

In that case, we need to handle the writer receiving concurrent writes.

@BenTheElder
Copy link
Member Author

Filed #972 with more details and a fix.

@BenTheElder
Copy link
Member Author

This is a little tricky to intentionally reproduce, I believe #972 should prevent it, but we should keep our eyes peeled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Categorizes issue or PR as related to a bug. lifecycle/active Indicates that an issue or PR is actively being worked on by a contributor. priority/critical-urgent Highest priority. Must be actively worked on as someone's top priority right now.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants