Skip to content

os/exec: environment variable de-duplication breaks old behaviour #19877

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

Closed
rogpeppe opened this issue Apr 7, 2017 · 5 comments
Closed

os/exec: environment variable de-duplication breaks old behaviour #19877

rogpeppe opened this issue Apr 7, 2017 · 5 comments

Comments

@rogpeppe
Copy link
Contributor

rogpeppe commented Apr 7, 2017

go version devel +2bd6360 Wed Mar 8 03:24:44 2017 +0000 linux/amd64

The change reviewed in https://go-review.googlesource.com/c/37586/
has broken some of our tests because Go's behaviour when
importing environment variables is to use the first instance
of the variable, not the last (unlike bash, for example), so
when some code that appends a duplicate variable to the
environment and then executes a Go program, the
variable seen by the program is now the last value
where before it was the first.

To demonstrate the issue, build the following two programs:

# tst1.go
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Printf("xxx=%s\n", os.Getenv("xxx"))
}

second program:

# tst2.go
package main

import (
	"os"
	"os/exec"
)

func main() {
	env := []string{"xxx=a", "xxx=b"}
	c := exec.Command("tst1")
	c.Env = env
	c.Stdout = os.Stdout
	c.Run()
}

Try running tst2 with different versions of Go. I'd expect to see "x=b" in both cases
but old versions of Go print "x=a" instead.

@mvdan
Copy link
Member

mvdan commented Apr 7, 2017

I would also think that the latest duplicate would be kept. Perhaps worth noting that elsewhere in the standard library, we keep the first of the duplicates, such as in url parameters or http headers.

to use the first instance of the variable, not the last (unlike bash, for example)

Could you elaborate on how bash behaves? Or do you mean the following?

$ a=foo a=bar; echo $a
bar

For the sake of completeness, both dash and BusyBox's ash behave the same.

@rogpeppe
Copy link
Contributor Author

rogpeppe commented Apr 7, 2017

@mvdan Change exec.Command("tst1") to exec.Command("/bin/sh", "-c", "echo $xxx") to see what shells do - I think they usually use the last variable found. It's an unfortunate difference from Go's behaviour which means that de-duplicating environment variables is never going to be fully backwardly compatible. It's arguable that we should just fix our tests to avoid the duplication, but I thought it worth raising the issue here anyway.

@mvdan
Copy link
Member

mvdan commented Apr 7, 2017

is never going to be fully backwardly compatible.

I don't understand - the os/exec deduplication was only introduced in February, so it hasn't been released yet. We can change it without breaking backwards compatibility.

@bradfitz
Copy link
Contributor

bradfitz commented Apr 7, 2017

When you use your shell,

$ xxx=a xxx=b ./cmd

The shell is stripping all but the last pair and only running ./cmd with the last.

Observe (on Linux):

package main

import (
        "fmt"
        "io/ioutil"
        "log"
        "os"
)

func main() {
        slurp, err := ioutil.ReadFile("/proc/self/environ")
        if err != nil {
                log.Fatal(err)
        }
        fmt.Printf("%q\n", slurp)
        fmt.Printf("%q\n", os.Getenv("xxx"))
}
$ xxx=a xxx=b ./printenv 
"xxx=b\x00XDG_SESSION_ID=1\x00SHELL=/bin/bash\x00TERM=screen\x00SSH_CLIENT=...

So at tip, Go is now doing what shells are doing. Go doesn't have the option of making os.Getenv change. And we don't want to change os/exec, because that would break the common pattern of appending to cmd.Env, and be inconsistent with shells.

We probably should've done this from day 1. Sorry. My fault. I never knew about shells doing this until recently.

I think the best option, @rogpeppe, is to update your tests. None of this was documented or guaranteed in the past, neither in Go nor in shell or C, AFAIK.

@robpike
Copy link
Contributor

robpike commented Apr 7, 2017

xxx=a xxx=b cat /proc/self environ suffices.

I agree it's a bug fix and should stay.

@bradfitz bradfitz closed this as completed Apr 9, 2017
rogpeppe added a commit to rogpeppe-contrib/juju-utils that referenced this issue Apr 20, 2017
This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.
rogpeppe added a commit to rogpeppe-contrib/juju-utils that referenced this issue Apr 20, 2017
This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.
jujubot added a commit to juju/utils that referenced this issue Apr 20, 2017
add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.
marcmolla pushed a commit to marcmolla/utils that referenced this issue Apr 21, 2017
This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.
marcmolla pushed a commit to marcmolla/utils that referenced this issue Apr 21, 2017
This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.
marcmolla added a commit to marcmolla/utils that referenced this issue Apr 21, 2017
?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file
marcmolla added a commit to marcmolla/utils that referenced this issue Apr 21, 2017
?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic

now it is ok
marcmolla pushed a commit to marcmolla/utils that referenced this issue Apr 21, 2017
This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.
marcmolla added a commit to marcmolla/utils that referenced this issue Apr 21, 2017
?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic

now it is ok

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

OpenSUSE support in utils/os

?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic

now it is ok

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic
marcmolla added a commit to marcmolla/utils that referenced this issue Apr 21, 2017
?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic

now it is ok

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

OpenSUSE support in utils/os

?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic

now it is ok

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic
axw pushed a commit to axw/juju-utils that referenced this issue Apr 24, 2017
?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic

now it is ok

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

OpenSUSE support in utils/os

?

rebase

rebase

Change the series name to align with other distros

corrected series ID

Added support to Zypper

added lsb-release as default package

typo in zypper name

test fails

rebase

adding debug info

missing line

solved

remove debug

Export proxy settings as systemd config

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

rebase

Added support to Zypper

typo in zypper name

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Corrected fails in test

Change the series name to align with other distros

corrected series ID

Added support to Zypper

typo in zypper name

test fails

adding debug info

missing line

solved

remove debug

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

solved zypper interactive bug

add test

make Setenv ignore malformed entries rather than panic

Updating PR with the first comments

Updated copyright of testing file

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic

now it is ok

AddNoProxyAddress

Add separate AutoNoProxyList

add Setenv function

This makes it easier to override environment variables
since just appending environment variables doesn't
work any more (and never did for non-Go programs).
See golang/go#19877 for
background.

make Setenv ignore malformed entries rather than panic

AddNoProxyAddress

Add separate AutoNoProxyList

Document AUtoNoProxy, add newline at the end of ScriptEnvironment and EnvironmentValues

test fix

make Setenv ignore malformed entries rather than panic
@golang golang locked and limited conversation to collaborators Apr 9, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants