-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
runtime: "found pointer to free object" on Windows #44900
Comments
Marking as release-blocker at least until we understand whether this is a regression. |
Could this be related to golang.org/cl/297389? All of those failure commits were after that CL was merged. /cc @zx2c4 |
https://build.golang.org/log/dcb6544b3a999b160ede916b98d49fad0d55465a Plan 9 isn't running any Windows code, so I don't think it's related. |
Fair point. Though there could also be separate issues affecting different platforms. The plan9-arm failures in #44903 date back to mid 2020, whereas the windows failures are all more recent. That makes me think there must have been something that affected Windows recently. E.g., I'm not saying that CL is incorrect, but maybe it's now tickling an underlying compiler/runtime issue that's been affecting plan9-arm and solaris too. |
Hmm... could be. Something like this should mirror minimally what's going on with defers and unsafe.Pointer and the GC in that commit: package main
import (
"unsafe"
)
func main() {
a := make([]unsafe.Pointer, 2)
defer func() { println(a[1]) }()
a[0] = unsafe.Pointer(&struct{ _ int }{})
a[1] = unsafe.Pointer(&struct{ _ int }{})
println(a[0])
} |
These all say elemsize=32. Does that mean it's the result of an allocation of structs size 24 in a list? That seems to be the case, because the code goes onto say: for i := uintptr(0); i < s.nelems; i++ {
addr := s.base() + i*s.elemsize So in that case, what struct of size 24 is being allocated in a list? It can't be those unsafe.Pointers, where elemsize=8. |
I think you meant they all say elemsize=24? If so, yeah, the error message is that there's an object that was allocated on heap of size 24 bytes. Also, that GC previously ran and didn't find any references to the object and marked it dead; but a later run found a pointer to it again. This could happen if a user converts a pointer to uintptr and then back to unsafe.Pointer in an unsafe way (hence the checkptr recommendation in the error message). But of course the compiler/runtime could be getting something wrong too. |
If I understand correctly, the calls to updateProcThreadAttribute are making Windows (i.e., non-Go code) store pointers into the []unsafe.Pointer slice allocated in newProcThreadAttributeList? If so, I suspect that's the issue then. It's not enough for the heap bits to be allocated as pointer memory. Mutators also need to know to use write barriers when storing pointers into memory during certain GC phases. Windows wouldn't know to do that. |
I also suspect the 24-byte object that's being lost and found again is the |
updateProcThreadAttribute is an Windows API that does not document it's implementation The doco says I am still against submitted CL https://go-review.googlesource.com/c/go/+/297389/ because it is too complicated. All we need to do here is to make sure that fd slice lives until the end of StartProcess. So something like what I suggested at https://go-review.googlesource.com/c/go/+/297391/1/src/syscall/exec_windows.go#253 should work. Alex |
Ahh, I wasn't aware of that (and apparently nobody mentioned that on the rather lengthy CL). I'll send two new CLs to fix this the straight forward way for go/src/syscall and a more usable way for x/sys/windows. |
Change https://golang.org/cl/300349 mentions this issue: |
Change https://golang.org/cl/300369 mentions this issue: |
Those two CLs should address the matter. |
This should actually still be open as https://golang.org/cl/300369 hasn't been merged yet. |
It turns out that if you write Go pointers to Go memory, the Go compiler must be involved so that it generates various calls to the GC in the process. Letting Windows write Go pointers to Go memory violated this. We fix this by having all the Windows-managed memory be just a boring []byte blob. Then, in order to prevent the GC from prematurely cleaning up the pointers referenced by that []byte blob, or in the future moving memory and attempting to fix up pointers, we copy the data to the Windows heap and then maintain a little array of pointers that have been used. Every time the Update function is called with a new pointer, we make a copy and append it to the list. Then, on Delete, we free the pointers from the Windows heap. Updates golang/go#44900. Change-Id: I42340a93fd9f6b8d10340634cf833fd4559a5f4f Reviewed-on: https://go-review.googlesource.com/c/sys/+/300369 Trust: Jason A. Donenfeld <[email protected]> Run-TryBot: Jason A. Donenfeld <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
This came to my attention via a
windows-amd64-longtest
failure in a TryBot (https://storage.googleapis.com/go-build-log/ef7da83e/windows-amd64-longtest_1a18709a.log).2021-03-09T20:35:41-48ddf70/windows-amd64-longtest
2021-03-09T18:35:29-48895d0/windows-amd64-longtest
2021-03-05T18:47:09-c082f9f/windows-amd64-longtest
The symptom resembles #44614 (@randall77 @mdempsky), but that was marked fixed before the first known Windows failure occurred.
CC @mknyszek @aclements @jeremyfaller
The text was updated successfully, but these errors were encountered: