Skip to content
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

x/tools/go/ssa: panic with Go 1.17 slice-to-array conversions #46987

Closed
ainar-g opened this issue Jun 30, 2021 · 17 comments
Closed

x/tools/go/ssa: panic with Go 1.17 slice-to-array conversions #46987

ainar-g opened this issue Jun 30, 2021 · 17 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@ainar-g
Copy link
Contributor

ainar-g commented Jun 30, 2021

I'm not sure if this is a bug or not, considering that Go 1.17 is not out yet, but then again, Go 1.17 Beta 1 is already out. The original issue is mvdan/unparam#55. Using golang.org/x/tools with the latest master version (v0.1.5-0.20210629191230-72e4d1bb8d47), ssa.(*Package).Build seems to panic with:

panic: in command-line-arguments.main: cannot convert *t0 ([]int) to *[4]int
Full panic message:
panic: in command-line-arguments.main: cannot convert *t0 ([]int) to *[4]int

goroutine 720 [running]:
golang.org/x/tools/go/ssa.emitConv(0xc0001de500, {0x705fd8, 0xc0007b02a0}, {0x700820, 0xc000205e90})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/emit.go:242 +0x7b9
golang.org/x/tools/go/ssa.(*builder).expr0(0x665ac0, 0xc0001de500, {0x700d40, 0xc00009b4c0}, {0x7, {0x700820, 0xc000205e90}, {0x0, 0x0}})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:573 +0x925
golang.org/x/tools/go/ssa.(*builder).expr(0x0, 0xc0001de500, {0x700d40, 0xc00009b4c0})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:530 +0x19f
golang.org/x/tools/go/ssa.(*builder).addr(0x665ac0, 0xc0001de500, {0x701340, 0xc000450db0}, 0x0)
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:417 +0xc8c
golang.org/x/tools/go/ssa.(*builder).expr(0x540eff, 0xc0001de500, {0x701340, 0xc000450db0})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:528 +0x145
golang.org/x/tools/go/ssa.(*builder).emitCallArgs(0xc00037b5c0, 0x7012b0, 0xc000495ce0, 0xc00009b500, {0x0, 0x0, 0x40cbe7})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:906 +0x7ed
golang.org/x/tools/go/ssa.(*builder).setCall(0x665ac0, 0xc0001de500, 0xc00009b500, 0xc0007b4240)
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:969 +0x94
golang.org/x/tools/go/ssa.(*builder).expr0(0x665ac0, 0xc0001de500, {0x700d40, 0xc00009b500}, {0x7, {0x7008c0, 0xc0000b4468}, {0x0, 0x0}})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:596 +0x1f8e
golang.org/x/tools/go/ssa.(*builder).expr(0x604d01744c010008, 0xc0001de500, {0x700d40, 0xc00009b500})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:530 +0x19f
golang.org/x/tools/go/ssa.(*builder).stmt(0xcab743c011aa6, 0xc0001de500, {0x700ef0, 0xc000205dd0})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:1988 +0x135b
golang.org/x/tools/go/ssa.(*builder).stmtList(0x9b0f931c01228310, 0x1a5400057420010c, {0xc00020aaa0, 0x2, 0x274002022ff228a})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:790 +0x67
golang.org/x/tools/go/ssa.(*builder).stmt(0xc0001de500, 0xc0001de500, {0x700ce0, 0xc000183800})
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:2105 +0x1331
golang.org/x/tools/go/ssa.(*builder).buildFunction(0x665f40, 0xc0001de500)
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:2198 +0x465
golang.org/x/tools/go/ssa.(*builder).buildFuncDecl(0x6652e0, 0xc00037b5c0, 0xc000183830)
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:2228 +0x154
golang.org/x/tools/go/ssa.(*Package).build(0xc00037b5c0)
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:2344 +0xd05
sync.(*Once).doSlow(0xc0004d97b8, 0x5fc89e)
	/home/ainar/go/go1.17/src/sync/once.go:68 +0xd2
sync.(*Once).Do(...)
	/home/ainar/go/go1.17/src/sync/once.go:59
golang.org/x/tools/go/ssa.(*Package).Build(...)
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:2263
golang.org/x/tools/go/ssa.(*Program).Build.func1(0x0)
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:2247 +0x4c
created by golang.org/x/tools/go/ssa.(*Program).Build
	/home/ainar/go/pkg/mod/golang.org/x/tools@v0.1.5-0.20210629191230-72e4d1bb8d47/go/ssa/builder.go:2246 +0x1a5

I've tested it using two analysers that use SSA, unparam and nilness, and both are panicking.

@gopherbot gopherbot added the Tools This label describes issues relating to any tools in the x/tools repository. label Jun 30, 2021
@gopherbot gopherbot added this to the Unreleased milestone Jun 30, 2021
@dmitshur dmitshur changed the title x/tools/ssa: panic with Go 1.17 slice-to-array conversions x/tools/go/ssa: panic with Go 1.17 slice-to-array conversions Jun 30, 2021
@dmitshur
Copy link
Contributor

CC @timothy-king, @findleyr via owners.

@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 30, 2021
@bcmills
Copy link
Contributor

bcmills commented Jun 30, 2021

This looks like a bug in the ssa package. Per https://tip.golang.org/doc/go1.17#reflect:

Checking the Type.ConvertibleTo method is no longer sufficient to guarantee that a call to Value.Convert will not panic. It may panic when converting []T to *[N]T if the slice's length is less than N.

I think the ssa package needs a similar change: an extra case in emitConv and the removal of some now-inaccurate claims that “[the Convert operation] cannot fail dynamically.”

@gopherbot
Copy link

Change https://golang.org/cl/332049 mentions this issue: go/ssa: allow conversion from slice to array pointer

@ainar-g
Copy link
Contributor Author

ainar-g commented Jul 1, 2021

Thanks, I can confirm that the current master fixes unparam. Are there any plans to release a tagged version of the golang.org/x/tools module to make automatic updates easier?

@timothy-king
Copy link
Contributor

[Apologies for the late reply and re-opening a closed issue.]

The current solution is definitely a short-term improvement and definitely fixed a bug.

I am not sure this is a good long term solution for ssa though. Having an ssa.Convert that can panic feels inconsistent with other parts of the ssa IR. The ssa IR distinguishes Go conversions into Convert, ChangeInterface, MakeInterface, and ChangeType. The slice to array conversion is the most similar to ChangeInterface IMO as this can panic. ChangeInterface got its own instruction type. Some possible alternatives for ssa to encode this change:

  1. Add a SliceToArray instruction and revert the changes to Convert.
  2. Merge some subset of Convert, ChangeInterface, and ChangeType into one Convert instruction and have helper functions to distinguish cases. (This will probably break users.)

FWIW the comment on Convert is now inaccurate after 332049 "One or both of those types is basic (but possibly named)." Slices and arrays are not basic. We can update this comment to be correct if we want to keep this change.

@bcmills I don't see how "[the Convert operation] cannot fail dynamically” was inaccurate. The ssa IR is not the same as conversion operators in Go. (It is inaccurate after 332049 though.)

@timothy-king timothy-king reopened this Jul 9, 2021
@cuonglm
Copy link
Member

cuonglm commented Jul 10, 2021

@timothy-king The doc of ChangeInterface claims that the operation cannot fails, though.

@timothy-king
Copy link
Contributor

@cuonglm That is a really good point. I think I was confused between ChangeInterface and TypeAssert's interface case. I feel like this makes having Convert maybe panic in one of its cases even more of an outlier.

@gopherbot
Copy link

Change https://golang.org/cl/333749 mentions this issue: all: add SliceToArrayPointer instruction

@dominikh
Copy link
Member

My first impression is that adding a new instruction will be a lot more disruptive to existing users of go/ssa than changing the dynamic behavior of the Convert instruction. Adding a new instruction will require most clients to be updated to handle the new instruction, whereas only few clients will care that Convert can now panic – and the clients that do care can inspect the types involved.

Note that my argument is purely based on the expected impact on users, not what's theoretically a cleaner abstraction.

@timothy-king
Copy link
Contributor

I am happy to factor the expected impact on users into this decision. For example, I am not supportive of deleting existing instructions to get a cast instruction that merges these cases. Adding a new instruction definitely requires more boilerplate and we should take this into account.

A concern with combining the slice-to-array-pointer into Convert is that people out there will have code that has violated assumptions. Off the top of head this can happen either because of:

  • the panic behavior,
  • the conversions are no longer Basic types, or
  • the list of conversions explicitly mentioned in the documentation expanded.

A data point is that https://golang.org/cl/333749 uncovered at least 1 instance of the 3rd case in go/ssa/interp/ops.go . That code would have silently failed until somebody ran it on code containing one of these casts.

OTOH adding a new instruction would mean that ssa users would now have an unmatched case in type switches. If they want to support the new operator they need to hunt down these spots. This seems somewhat reasonable if you want to support a new construct added in Go 1.17. Not the best, but maybe better?

So I don't think the solutions proposed so far won't require some action for ssa users to support it.

Happy to hear from users if they have a clear preference in either direction.

@dominikh
Copy link
Member

I don't have strong opinions on this. Both solutions have their pros and cons. Changing the behavior of Convert has the benefit that more code will keep working without change, but may introduce subtle bugs. Adding a new instruction means that ~all code needs to be updated to support the new instruction, but the change in behavior will be obvious, and it's the overall cleaner change.

the conversions are no longer Basic types

is an interesting, subtle point, and something that hasn't been changed in Convert's documentation in the first CL. The documentation still claims that at least one of the types is basic.

To be perfectly honest, I also mixed up Convert and ChangeType, and thinking more about it, slice to array conversion seems to sit somewhere between the two; another point in favour of introducing a new instruction.

@cuonglm
Copy link
Member

cuonglm commented Jul 15, 2021

@timothy-king @dominikh I'm leaning to add new instruction, as now I realize that mixing slice to array pointer in Convert seems make the current code more complicated.

For reference, the compiler SSA backend also add new op for this conversion.

@timothy-king
Copy link
Contributor

It has been a few days without more input. The conversation seems to be heading towards adding a SliceToArrayPointer instruction. Please speak up in the next couple of days if you would prefer a different solution.

@mdempsky
Copy link
Member

Adding a new instruction seems reasonable to me.

(Caveat: I don't use x/tools/go/ssa much.)

@timothy-king
Copy link
Contributor

timothy-king commented Jul 21, 2021

Looks like there are no [dissenting] updates here. I +2'd the change.

#47326 includes a list of golang.org packages that may need to be updated.

@gopherbot
Copy link

Change https://golang.org/cl/336489 mentions this issue: go/ssa/interp: handle nil slice convert to array pointer

gopherbot pushed a commit to golang/tools that referenced this issue Jul 31, 2021
Converting from nil slice to a zero length array pointer must be nil.

Updates golang/go#46987

Change-Id: I8894b92bd85fae8ea77bf01b92ee56f1a215a75b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/336489
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Tim King <taking@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Tim King <taking@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
@adonovan
Copy link
Member

adonovan commented May 26, 2022

I just came across SliceToArrayPointer today, and my first reaction was that this could have been compiled to existing instructions something like this:

return (*[n]T)(&slice[0]) // use *ssa.Convert here, since it can't fail

Of course this would need to be preceded by a bounds check that len(slice) >= n, but this neglects two edge cases:

  1. If slice is nil, the operation shouldn't fail, but should return a nil array pointer. This requires an additional preceding check.
  2. If n=0 and the slice is empty but non-nil, the &slice[0] operation will fail.

The take approach of adding a new operator seems reasonable.

@golang golang locked and limited conversation to collaborators May 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

9 participants