Skip to content

cmd/vet: improve the frame pointer check #69838

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

Open
nsrip-dd opened this issue Oct 10, 2024 · 7 comments
Open

cmd/vet: improve the frame pointer check #69838

nsrip-dd opened this issue Oct 10, 2024 · 7 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FeatureRequest Issues asking for a new feature that does not need a proposal. help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@nsrip-dd
Copy link
Contributor

The framepointer check from go vet is currently quite conservative. Since Go 1.21, frame pointers have become more load-bearing in the Go runtime. They're now used on amd64 and arm64 to collect call stacks for the execution tracer and the block & mutex profilers. Now, frame pointer bugs can crash Go programs, whereas before they would merely result in broken call stacks for external profilers like Linux perf.

For example, #69629 was ultimately caused by a bug in programatically-generated amd64 assembly which clobbered the frame pointer register. As of Go 1.23.2, go vet misses that frame pointer bug. This is because the frame pointer is clobbered after a branch instruction, and the check aborts if it reaches a branch.

I think we should try to expand the number of bugs the framepointer check can catch. For example, arm64 support would be good. We also might be able to drop that branch check, or flag assembly that writes to rbp without a push rbp near the beginning and a pop rbp before returning. These kinds of ideas should of course be tested against existing open source Go assembly code, since I assume there is little (if any?) tolerance for false positives in go vet tools.

@cherrymui cherrymui added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. FeatureRequest Issues asking for a new feature that does not need a proposal. labels Oct 10, 2024
@cherrymui cherrymui added this to the Backlog milestone Oct 10, 2024
@cherrymui cherrymui added the compiler/runtime Issues related to the Go compiler and/or runtime. label Oct 10, 2024
@mknyszek mknyszek modified the milestones: Backlog, Unplanned Oct 30, 2024
@prattmic
Copy link
Member

prattmic commented Dec 10, 2024

I ran an analysis on modules with 10 or more imports on the module proxy (~25k modules).

Normally I'd provide sampled results, but there are few enough results that these are the full results.

As a baseline, here are findings of the framepointer vet check at tip:

github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_avx2_amd64.s#L13322
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_avx2_amd64.s#L18
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_avx2_amd64.s#L20569
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_avx2_amd64.s#L25887
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_avx2_amd64.s#L5858
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_sse4_amd64.s#L13800
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_sse4_amd64.s#L16
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_sse4_amd64.s#L20509
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_sse4_amd64.s#L26381
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/base_arithmetic_sse4_amd64.s#L7209
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/cast_numeric_avx2_amd64.s#L37
github.com/apache/arrow/go/[email protected]/arrow/compute/internal/kernels/cast_numeric_sse4_amd64.s#L48
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_avx2_amd64.s#L24
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_avx2_amd64.s#L272
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_avx2_amd64.s#L497
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_avx2_amd64.s#L686
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_avx2_amd64.s#L795
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_sse4_amd64.s#L16
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_sse4_amd64.s#L250
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_sse4_amd64.s#L468
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_sse4_amd64.s#L699
github.com/apache/arrow/go/[email protected]/internal/utils/min_max_sse4_amd64.s#L855
github.com/apache/arrow/go/[email protected]/parquet/internal/bmi/bitmap_bmi2_amd64.s#L29
<same findings on older versions of github.com/apache/arrow/go>
github.com/bwesterb/[email protected]/edwards25519/field_amd64.s#L15
github.com/cloudflare/[email protected]/scan/crypto/md5/md5block_amd64.s#L17
github.com/dgraph-io/[email protected]/z/simd/search_amd64.s#L15
github.com/dgryski/[email protected]/sip13_amd64.s#L13
github.com/dgryski/[email protected]/sip13_amd64.s#L172
github.com/emmansun/[email protected]/zuc/asm_amd64.s#L502
github.com/emmansun/[email protected]/zuc/asm_amd64.s#L649
github.com/gtank/[email protected]/internal/radix51/fe_mul_amd64.s#L20
github.com/hellobchain/[email protected]/sm2/sm2_asm_amd64.s#L1536
github.com/hellobchain/[email protected]/sm2/sm2_asm_amd64.s#L1690
github.com/Hyperledger-TWGC/[email protected]/sm2/sm2p256_amd64.s#L1606
github.com/Hyperledger-TWGC/[email protected]/sm2/sm2p256_amd64.s#L1821
github.com/nicocha30/[email protected]/pkg/ring0/entry_amd64.s#L404
github.com/outcaste-io/[email protected]/z/simd/search_amd64.s#L15
github.com/phoreproject/[email protected]/primitivefuncs_amd64.s#L102
github.com/phoreproject/[email protected]/primitivefuncs_amd64.s#L1474
github.com/phoreproject/[email protected]/primitivefuncs_amd64.s#L1502
github.com/RyuaNerin/[email protected]/lsh256/asm_amd64_avx2.s#L550
github.com/RyuaNerin/[email protected]/lsh256/asm_amd64_avx2.s#L63
github.com/RyuaNerin/[email protected]/lsh256/asm_amd64_ssse3.s#L32
github.com/RyuaNerin/[email protected]/lsh256/asm_amd64_ssse3.s#L715
github.com/RyuaNerin/[email protected]/lsh512/asm_amd64_avx2.s#L798
github.com/vmware/[email protected]/bdoor/bdoor_amd64.s#L15
github.com/vmware/[email protected]/bdoor/bdoor_amd64.s#L36
github.com/vmware/[email protected]/bdoor/bdoor_amd64.s#L57
github.com/vmware/[email protected]/bdoor/bdoor_amd64.s#L78
github.com/ziutek/[email protected]/dasum_amd64.s#L3
github.com/ziutek/[email protected]/daxpy_amd64.s#L3
github.com/ziutek/[email protected]/dcopy_amd64.s#L10
github.com/ziutek/[email protected]/ddot_amd64.s#L3
github.com/ziutek/[email protected]/dnrm2_amd64.s#L3
github.com/ziutek/[email protected]/drot_amd64.s#L3
github.com/ziutek/[email protected]/dscal_amd64.s#L3
github.com/ziutek/[email protected]/dswap_amd64.s#L6
github.com/ziutek/[email protected]/idamax_amd64.s#L3
github.com/ziutek/[email protected]/isamax_amd64.s#L3
github.com/ziutek/[email protected]/sasum_amd64.s#L3
github.com/ziutek/[email protected]/saxpy_amd64.s#L3
github.com/ziutek/[email protected]/scopy_amd64.s#L10
github.com/ziutek/[email protected]/sdot_amd64.s#L3
github.com/ziutek/[email protected]/sdsdot_amd64.s#L3
github.com/ziutek/[email protected]/snrm2_amd64.s#L3
github.com/ziutek/[email protected]/srot_amd64.s#L3
github.com/ziutek/[email protected]/sscal_amd64.s#L3
github.com/ziutek/[email protected]/sswap_amd64.s#L3
github.com/ztalab/[email protected]/scan/crypto/md5/md5block_amd64.s#L17
github.com/ztdbp/[email protected]/scan/crypto/md5/md5block_amd64.s#L17

The new findings from eliminating the bail out on control flow:

github.com/bamiaux/[email protected]/vscalers_amd64.s#L1019
github.com/bamiaux/[email protected]/vscalers_amd64.s#L1341
github.com/bamiaux/[email protected]/vscalers_amd64.s#L149
github.com/bamiaux/[email protected]/vscalers_amd64.s#L305
github.com/bamiaux/[email protected]/vscalers_amd64.s#L37
github.com/bamiaux/[email protected]/vscalers_amd64.s#L503
github.com/bamiaux/[email protected]/vscalers_amd64.s#L741
github.com/consensys/[email protected]/ecc/bls12-381/internal/fptower/e2_amd64.s#L449
github.com/consensys/[email protected]/ecc/bls24-315/internal/fptower/e2_amd64.s#L406
github.com/consensys/[email protected]/ecc/bn254/internal/fptower/e2_amd64.s#L714
github.com/dgryski/[email protected]/metro_amd64.s#L205
github.com/dgryski/[email protected]/metro_amd64.s#L21
github.com/emmansun/[email protected]/sm4/gcm_amd64.s#L826
github.com/enceve/[email protected]/chacha20/chacha/chacha_amd64.s#L213
github.com/fumiama/[email protected]/base14_amd64.s#L137
github.com/fumiama/[email protected]/base14_amd64.s#L16
github.com/klauspost/[email protected]/galois_gen_amd64.s#L103710
github.com/klauspost/[email protected]/galois_gen_amd64.s#L104213
github.com/klauspost/[email protected]/galois_gen_amd64.s#L104533
github.com/klauspost/[email protected]/galois_gen_amd64.s#L10918
github.com/klauspost/[email protected]/galois_gen_amd64.s#L11247
github.com/klauspost/[email protected]/galois_gen_amd64.s#L11535
github.com/klauspost/[email protected]/galois_gen_amd64.s#L17922
github.com/klauspost/[email protected]/galois_gen_amd64.s#L26231
github.com/klauspost/[email protected]/galois_gen_amd64.s#L35773
github.com/klauspost/[email protected]/galois_gen_amd64.s#L46607
github.com/klauspost/[email protected]/galois_gen_amd64.s#L58798
github.com/klauspost/[email protected]/galois_gen_amd64.s#L72411
github.com/klauspost/[email protected]/galois_gen_amd64.s#L87270
github.com/klauspost/[email protected]/galois_gen_amd64.s#L87838
github.com/klauspost/[email protected]/galois_gen_amd64.s#L88196
github.com/minio/[email protected]/md5block_amd64.s#L18
github.com/nicocha30/[email protected]/pkg/ring0/entry_amd64.s#L467
github.com/nicocha30/[email protected]/pkg/ring0/entry_amd64.s#L585
github.com/RyuaNerin/[email protected]/lsh256/asm_amd64_avx2.s#L23
github.com/RyuaNerin/[email protected]/lsh256/asm_amd64_sse2.s#L23
github.com/RyuaNerin/[email protected]/lsh512/asm_amd64_avx2.s#L95
github.com/RyuaNerin/[email protected]/lsh512/asm_amd64_sse2.s#L88
github.com/skycoin/[email protected]/src/cipher/chacha20poly1305/chacha20poly1305_amd64.s#L271
github.com/Sora233/[email protected]/internal/encryption/t544/encryption_amd64.s#L476
gitlab.com/yawning/[email protected]/internal/hardware/impl_amd64.s#L1032
leb.io/[email protected]/aeshash.s#L67

@randall77
Copy link
Contributor

I don't understand, for example, this one: https://go-mod-viewer.appspot.com/github.com/klauspost/[email protected]/galois_gen_amd64.s#L11535

It is in a function with a nonzero frame size, so we already spill/restore BP. The vet check shouldn't be checking such functions.
(The check here: https://cs.opensource.google/go/x/tools/+/master:go/analysis/passes/framepointer/framepointer.go;drc=74c9cfe4d22faa696baabeea02df6493b15e8c79;l=68 . Maybe that check is wrong? Perhaps it doesn't deactivate correctly from the previous function?)

@nsrip-dd
Copy link
Contributor Author

@prattmic and I discussed this on Gopher slack, small mistake in the change to the analyzer. If the branch check (which also checks for RET) is dropped with no other changes, then the analyzer stays "active" once it sees a frameless function for the first time. So in that example, it's looking for BP writes because the preceding function was frameless. We can tweak it to reset the active flag for every TEXT line.

@nsrip-dd
Copy link
Contributor Author

Excluding the false positives for functions with frames, the rest seem to mostly be true positives. One exception is https://go-mod-viewer.appspot.com/github.com/nicocha30/[email protected]/pkg/ring0/entry_amd64.s#L467, which saves the frame pointer in a macro. Unless the vet check does preprocessing it's going to miss things like that.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/635338 mentions this issue: go/analysis/passes/framepointer: support arm64

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/640075 mentions this issue: go/analysis/passes/framepointer: only stop on unconditional branches

gopherbot pushed a commit to golang/tools that referenced this issue Feb 7, 2025
Add arm64 support to the framepointer vet check. Essentially use the
same logic as the amd64 check: in instruction order, look at functions
without frames, and fail if the functions write to the frame pointer
register before reading it. Stop looking at a function on the first
branch instruction.

For golang/go#69838

Change-Id: If69be8a6eb5f9275df602c2c2ff644c338deaef2
Reviewed-on: https://go-review.googlesource.com/c/tools/+/635338
Reviewed-by: Cherry Mui <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Carlos Amedee <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FeatureRequest Issues asking for a new feature that does not need a proposal. help wanted NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

7 participants