From 6c792e69b341de543d31598c63acbc8fa4cba429 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 11 Mar 2026 13:53:24 -0700 Subject: [PATCH 1/7] Expose the indirection index --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index fe954c640d1b..d1eccf8c1cce 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -767,10 +767,11 @@ module Public { */ class UninitializedNode extends Node { LocalVariable v; + int indirectionIndex; UninitializedNode() { exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv | - def.getIndirectionIndex() = 0 and + def.getIndirectionIndex() = indirectionIndex and def.getValue().asInstruction() instanceof UninitializedInstruction and SsaImpl::defToNode(this, def, sv) and v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst() @@ -779,6 +780,9 @@ module Public { /** Gets the uninitialized local variable corresponding to this node. */ LocalVariable getLocalVariable() { result = v } + + /** Gets the level of indirection to get to this node. */ + int getIndirectionIndex() { result = indirectionIndex } } /** From 8c03136c252e22cc062b63f132d89235b3354633 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 13 Mar 2026 10:11:40 -0700 Subject: [PATCH 2/7] Revert "Expose the indirection index" This reverts commit 6c792e69b341de543d31598c63acbc8fa4cba429. --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index d1eccf8c1cce..fe954c640d1b 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -767,11 +767,10 @@ module Public { */ class UninitializedNode extends Node { LocalVariable v; - int indirectionIndex; UninitializedNode() { exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv | - def.getIndirectionIndex() = indirectionIndex and + def.getIndirectionIndex() = 0 and def.getValue().asInstruction() instanceof UninitializedInstruction and SsaImpl::defToNode(this, def, sv) and v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst() @@ -780,9 +779,6 @@ module Public { /** Gets the uninitialized local variable corresponding to this node. */ LocalVariable getLocalVariable() { result = v } - - /** Gets the level of indirection to get to this node. */ - int getIndirectionIndex() { result = indirectionIndex } } /** From d3066af2e2ca786bca7cc16c65613f07720c9ffc Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 13 Mar 2026 11:39:57 -0700 Subject: [PATCH 3/7] Create `IndirectUninitializedNode` and add a bridge from it to `LocalVariable` This way the changes do not alter the meaning of `UninitializedNode`. In the meantime, the code still provides a specialized `Node` type `IndirectUninitializedNode` to access the nodes behind levels of indirection. --- .../ir/dataflow/internal/DataFlowNodes.qll | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index fe954c640d1b..6b201a7aa8b5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -617,6 +617,25 @@ module Public { */ LocalVariable asUninitialized() { result = this.(UninitializedNode).getLocalVariable() } + /** + * Gets the uninitialized local variable corresponding to this node behind + * the given levels of indirection, if any. + */ + LocalVariable asIndirectUninitialized(int indirectionIndex) { + exists(IndirectUninitializedNode indirectUninitializedNode | + this = indirectUninitializedNode and + indirectUninitializedNode.getIndirectionIndex() = indirectionIndex + | + result = indirectUninitializedNode.getLocalVariable() + ) + } + + /** + * Gets the uninitialized local variable corresponding to this node behind + * any levels of indirection, if any. + */ + LocalVariable asIndirectUninitialized() { result = this.asIndirectUninitialized(_) } + /** * Gets the positional parameter corresponding to the node that represents * the value of the parameter after `index` number of loads, if any. For @@ -781,6 +800,34 @@ module Public { LocalVariable getLocalVariable() { result = v } } + /** + * The value of an uninitialized local variable behind one or more levels of + * indirection, viewed as a node in a data flow graph. + * + * NOTE: For the direct value of the uninitialized local variable, see + * `UninitializedNode`. + */ + class IndirectUninitializedNode extends Node { + LocalVariable v; + int indirectionIndex; + + IndirectUninitializedNode() { + exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv | + def.getIndirectionIndex() = indirectionIndex and + indirectionIndex > 0 and // With `indirectionIndex` = 0, this class becomes the same as `UninitializedNode`. + def.getValue().asInstruction() instanceof UninitializedInstruction and + SsaImpl::defToNode(this, def, sv) and + v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst() + ) + } + + /** Gets the uninitialized local variable corresponding to this node. */ + LocalVariable getLocalVariable() { result = v } + + /** Gets the level of indirection to get to this node. */ + int getIndirectionIndex() { result = indirectionIndex } + } + /** * The value of a parameter at function entry, viewed as a node in a data * flow graph. This includes both explicit parameters such as `x` in `f(x)` From 3f9ad144737a814b69766e1d218b073a06759eec Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 16 Mar 2026 14:11:34 -0700 Subject: [PATCH 4/7] Factor out common code into an abstract private class --- .../ir/dataflow/internal/DataFlowNodes.qll | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index 6b201a7aa8b5..51cc7430f62c 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -780,16 +780,13 @@ module Public { final override Type getType() { result = this.getPreUpdateNode().getType() } } - /** - * The value of an uninitialized local variable, viewed as a node in a data - * flow graph. - */ - class UninitializedNode extends Node { + abstract private class AbstractUninitializedNode extends Node { LocalVariable v; + int indirectionIndex; - UninitializedNode() { + AbstractUninitializedNode() { exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv | - def.getIndirectionIndex() = 0 and + def.getIndirectionIndex() = indirectionIndex and def.getValue().asInstruction() instanceof UninitializedInstruction and SsaImpl::defToNode(this, def, sv) and v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst() @@ -800,6 +797,14 @@ module Public { LocalVariable getLocalVariable() { result = v } } + /** + * The value of an uninitialized local variable, viewed as a node in a data + * flow graph. + */ + class UninitializedNode extends AbstractUninitializedNode { + UninitializedNode() { indirectionIndex = 0 } + } + /** * The value of an uninitialized local variable behind one or more levels of * indirection, viewed as a node in a data flow graph. @@ -807,22 +812,8 @@ module Public { * NOTE: For the direct value of the uninitialized local variable, see * `UninitializedNode`. */ - class IndirectUninitializedNode extends Node { - LocalVariable v; - int indirectionIndex; - - IndirectUninitializedNode() { - exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv | - def.getIndirectionIndex() = indirectionIndex and - indirectionIndex > 0 and // With `indirectionIndex` = 0, this class becomes the same as `UninitializedNode`. - def.getValue().asInstruction() instanceof UninitializedInstruction and - SsaImpl::defToNode(this, def, sv) and - v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst() - ) - } - - /** Gets the uninitialized local variable corresponding to this node. */ - LocalVariable getLocalVariable() { result = v } + class IndirectUninitializedNode extends AbstractUninitializedNode { + IndirectUninitializedNode() { indirectionIndex > 0 } /** Gets the level of indirection to get to this node. */ int getIndirectionIndex() { result = indirectionIndex } From d191d09c5553e4b2851bc8b2612f0e98831f4cbf Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 19 Mar 2026 15:48:47 -0700 Subject: [PATCH 5/7] Apply suggestions from code review Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com> --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index 51cc7430f62c..25e675053e22 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -619,7 +619,7 @@ module Public { /** * Gets the uninitialized local variable corresponding to this node behind - * the given levels of indirection, if any. + * `index` number of indirections, if any. */ LocalVariable asIndirectUninitialized(int indirectionIndex) { exists(IndirectUninitializedNode indirectUninitializedNode | @@ -632,7 +632,7 @@ module Public { /** * Gets the uninitialized local variable corresponding to this node behind - * any levels of indirection, if any. + * a number indirections, if any. */ LocalVariable asIndirectUninitialized() { result = this.asIndirectUninitialized(_) } @@ -815,7 +815,7 @@ module Public { class IndirectUninitializedNode extends AbstractUninitializedNode { IndirectUninitializedNode() { indirectionIndex > 0 } - /** Gets the level of indirection to get to this node. */ + /** Gets the indirection index of this node. */ int getIndirectionIndex() { result = indirectionIndex } } From dc291ffad76b569c9c23d55630858f6afb8f0d0b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 19 Mar 2026 15:51:00 -0700 Subject: [PATCH 6/7] Address code review --- .../semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index 51cc7430f62c..5c5b20f9e814 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -621,10 +621,10 @@ module Public { * Gets the uninitialized local variable corresponding to this node behind * the given levels of indirection, if any. */ - LocalVariable asIndirectUninitialized(int indirectionIndex) { + LocalVariable asIndirectUninitialized(int index) { exists(IndirectUninitializedNode indirectUninitializedNode | this = indirectUninitializedNode and - indirectUninitializedNode.getIndirectionIndex() = indirectionIndex + indirectUninitializedNode.getIndirectionIndex() = index | result = indirectUninitializedNode.getLocalVariable() ) @@ -808,9 +808,6 @@ module Public { /** * The value of an uninitialized local variable behind one or more levels of * indirection, viewed as a node in a data flow graph. - * - * NOTE: For the direct value of the uninitialized local variable, see - * `UninitializedNode`. */ class IndirectUninitializedNode extends AbstractUninitializedNode { IndirectUninitializedNode() { indirectionIndex > 0 } From d2fcced5adf53ee9dde4338ceae57c49b5290736 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 20 Mar 2026 09:59:12 -0700 Subject: [PATCH 7/7] Add a `feature` change note --- .../2026-03-20-add-indirect-uninitialized-node.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cpp/ql/lib/change-notes/2026-03-20-add-indirect-uninitialized-node.md diff --git a/cpp/ql/lib/change-notes/2026-03-20-add-indirect-uninitialized-node.md b/cpp/ql/lib/change-notes/2026-03-20-add-indirect-uninitialized-node.md new file mode 100644 index 000000000000..9dd67f8910d6 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-03-20-add-indirect-uninitialized-node.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* A new data flow class called `IndirectUninitializedNode` represents uninitialized data of a variable behind some level of indirection.