Repository: godbus/dbus (go)

Issue:
WSL: Unexpected dbus-launch response leads to panic when parsing for address
In using this library via [clisso](https://github.com/allcloud-io/clisso/blob/5e9ac85519bade283db67ac7c77de194449b2663/Gopkg.lock#L95-L101/), I encountered an exception parsing the output of `dbus-launch`. My machine was responding to that with the following:
```
process 7616: D-Bus library appears to be incorrectly set up; failed to read machine uuid: UUID file '/etc/machine-id' should contain a hex string of length 32, not len
gth 0, with no other text
See the manual page for dbus-uuidgen to correct this issue.
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-0SO9YZUBGA,guid=ac22f2f3b9d228496b4d4b935cae3417
DBUS_SESSION_BUS_PID=7620
DBUS_SESSION_BUS_WINDOWID=16777217
```

I think this is due to the fact that I'm running WSL, and I had to do [the following](https://github.com/Microsoft/WSL/issues/2016#issuecomment-435091497) to get dbus properly setup on my machine.
```
sudo apt-get install dbus-x11
sudo service dbus start
```

[The code](https://github.com/godbus/dbus/blob/a31833e1a12623054b23f7ecc37e03a0beff8e87/conn_other.go#L25-L26) assumes the `=` will always preceed the `\n`, and thus does `b[i+1:j]`:
```go
	i := bytes.IndexByte(b, '=')
	j := bytes.IndexByte(b, '\n')
```
```go
	env, addr := string(b[0:i]), string(b[i+1:j])
```
In my case, the newline came before the equals sign, and thus the slice arguments made no sense and threw `panic: runtime error: slice bounds out of range`.

Pull request:
Handle multiline responses to dbus-launch
Users may not have dbus properly configured, and their machine may respond
to dbus-launch with a multiline string that prints a warning before returning
the expected output. The code handling this response assumed that it would
always find '=' before it finds '\n', but this not true in the case of a
multiline string. Rather, it is the other way around, and thus the code sliced
the response with a lower bound greater than its upper bound, leading to a
"panic: runtime error: slice bounds out of range" crash.

Fixes #151

Patch:
diff --git a/conn_other.go b/conn_other.go
index 289044a..616dcf6 100644
--- a/conn_other.go
+++ b/conn_other.go
@@ -14,8 +14,10 @@ import (
 	"strings"
 )
 
+var execCommand = exec.Command
+
 func getSessionBusPlatformAddress() (string, error) {
-	cmd := exec.Command("dbus-launch")
+	cmd := execCommand("dbus-launch")
 	b, err := cmd.CombinedOutput()
 
 	if err != nil {
@@ -25,7 +27,7 @@ func getSessionBusPlatformAddress() (string, error) {
 	i := bytes.IndexByte(b, '=')
 	j := bytes.IndexByte(b, '\n')
 
-	if i == -1 || j == -1 {
+	if i == -1 || j == -1 || i > j {
 		return "", errors.New("dbus: couldn't determine address of session bus")
 	}
 


Test patch:
diff --git a/exec_command_test.go b/exec_command_test.go
new file mode 100755
index 0000000..2b5350a
--- /dev/null
+++ b/exec_command_test.go
@@ -0,0 +1,61 @@
+package dbus
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"strconv"
+	"testing"
+)
+
+// How to mock exec.Command for unit tests
+// https://stackoverflow.com/q/45789101/10513533
+
+var mockedExitStatus = 0
+var mockedStdout string
+
+func fakeExecCommand(command string, args ...string) *exec.Cmd {
+	cs := []string{"-test.run=TestExecCommandHelper", "--", command}
+	cs = append(cs, args...)
+	cmd := exec.Command(os.Args[0], cs...)
+	es := strconv.Itoa(mockedExitStatus)
+	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1",
+		"STDOUT=" + mockedStdout,
+		"EXIT_STATUS=" + es}
+	return cmd
+}
+
+func TestExecCommandHelper(t *testing.T) {
+	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+		return
+	}
+
+	fmt.Fprintf(os.Stdout, os.Getenv("STDOUT"))
+	i, _ := strconv.Atoi(os.Getenv("EXIT_STATUS"))
+	os.Exit(i)
+}
+
+func TestDbusLaunchMultilineResponse(t *testing.T) {
+	mockedExitStatus = 0
+	mockedStdout = `process 7616: D-Bus library appears to be incorrectly set up; failed to read machine uuid: UUID file '/etc/machine-id' should contain a hex string of length 32, not length 0, with no other text
+See the manual page for dbus-uuidgen to correct this issue.
+DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-0SO9YZUBGA,guid=ac22f2f3b9d228496b4d4b935cae3417
+DBUS_SESSION_BUS_PID=7620
+DBUS_SESSION_BUS_WINDOWID=16777217`
+	execCommand = fakeExecCommand
+	defer func() { execCommand = exec.Command }()
+	expOut := ""
+	expErr := "dbus: couldn't determine address of session bus"
+
+	out, err := getSessionBusPlatformAddress()
+	if string(out) != expOut {
+		t.Errorf("Expected %q, got %q", expOut, string(out))
+	}
+	if err == nil {
+		t.Error("Excepted error, got none")
+	} else {
+		if err.Error() != expErr {
+			t.Errorf("Expected error to be %q, got %q", expErr, err.Error())
+		}
+	}
+}