-
-
Notifications
You must be signed in to change notification settings - Fork 669
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
go_test: I/O in package init function fails after Go 1.21 due to initialization order change #3675
Comments
Thanks for the mini design doc! I agree that it's worth fixing this at least if we can find a solution that isn't too complex. I personally prefer 2 as it's really simple if it works and should only really break if someone else is also hacking hard (and I won't be sorry for them). According to https://go.dev/ref/spec#Packages, either |
Im also leaning toward 2. I don't think of it as a hack though, it's a solution that comply to current Go spec. And the spec was made intentionally simple so we should not try to make the fix complicated. If there are cases that 2 would not work well for, we could revisit 3 in the future as well. |
2 is also my preference. I'll send a fix early next week. |
Go 1.21 clarified package initialization order and changed behavior: packages with lexicographically lower paths are now initialized earlier. We need bzltestutil to initialize before user packages so it can change to the correct directory. To accomplish this, we set an importmap prefix that starts with '+', the lowest allowed character. Fixes bazel-contrib#3675
Go 1.21 clarified package initialization order and changed behavior: packages with lexicographically lower paths are now initialized earlier. We need bzltestutil to initialize before user packages so it can change to the correct directory. To accomplish this, we set an importmap prefix that starts with '+', the lowest allowed character. Fixes #3675
Sorry for missing this the first time in bazel-contrib#3679. The package init algorithm was a little different than I thought, and I imagined that Go 1.21 was already in use, so I didn't look into it deeply. The problem was that even though "+initfirst/.../bzlutil" sorts lower than other packages, it imports "sync" and a number of other std packages that sort higher than "github.com/..." user packages. If a user package has no dependencies, it's eligible to be initialized before bzltestutil, even with the lower name. I moved the init function with the os.Chdir call into a separate tiny package that only imports "os" and "runtime". It should get initialized much earlier. Fixes bazel-contrib#3675
* bzltestutil: move os.Chdir call into new package Sorry for missing this the first time in #3679. The package init algorithm was a little different than I thought, and I imagined that Go 1.21 was already in use, so I didn't look into it deeply. The problem was that even though "+initfirst/.../bzlutil" sorts lower than other packages, it imports "sync" and a number of other std packages that sort higher than "github.com/..." user packages. If a user package has no dependencies, it's eligible to be initialized before bzltestutil, even with the lower name. I moved the init function with the os.Chdir call into a separate tiny package that only imports "os" and "runtime". It should get initialized much earlier. Fixes #3675 * address review feedback * not
What version of rules_go are you using?
v0.41.0 but also reproduced at
5206498b4f67ff3e6a9222a923cf67ff5191754e
(master as of 2023-09-01).What version of gazelle are you using?
n/a
What version of Bazel are you using?
7.0.0-pre.20230530.3
Does this issue reproduce with the latest releases of all the above?
yes
What operating system and processor architecture are you using?
darwin arm64
Any other potentially useful information about your toolchain?
n/a
What did you do?
We're in the process of upgrading to Go 1.21, running all our tests including those from vendored packages.
What did you expect to see?
All tests pass, as before.
What did you see instead?
A couple vendored tests are failing for us as part of that upgrade, for example
github.com/klauspost/compress/huff0
. This fails incompress_test.go
because the test reads a testdata file in its init function.I think we can all agree that doing I/O in an init function is bad and anti-social. Regrettably there are no test-I/O cops, so people do this somewhat frequently.
This is caused by the change documented in the Go 1.21 release notes:
go_test
links tests withgo/tools/bzltestutil
. Theinit
function in that package is responsible for changing into the test directory from the repository root directory where Bazel starts the test process. I added some print statements and confirmed thatbzltestutil
's init function does not run in the test above before it panics.I see there's some discussion already in #3643. #3655 also adds comments documenting the change.
It would be great to fix the regression here. I'm happy to work on a fix, but this is definitely the kind of change that needs some discussion. Some ideas:
bzltestutil
. That would add a dependency edge, forcingbzltestutil
to be initialized first. It might still be initialized before other transitively imported packages though, so this may not be a sufficient fix.bzltestutil
to something that sorts before anything else. Of course this is an egregious hack, but it's lightweight and would work reasonably well under the new semantics.bzltestutil/wrap.go
). Although it would be cleaner to separate that, I think it would mean an extra link action pergo_test
.cc @fmeum @sluongng
The text was updated successfully, but these errors were encountered: