From 770c770a8f4a445bcce49ec259e26d98a2ea7682 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 24 Mar 2021 15:27:54 +0000 Subject: [PATCH] Add tests for promoted methods We need implicit field reads for calls to promoted methods. False negative flags have been added to make this pass on main. --- .../PromotedMethods/DataFlowConfig.expected | 0 .../PromotedMethods/DataFlowConfig.ql | 39 +++++++++ .../go/dataflow/PromotedMethods/methods.go | 81 +++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.expected create mode 100644 ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.ql create mode 100644 ql/test/library-tests/semmle/go/dataflow/PromotedMethods/methods.go diff --git a/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.expected b/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.ql b/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.ql new file mode 100644 index 00000000000..3dc328238b8 --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.ql @@ -0,0 +1,39 @@ +import go +import TestUtilities.InlineExpectationsTest + +class SourceFunction extends Function { + SourceFunction() { this.getName() = "source" } +} + +class SinkFunction extends Function { + SinkFunction() { this.getName() = "sink" } +} + +class TestConfig extends DataFlow::Configuration { + TestConfig() { this = "testconfig" } + + override predicate isSource(DataFlow::Node source) { + source = any(SourceFunction f).getACall().getAResult() + } + + override predicate isSink(DataFlow::Node sink) { + sink = any(SinkFunction f).getACall().getAnArgument() + } +} + +class PromotedMethodsTest extends InlineExpectationsTest { + PromotedMethodsTest() { this = "PromotedMethodsTest" } + + override string getARelevantTag() { result = "promotedmethods" } + + override predicate hasActualResult(string file, int line, string element, string tag, string value) { + exists(TestConfig config, DataFlow::Node source, DataFlow::Node sink | + config.hasFlow(source, sink) + | + sink.hasLocationInfo(file, line, _, _, _) and + element = sink.toString() and + value = source.getEnclosingCallable().getName() and + tag = "promotedmethods" + ) + } +} diff --git a/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/methods.go b/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/methods.go new file mode 100644 index 00000000000..41debd07a8a --- /dev/null +++ b/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/methods.go @@ -0,0 +1,81 @@ +package main + +func source() string { + return "hello world" +} + +func sink(s string) {} + +type Embedded struct { + field string +} + +type Base1 struct { + Embedded +} + +type Base2 struct { + *Embedded +} + +func (e Embedded) sinkFieldOnEmbeddedNonPointerReceiver() { + sink(e.field) // $promotedmethods=nonPointerSender1 $promotedmethods=pointerSender1 $promotedmethods=nonPointerSender2 $promotedmethods=pointerSender2 +} + +func (e *Embedded) sinkFieldOnEmbeddedPointerReceiver() { + sink(e.field) // $f-:promotedmethods=nonPointerSender1 $f-:promotedmethods=pointerSender1 $f-:promotedmethods=nonPointerSender2 $f-:promotedmethods=pointerSender2 +} + +func (base1 Base1) sinkFieldOnBase1NonPointerReceiver() { + sink(base1.field) // $promotedmethods=nonPointerSender1 $promotedmethods=pointerSender1 +} + +func (base1 *Base1) sinkFieldOnBase1PointerReceiver() { + sink(base1.field) // $f-:promotedmethods=nonPointerSender1 $promotedmethods=pointerSender1 +} + +func (base2 Base2) sinkFieldOnBase2NonPointerReceiver() { + sink(base2.field) // $promotedmethods=nonPointerSender2 $promotedmethods=pointerSender2 +} + +func (base2 *Base2) sinkFieldOnBase2PointerReceiver() { + sink(base2.field) // $f-:promotedmethods=nonPointerSender2 $promotedmethods=pointerSender2 +} + +func nonPointerSender1() { + var base1 Base1 + base1.field = source() + base1.sinkFieldOnEmbeddedNonPointerReceiver() + base1.sinkFieldOnEmbeddedPointerReceiver() + base1.sinkFieldOnBase1NonPointerReceiver() + base1.sinkFieldOnBase1PointerReceiver() +} + +func pointerSender1() { + var base1 Base1 + base1.field = source() + base1p := &base1 + base1p.sinkFieldOnEmbeddedNonPointerReceiver() + base1p.sinkFieldOnEmbeddedPointerReceiver() + base1p.sinkFieldOnBase1NonPointerReceiver() + base1p.sinkFieldOnBase1PointerReceiver() +} + +func nonPointerSender2() { + var base2 Base2 + base2.field = source() + base2.sinkFieldOnEmbeddedNonPointerReceiver() + base2.sinkFieldOnEmbeddedPointerReceiver() + base2.sinkFieldOnBase2NonPointerReceiver() + base2.sinkFieldOnBase2PointerReceiver() +} + +func pointerSender2() { + var base2 Base2 + base2.field = source() + base2p := &base2 + base2p.sinkFieldOnEmbeddedNonPointerReceiver() + base2p.sinkFieldOnEmbeddedPointerReceiver() + base2p.sinkFieldOnBase2NonPointerReceiver() + base2p.sinkFieldOnBase2PointerReceiver() +}