Repository: go-delve/delve

Issue:
E08 during memory read for packet
Please answer the following before submitting your issue:

Note: Please include any substantial examples (debug session output,
stacktraces, etc) as linked gists.

If this is about source listing not showing up (or breakpoints not being
accepted) while running in a container please read our
[FAQ](https://github.com/go-delve/delve/blob/master/Documentation/faq.md#substpath)
first.

1. What version of Delve are you using (`dlv version`)?
```
❯ dlv version
Delve Debugger
Version: 1.21.2
Build: $Id: 98f8ab2662d926245917ade2f2bb38277315c7fc $
```
2. What version of Go are you using? (`go version`)?
```
❯ go version
go version go1.21.1 darwin/amd64
```
3. What operating system and processor architecture are you using?
```
macOS Sonoma 14.1 amd64
```
4. What did you do?
When trying to debug a test that contains a struct with a non-pointer object that has a function with a pointer receiver defined, interacting with that object causes all locals to return `unreadable could not read string pointer protocol error E08 during memory read for packet`.

Steps:
```
b TestHi:13
c
p c
```
5. What did you expect to see?
I expected to able to print values for locals.
6. What did you see instead?
I see all values being returned as error E08.

Log file and files to reproduce error are [here](https://gist.github.com/dhoizner/d728ca57bfd3a4cf1ebc287bc96ce8f7).

Changing `Thing` to be `*Thing`  on [line 11](https://gist.github.com/dhoizner/d728ca57bfd3a4cf1ebc287bc96ce8f7#file-foo_test-go-L11) resolves the error.

Discussion:
@aarzilli: This is a bug in the compiler, which was fixed (I think unintentionally) by 505e50b1e34cdf6dff29615a076e26fb0780d10d in go1.22

cc @dr2chase, you might be interested in this. Do you think something should be done for go1.21, a backport seems unlikely to me. @aarzilli: PS. the associated pull request has a reduced reproduction for this bug: https://github.com/go-delve/delve/pull/3553@dhoizner: > This is a bug in the compiler, which was fixed (I think unintentionally) by 505e50b1e34cdf6dff29615a076e26fb0780d10d in go1.22
> 
> cc @dr2chase, you might be interested in this. Do you think something should be done for go1.21, a backport seems unlikely to me.

thanks for digging into this @aarzilli!@PeterGerma: > This is a bug in the compiler, which was fixed (I think unintentionally) by 505e50b1e34cdf6dff29615a076e26fb0780d10d in go1.22
> 
> cc @dr2chase, you might be interested in this. Do you think something should be done for go1.21, a backport seems unlikely to me.

Same issue when on Go 1.22@carlosmiei: > > This is a bug in the compiler, which was fixed (I think unintentionally) by 505e50b1e34cdf6dff29615a076e26fb0780d10d in go1.22
> > cc @dr2chase, you might be interested in this. Do you think something should be done for go1.21, a backport seems unlikely to me.
> 
> Same issue when on Go 1.22

@PeterGerma Same issue as well@zhaozkTHU: > > This is a bug in the compiler, which was fixed (I think unintentionally) by 505e50b1e34cdf6dff29615a076e26fb0780d10d in go1.22
> > cc [@dr2chase](https://github.com/dr2chase), you might be interested in this. Do you think something should be done for go1.21, a backport seems unlikely to me.
> 
> Same issue when on Go 1.22

Same issue in go1.24.2 darwin/arm64@SlavaUtesinov: Same issue for go1.25.0 darwin/arm64@balleriniGsped: we just run in the same problem on 1.25.1 darwin/amd64 WITHOUT calling a method with a pointer receiver (our type doesn't have any pointer receiver at all). Just assigning the value of the structure to another variable make it so that the new variable value is all corrupted. This is happening in a test, starting from json.Unmarshal() of the values. Funny enough, the same exact code form the same exact json, just 10 lines above works as expected

Solution patch:
diff --git a/_fixtures/issue3548.go b/_fixtures/issue3548.go
new file mode 100644
index 00000000..e3f10537
--- /dev/null
+++ b/_fixtures/issue3548.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"fmt"
+)
+
+type Thing struct {
+	str string
+}
+
+func (d *Thing) Test() bool {
+	return d != nil
+}
+
+func callit(f func()) {
+	f()
+}
+
+func main() {
+	cases := []struct {
+		name  string
+		thing Thing
+	}{
+		{
+			name:  "Success",
+			thing: Thing{str: "hello"},
+		},
+	}
+
+	for _, c := range cases {
+		callit(func() {
+			fmt.Println("hello", c.thing.Test())
+		})
+	}
+}



Test patch:
diff --git a/pkg/proc/variables_test.go b/pkg/proc/variables_test.go
index 0d9dc98f..b90abaf1 100644
--- a/pkg/proc/variables_test.go
+++ b/pkg/proc/variables_test.go
@@ -1722,3 +1722,23 @@ func TestBadUnsafePtr(t *testing.T) {
 		}
 	})
 }
+
+func TestCapturedVariable(t *testing.T) {
+	// Checks that variables captured by a closure (that are not pointers) are
+	// readable. See issue #3548.
+	// This was broken in Go 1.21 due to a compiler bug.
+	if goversion.VersionAfterOrEqual(runtime.Version(), 1, 21) && !goversion.VersionAfterOrEqual(runtime.Version(), 1, 22) {
+		t.Skip("broken")
+	}
+	withTestProcess("issue3548", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
+		setFileBreakpoint(p, t, fixture.Source, 32)
+		assertNoError(grp.Continue(), t, "Continue()")
+		v := evalVariable(p, t, "c")
+		assertVariable(t, v, varTest{
+			name:         "c",
+			preserveName: true,
+			value:        "struct { main.name string; main.thing main.Thing } {name: \"Success\", thing: main.Thing {str: \"hello\"}}",
+			varType:      "struct { main.name string; main.thing main.Thing }",
+		})
+	})
+}