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

cmd/vet: improve the frame pointer check #69838

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

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