From 0a8e63141faff1a55ecf777e0e846c73e23fe6e7 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Tue, 13 Nov 2018 13:28:57 -0500 Subject: [PATCH] go/analysis/passes/printf: fix false negative with nested pointers Pointers to compound objects (structs, slices, arrays, maps) are only followed by fmt if the pointer is at the top level of an argument. This is to minimise the chances of fmt running into loops. However, vet did not follow this rule. It likely doesn't help that fmt does not document that restriction well, which is being tracked in #28625. This change was originally made to cmd/vet as https://go-review.googlesource.com/c/147997. Updates #27672. Change-Id: I65944cf355baedb4578af57046e2bbfd3fe6a9dc Reviewed-on: https://go-review.googlesource.com/c/149319 Reviewed-by: Michael Matloob Run-TryBot: Michael Matloob --- go/analysis/passes/printf/testdata/src/a/a.go | 10 +++++++++- go/analysis/passes/printf/types.go | 10 +++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/go/analysis/passes/printf/testdata/src/a/a.go b/go/analysis/passes/printf/testdata/src/a/a.go index 40e8f2f77c..603179bccb 100644 --- a/go/analysis/passes/printf/testdata/src/a/a.go +++ b/go/analysis/passes/printf/testdata/src/a/a.go @@ -237,7 +237,7 @@ func PrintfTests() { Printf("%T", someFunction) // ok: maybe someone wants to see the type // Bug: used to recur forever. Printf("%p %x", recursiveStructV, recursiveStructV.next) - Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next) + Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next) // want `Printf format %x has arg recursiveStruct1V\.next of wrong type \*a\.RecursiveStruct2` Printf("%p %x", recursiveSliceV, recursiveSliceV) Printf("%p %x", recursiveMapV, recursiveMapV) // Special handling for Log. @@ -678,6 +678,14 @@ func PointersToCompoundTypes() { intMap := map[int]int{3: 4} fmt.Printf("%s", &intMap) // want `Printf format %s has arg &intMap of wrong type \*map\[int\]int` + + type T2 struct { + X string + } + type T1 struct { + X *T2 + } + fmt.Printf("%s\n", T1{&T2{"x"}}) // want `Printf format %s has arg T1{&T2{.x.}} of wrong type a\.T1` } // Printf wrappers from external package diff --git a/go/analysis/passes/printf/types.go b/go/analysis/passes/printf/types.go index 28d94e1f94..0ebc8107f3 100644 --- a/go/analysis/passes/printf/types.go +++ b/go/analysis/passes/printf/types.go @@ -108,9 +108,13 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type, // Check whether the rest can print pointers. return t&argPointer != 0 } - // If it's a pointer to a struct, array, slice, or map, that's - // equivalent in our analysis to whether we can print the type - // being pointed to. + // If it's a top-level pointer to a struct, array, slice, or + // map, that's equivalent in our analysis to whether we can + // print the type being pointed to. Pointers in nested levels + // are not supported to minimize fmt running into loops. + if len(inProgress) > 1 { + return false + } return matchArgTypeInternal(pass, t, under, arg, inProgress) case *types.Struct: