This is present on master, for example on go version go1.25-devel_8131635e5a
and bisecting the problem leads to 988a20c8c5e2c9eb49f8749e5ee94ce3c964fe59.
The following piece of code:
1 package main
2
3 import (
4 "fmt"
5 "runtime"
6 )
7
8 func main() {
9 a := 0
10 {
11 a := 1
12 runtime.Breakpoint()
13 fmt.Println(a)
14 }
15 fmt.Println(a)
16 }
(also found at https://github.com/go-delve/delve/blob/4a2a6e1aeb90f92eb17f5f055bfe5d7f066a008d/_fixtures/testshadow.go)
When compiled with -gcflags='-N -l'
will produce a debug_line table such that execution proceeds as such: line 8, 9, 11, 12, 11 again, 13, 9 again, finally 15. Lines 9 and 11 are executed twice each.
The more variables initialized to a constant there are the more execution will jump back and forth, for example see https://github.com/go-delve/delve/blob/4a2a6e1aeb90f92eb17f5f055bfe5d7f066a008d/_fixtures/testvariables.go.
Now, this problem is probably way more prevalent in delve's test suite than in code so I'm probably the person who is most inconvenienced by this in the universe, nevertheless, it is a regression that I imagine will affect others as well.
cc @thepudds, @randall77 because of the bisect cc @dr2chase because it's about line numbers
Comment From: thepudds
Hi @aarzilli, thanks for reporting this. I'll take a look shortly.
Comment From: gopherbot
Change https://go.dev/cl/687815 mentions this issue: cmd/compile/internal/escape: improve line number debug info when rewriting with literals
Comment From: thepudds
Hi @aarzilli, I sent https://go.dev/cl/687815.
I added a couple tests of the resulting debug_line table as part of that. One test uses a simplified version of your first example and it uses fmt.Println
. That test is exercising the interface conversion allocation optimizations from https://go.dev/cl/649079. I also added a test that uses make
on a slice with non-constant argument, which exercises a related optimization.
It looks like at least one of the problematic examples you supplied is tested by the delve/pkg/proc
package.
Using go1.25rc2
, if I clone the delve repo (current master / 4a2a6e1aeb), and do:
$ go1.25rc2 test ./pkg/proc
I can see that fail with ~3K lines of output that ends with:
[...]
about to panic
first: 10 second: 20
foo
3 2.1 map[2.1:3]
a string
FAIL
FAIL github.com/go-delve/delve/pkg/proc 141.648s
If I use my https://go.dev/cl/687815, it seems that the delve/pkg/proc
package now passes:
$ go install golang.org/dl/gotip@latest
$ gotip download 687815
$ gotip test ./pkg/proc
ok github.com/go-delve/delve/pkg/proc 151.656s
Using ./...
from the delve repo root also seems to pass with my CL:
$ gotip test ./...
I also tried stepping through using the dlv
command line using your complete first example above with go1.25rc2
. (I did break main.main
, followed by next
-ing repeatedly through main
). I could see it hop backwards then forwards using go1.25rc2
, but with my CL it seemed to just progress forwards as I next
-ed through main
, without going backwards.
Are there other things to test beyond that? (For example, I don't know if the delve tests have some -long
flag or similar, or maybe you have some other examples that are not covered by what I outlined above, etc.).
The CL is still WIP and I want to look at it a little more, but wanted to give a quick update here. One thing I will probably try is adding at least one more test that covers struct literals. (Not sure if those have a similar debug_line table issue, but I made some related interface conversion allocation optimizations for struct literals earlier in the Go 1.25 dev cycle).
Feel free to try the CL if you have time. And thanks again for the report!
Comment From: aarzilli
There is no -long
option but _scripts/make.go runs the same tests in a couple of different configurations. I've tried your patch and all tests pass with it.