From ba147e8661bb04d1ef68b49f14eb270708252f56 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Thu, 21 Apr 2022 22:33:30 +0100 Subject: [PATCH] Test calls through variables The tests which involve a flow through a receiver with a non-trivial access path currently don't give the right result. This should be fixed in a follow-up issue. --- .../genericfunctions.go | 19 +++++++ .../generictypesandmethods.go | 51 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/genericfunctions.go b/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/genericfunctions.go index 2ab18e235f8..b82420511e6 100644 --- a/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/genericfunctions.go +++ b/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/genericfunctions.go @@ -17,6 +17,10 @@ func genericSink2[T any](t T, u string) { sink(u) // $ hasValueFlow="u" } +func genericSink3[T any](t T, u string) { + sink(u) // $ hasValueFlow="u" +} + func test() { var x struct { x1 int @@ -30,6 +34,11 @@ func test() { s := genericSource[int8](2) sink(s) // $ hasValueFlow="s" } + { + f := genericSource[int8] + s := f(2) + sink(s) // $ hasValueFlow="s" + } { s := genericIdentity(source()) sink(s) // $ hasValueFlow="s" @@ -38,6 +47,11 @@ func test() { s := genericIdentity[string](source()) sink(s) // $ hasValueFlow="s" } + { + f := genericIdentity[string] + s := f(source()) + sink(s) // $ hasValueFlow="s" + } { s := source() genericSink1(x, s) @@ -46,4 +60,9 @@ func test() { s := source() genericSink2[uint16](3, s) } + { + s := source() + f := genericSink3[uint16] + f(3, s) + } } diff --git a/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/generictypesandmethods.go b/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/generictypesandmethods.go index 18d42d0e934..4e2dc169c6d 100644 --- a/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/generictypesandmethods.go +++ b/ql/test/library-tests/semmle/go/dataflow/GenericFunctionsAndTypes/generictypesandmethods.go @@ -37,16 +37,33 @@ func main() { gs1 := GenericStruct1[string]{""} sink(gs1.Identity(source())) // $ hasValueFlow="call to Identity" } + { + gs1 := GenericStruct1[string]{""} + f := gs1.Identity + sink(f(source())) // $ hasValueFlow="call to f" + } { gs1 := GenericStruct1[string]{""} gs1.Field = source() sink(gs1.Getter()) // $ hasValueFlow="call to Getter" } + { + gs1 := GenericStruct1[string]{""} + gs1.Field = source() + f := gs1.Getter + sink(f()) // $ MISSING: hasValueFlow="call to f" + } { gs1 := GenericStruct1[string]{""} gs1.Setter(source()) sink(gs1.Field) // $ hasValueFlow="selection of Field" } + { + gs1 := GenericStruct1[string]{""} + f := gs1.Setter + f(source()) + sink(gs1.Field) // $ MISSING: hasValueFlow="selection of Field" + } { gs2 := GenericStruct2[string, string]{source(), ""} @@ -56,16 +73,33 @@ func main() { gs2 := GenericStruct2[string, string]{"", ""} sink(gs2.Identity1(source())) // $ hasValueFlow="call to Identity1" } + { + gs2 := GenericStruct2[string, string]{"", ""} + f := gs2.Identity1 + sink(f(source())) // $ hasValueFlow="call to f" + } { gs2 := GenericStruct2[string, string]{"", ""} gs2.Field1 = source() sink(gs2.Getter1()) // $ hasValueFlow="call to Getter1" } + { + gs2 := GenericStruct2[string, string]{"", ""} + gs2.Field1 = source() + f := gs2.Getter1 + sink(f()) // $ MISSING: hasValueFlow="call to f" + } { gs2 := GenericStruct2[string, string]{"", ""} gs2.Setter1(source()) sink(gs2.Field1) // $ hasValueFlow="selection of Field1" } + { + gs2 := GenericStruct2[string, string]{"", ""} + f := gs2.Setter1 + f(source()) + sink(gs2.Field1) // $ MISSING: hasValueFlow="selection of Field1" + } { gs2 := GenericStruct2[string, string]{"", source()} @@ -75,14 +109,31 @@ func main() { gs2 := GenericStruct2[string, string]{"", ""} sink(gs2.Identity2(source())) // $ hasValueFlow="call to Identity2" } + { + gs2 := GenericStruct2[string, string]{"", ""} + f := gs2.Identity2 + sink(f(source())) // $ hasValueFlow="call to f" + } { gs2 := GenericStruct2[string, string]{"", ""} gs2.Field2 = source() sink(gs2.Getter2()) // $ hasValueFlow="call to Getter2" } + { + gs2 := GenericStruct2[string, string]{"", ""} + gs2.Field2 = source() + f := gs2.Getter2 + sink(f()) // $ MISSING: hasValueFlow="call to f" + } { gs2 := GenericStruct2[string, string]{"", ""} gs2.Setter2(source()) sink(gs2.Field2) // $ hasValueFlow="selection of Field2" } + { + gs2 := GenericStruct2[string, string]{"", ""} + f := gs2.Setter2 + f(source()) + sink(gs2.Field2) // $ MISSING: hasValueFlow="selection of Field2" + } }