Skip to content

x/tools/gopls/internal/analysis/modernize: slices.Delete modernizer is unsound (clears out s[len:cap]) #73686

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
gandrejczuk opened this issue May 13, 2025 · 3 comments
Assignees
Labels
BugReport Issues describing a possible bug in the Go implementation. gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@gandrejczuk
Copy link

gandrejczuk commented May 13, 2025

gopls version

The issue is for latest modernize

go env

See below

What did you do?

$ cat test.go
// You can edit this code!
// Click here and start typing.
package main

import (
        "fmt"
)

func p(v int) *int {
        return &v
}

func main() {
        fmt.Println("Hello, 世界")
        x := []*int{p(1), p(2), p(3), p(4)}

        for i, member := range x {
                println(i)
                if *member == 2 {
                        x = append(x[:i], x[i+1:]...)
                        // Modernize will generate following code which will panic
                        // when last elemeny will be accessed
                        // x = slices.Delete(x, i, i+1)
                }
        }

        fmt.Printf("%v\n", x)
}
$ go run test.go
Hello, 世界
0
1
2
3
[0xc0000120f0 0xc000012100 0xc000012108]
$ go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix test.go
$ cat test.go
// You can edit this code!
// Click here and start typing.
package main

import (
        "fmt"
        "slices"
)

func p(v int) *int {
        return &v
}

func main() {
        fmt.Println("Hello, 世界")
        x := []*int{p(1), p(2), p(3), p(4)}

        for i, member := range x {
                println(i)
                if *member == 2 {
                        x = slices.Delete(x, i, i+1)
                        // Modernize will generate following code which will panic
                        // when last elemeny will be accessed
                        // x = slices.Delete(x, i, i+1)
                }
        }

        fmt.Printf("%v\n", x)
}
$ go run test.go
Hello, 世界
0
1
2
3
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4912d7]

goroutine 1 [running]:
main.main()
        test.go:20 +0x1d7
exit status 2

What did you see happen?

Hello, 世界
0
1
2
3
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4930b7]

goroutine 1 [running]:
main.main()
	/tmp/sandbox3797330105/prog.go:20 +0x1d7

What did you expect to see?

Hello, 世界
0
1
2
3
[0xc000010080 0xc000010090 0xc000010098]

Program exited.

Editor and settings

No response

Logs

No response

@gandrejczuk gandrejczuk added gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository. labels May 13, 2025
@gopherbot gopherbot added this to the Unreleased milestone May 13, 2025
@adonovan adonovan changed the title x/tools/gopls/internal/analysis/modernize: Modernize might generate panicking code x/tools/gopls/internal/analysis/modernize: slices.Delete modernizer is unsound (clears out s[len:cap]) May 13, 2025
@adonovan adonovan added the BugReport Issues describing a possible bug in the Go implementation. label May 13, 2025
@adonovan
Copy link
Member

adonovan commented May 13, 2025

Thanks for the bug report and test case. The fundamental issue here is that slices.Delete clears out the array elements between len and cap (or the new length and the old), ostensibly to aid garbage collection, whereas append does not, and without further analysis--that is I think far beyond our scope--it is impossible to tell whether they are needed.

Here's a more minimal example:

https://go.dev/play/p/a_-7zP0N-Xq

	{
		slice := []int{0, 1, 2, 3, 4, 5}
		orig := slice
		slice = append(slice[:2], slice[3:]...)
		fmt.Println(orig) // "[0 1 3 4 5 5]"
	}
	{
		slice := []int{0, 1, 2, 3, 4, 5}
		orig := slice
		slice = slices.Delete(slice, 2, 3)
		fmt.Println(orig) // "[0 1 3 4 5 0]"
	}

I propose we disable the slices.Delete modernizer. Sigh.

@adonovan adonovan modified the milestones: Unreleased, gopls/v0.19.0 May 13, 2025
@adonovan adonovan self-assigned this May 16, 2025
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/673516 mentions this issue: gopls/internal/analysis/modernize: disable slicesdelete pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugReport Issues describing a possible bug in the Go implementation. gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

4 participants