From 8dbcc66f33bb0acac38e8777732a369d38151a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Rainone?= Date: Tue, 22 Jan 2019 10:20:45 +0100 Subject: [PATCH] go/analysis/passes/atomicalign: handle pointers to struct The atomicalign checker detects non-64-bit aligned struct field arguments to sync/atomic functions but currently misses out cases where the struct variable identifier is a pointer to struct. This is very common as it happens when the 64-bit field is accessed in a method with pointer receiver, where the struct is itself the method receiver. Add some tests to cover that new case. While I'm at it, fix some typos. Change-Id: I582cf5b7286b11285010f085045f58dc636ef3ee Reviewed-on: https://go-review.googlesource.com/c/158999 Reviewed-by: Alan Donovan --- go/analysis/passes/atomicalign/atomicalign.go | 12 +++++++----- .../passes/atomicalign/testdata/src/a/a.go | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/go/analysis/passes/atomicalign/atomicalign.go b/go/analysis/passes/atomicalign/atomicalign.go index d3fc3e2d..0326bf53 100644 --- a/go/analysis/passes/atomicalign/atomicalign.go +++ b/go/analysis/passes/atomicalign/atomicalign.go @@ -21,7 +21,7 @@ import ( var Analyzer = &analysis.Analyzer{ Name: "atomicalign", - Doc: "check for non-64-bits-aligned arguments to sync/atomic functions", + Doc: "check for non-64-bit-aligned arguments to sync/atomic functions", Requires: []*analysis.Analyzer{inspect.Analyzer}, Run: run, } @@ -70,7 +70,7 @@ func run(pass *analysis.Pass) (interface{}, error) { } func check64BitAlignment(pass *analysis.Pass, funcName string, arg ast.Expr) { - // Checks the argument is made of the address operator (&) applied to + // Checks the argument is made of the address operator (&) applied // to a struct field (as opposed to a variable as the first word of // uint64 and int64 variables can be relied upon to be 64-bit aligned. unary, ok := arg.(*ast.UnaryExpr) @@ -80,16 +80,18 @@ func check64BitAlignment(pass *analysis.Pass, funcName string, arg ast.Expr) { // Retrieve the types.Struct in order to get the offset of the // atomically accessed field. - sel, ok := unary.X.(*ast.SelectorExpr) + selector, ok := unary.X.(*ast.SelectorExpr) if !ok { return } - tvar, ok := pass.TypesInfo.Selections[sel].Obj().(*types.Var) + + sel := pass.TypesInfo.Selections[selector] + tvar, ok := sel.Obj().(*types.Var) if !ok || !tvar.IsField() { return } - stype, ok := pass.TypesInfo.Types[sel.X].Type.Underlying().(*types.Struct) + stype, ok := sel.Recv().Underlying().(*types.Struct) if !ok { return } diff --git a/go/analysis/passes/atomicalign/testdata/src/a/a.go b/go/analysis/passes/atomicalign/testdata/src/a/a.go index 45dd73d3..7aa7278e 100644 --- a/go/analysis/passes/atomicalign/testdata/src/a/a.go +++ b/go/analysis/passes/atomicalign/testdata/src/a/a.go @@ -228,3 +228,22 @@ func embeddedStructFields() { atomic.AddUint64(&s1.b, 9) // want "address of non 64-bit aligned field .b passed to atomic.AddUint64" atomic.AddInt64(&s1.c, 9) } + +type t struct { + _ int32 + a int64 + _ int16 + _ int16 + b uint64 +} + +func (t *t) structPointerReceiver() { + atomic.LoadInt64(&t.a) // want "address of non 64-bit aligned field .a passed to atomic.LoadInt64" + atomic.LoadUint64(&t.b) +} + +func structPointer() { + t := &t{} + atomic.StoreInt64(&t.a, -1) // want "address of non 64-bit aligned field .a passed to atomic.StoreInt64" + atomic.StoreUint64(&t.b, 1) +}