From 44cc19cd6b8bdfc494856d970e4b51d513473a06 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 3 Jun 2024 18:03:48 +0100 Subject: [PATCH] C++: Handle phi inputs in barrier guards logic. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 73 +++++++++++++++++-- 1 file changed, 66 insertions(+), 7 deletions(-) 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 fa8abd7f32b..41f448197d0 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 @@ -159,6 +159,12 @@ class Node extends TIRDataFlowNode { /** Gets the operands corresponding to this node, if any. */ Operand asOperand() { result = this.(OperandNode).getOperand() } + /** + * Gets the operand that is indirectly tracked by this node behind `index` + * number of indirections. + */ + Operand asIndirectOperand(int index) { hasOperandAndIndex(this, result, index) } + /** * Holds if this node is at index `i` in basic block `block`. * @@ -2673,6 +2679,22 @@ class ContentSet instanceof Content { } } +pragma[nomagic] +private predicate guardControlsPhiInput( + IRGuardCondition g, boolean branch, Ssa::Definition def, IRBlock input, Ssa::PhiInputNodeExt phi +) { + phi.hasInputFromBlock(def, input) and + ( + g.controls(input, branch) + or + exists(EdgeKind kind | + g.getBlock() = input and + kind = getConditionalEdge(branch) and + input.getSuccessor(kind) = phi.getBasicBlock() + ) + ) +} + /** * Holds if the guard `g` validates the expression `e` upon evaluating to `branch`. * @@ -2721,13 +2743,22 @@ module BarrierGuard { * * NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead. */ - ExprNode getABarrierNode() { + Node getABarrierNode() { exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge | e = value.getAnInstruction().getConvertedResultExpression() and - result.getConvertedExpr() = e and + result.asConvertedExpr() = e and guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and g.controls(result.getBasicBlock(), edge) ) + or + exists( + IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, + Ssa::PhiInputNodeExt phi + | + guardChecks(g, def.getARead().asOperand().getDef().getConvertedResultExpression(), branch) and + guardControlsPhiInput(g, branch, def, input, phi) and + result = TSsaPhiInputNode(phi.getPhi(), input) + ) } /** @@ -2763,7 +2794,7 @@ module BarrierGuard { * * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. */ - IndirectExprNode getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) } + Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) } /** * Gets an indirect expression node with indirection index `indirectionIndex` that is @@ -2799,13 +2830,24 @@ module BarrierGuard { * * NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead. */ - IndirectExprNode getAnIndirectBarrierNode(int indirectionIndex) { + Node getAnIndirectBarrierNode(int indirectionIndex) { exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge | e = value.getAnInstruction().getConvertedResultExpression() and - result.getConvertedExpr(indirectionIndex) = e and + result.asIndirectConvertedExpr(indirectionIndex) = e and guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and g.controls(result.getBasicBlock(), edge) ) + or + exists( + IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, + Ssa::PhiInputNodeExt phi + | + guardChecks(g, + def.getARead().asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(), + branch) and + guardControlsPhiInput(g, branch, def, input, phi) and + result = TSsaPhiInputNode(phi.getPhi(), input) + ) } } @@ -2814,6 +2856,14 @@ module BarrierGuard { */ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch); +private EdgeKind getConditionalEdge(boolean branch) { + branch = true and + result instanceof TrueEdge + or + branch = false and + result instanceof FalseEdge +} + /** * Provides a set of barrier nodes for a guard that validates an instruction. * @@ -2822,12 +2872,21 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in */ module InstructionBarrierGuard { /** Gets a node that is safely guarded by the given guard check. */ - ExprNode getABarrierNode() { + Node getABarrierNode() { exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use | instructionGuardChecks(g, value.getAnInstruction(), edge) and use = value.getAnInstruction().getAUse() and result.asOperand() = use and - g.controls(use.getDef().getBlock(), edge) + g.controls(result.getBasicBlock(), edge) + ) + or + exists( + IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, + Ssa::PhiInputNodeExt phi + | + instructionGuardChecks(g, def.getARead().asOperand().getDef(), branch) and + guardControlsPhiInput(g, branch, def, input, phi) and + result = TSsaPhiInputNode(phi.getPhi(), input) ) } }