Files
odidere/vendor/honnef.co/go/tools/staticcheck/sa1027/sa1027.go
2026-06-06 01:17:29 +00:00

77 lines
2.5 KiB
Go

package sa1027
import (
"fmt"
"go/types"
"honnef.co/go/tools/analysis/callcheck"
"honnef.co/go/tools/analysis/lint"
"honnef.co/go/tools/go/ir"
"honnef.co/go/tools/go/ir/irutil"
"honnef.co/go/tools/internal/passes/buildir"
"golang.org/x/tools/go/analysis"
)
var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
Analyzer: &analysis.Analyzer{
Name: "SA1027",
Requires: []*analysis.Analyzer{buildir.Analyzer},
Run: callcheck.Analyzer(checkAtomicAlignment),
},
Doc: &lint.RawDocumentation{
Title: `Atomic access to 64-bit variable must be 64-bit aligned`,
Text: `On ARM, x86-32, and 32-bit MIPS, it is the caller's responsibility to
arrange for 64-bit alignment of 64-bit words accessed atomically. The
first word in a variable or in an allocated struct, array, or slice
can be relied upon to be 64-bit aligned.
You can use the structlayout tool to inspect the alignment of fields
in a struct.`,
Since: "2019.2",
Severity: lint.SeverityWarning,
MergeIf: lint.MergeIfAny,
},
})
var Analyzer = SCAnalyzer.Analyzer
var checkAtomicAlignment = map[string]callcheck.Check{
"sync/atomic.AddInt64": checkAtomicAlignmentImpl,
"sync/atomic.AddUint64": checkAtomicAlignmentImpl,
"sync/atomic.CompareAndSwapInt64": checkAtomicAlignmentImpl,
"sync/atomic.CompareAndSwapUint64": checkAtomicAlignmentImpl,
"sync/atomic.LoadInt64": checkAtomicAlignmentImpl,
"sync/atomic.LoadUint64": checkAtomicAlignmentImpl,
"sync/atomic.StoreInt64": checkAtomicAlignmentImpl,
"sync/atomic.StoreUint64": checkAtomicAlignmentImpl,
"sync/atomic.SwapInt64": checkAtomicAlignmentImpl,
"sync/atomic.SwapUint64": checkAtomicAlignmentImpl,
}
func checkAtomicAlignmentImpl(call *callcheck.Call) {
sizes := call.Pass.TypesSizes
if sizes.Sizeof(types.Typ[types.Uintptr]) != 4 {
// Not running on a 32-bit platform
return
}
v, ok := irutil.Flatten(call.Args[0].Value.Value).(*ir.FieldAddr)
if !ok {
// TODO(dh): also check indexing into arrays and slices
return
}
T := v.X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct)
fields := make([]*types.Var, 0, T.NumFields())
for i := 0; i < T.NumFields() && i <= v.Field; i++ {
fields = append(fields, T.Field(i))
}
off := sizes.Offsetsof(fields)[v.Field]
if off%8 != 0 {
msg := fmt.Sprintf("address of non 64-bit aligned field %s passed to %s",
T.Field(v.Field).Name(),
irutil.CallName(call.Instr.Common()))
call.Invalid(msg)
}
}