diff --git a/cpp/ql/lib/change-notes/2026-01-23-as-definition.md b/cpp/ql/lib/change-notes/2026-01-23-as-definition.md new file mode 100644 index 000000000000..1f18562cdcd7 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-01-23-as-definition.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Fixed a bug which caused `Node.asDefinition()` to not have a result for certain assignments. \ No newline at end of file diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 1c338d5a52d9..c66c76e60d78 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -312,6 +312,13 @@ class Node extends TIRDataFlowNode { */ Expr asDefinition() { result = this.asDefinition(_) } + private predicate isCertainStore() { + exists(SsaImpl::Definition def | + SsaImpl::defToNode(this, def, _) and + def.isCertain() + ) + } + /** * Gets the definition associated with this node, if any. * @@ -361,11 +368,10 @@ class Node extends TIRDataFlowNode { * pointed to by `p`. */ Expr asDefinition(boolean uncertain) { - exists(StoreInstruction store, SsaImpl::Definition def | + exists(StoreInstruction store | store = this.asInstruction() and result = asDefinitionImpl(store) and - SsaImpl::defToNode(this, def, _) and - if def.isCertain() then uncertain = false else uncertain = true + if this.isCertainStore() then uncertain = false else uncertain = true ) } diff --git a/cpp/ql/test/library-tests/dataflow/asDefinition/test.cpp b/cpp/ql/test/library-tests/dataflow/asDefinition/test.cpp new file mode 100644 index 000000000000..facb67399585 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/asDefinition/test.cpp @@ -0,0 +1,18 @@ +struct S { + int x; +}; + +void use(int); + +void test() { + int y = 43; // $ asDefinition=43 + use(y); + y = 44; // $ asDefinition="... = ..." + use(y); + + int x = 43; // $ asDefinition=43 + x = 44; // $ asDefinition="... = ..." + + S s; + s.x = 42; // $ asDefinition="... = ..." +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/asDefinition/test.expected b/cpp/ql/test/library-tests/dataflow/asDefinition/test.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cpp/ql/test/library-tests/dataflow/asDefinition/test.ql b/cpp/ql/test/library-tests/dataflow/asDefinition/test.ql new file mode 100644 index 000000000000..b996f47fb49f --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/asDefinition/test.ql @@ -0,0 +1,22 @@ +import cpp +import utils.test.InlineExpectationsTest +import semmle.code.cpp.dataflow.new.DataFlow::DataFlow + +bindingset[s] +string quote(string s) { if s.matches("% %") then result = "\"" + s + "\"" else result = s } + +module AsDefinitionTest implements TestSig { + string getARelevantTag() { result = "asDefinition" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(Node n, Expr e | + e = n.asDefinition() and + location = e.getLocation() and + element = n.toString() and + tag = "asDefinition" and + value = quote(e.toString()) + ) + } +} + +import MakeTest