From 45080ec9f0c546ba169bd2bcfa77557a53eefabd Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 13 Dec 2023 12:05:04 +0000 Subject: [PATCH] C++: Create an abstract class to control debug 'toString' output for dataflow nodes. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 13 +--- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 11 ++- .../ir/dataflow/internal/DebugPrinting.qll | 9 +++ .../ir/dataflow/internal/Node0ToString.qll | 75 +++++++++++++++++++ 4 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DebugPrinting.qll create mode 100644 cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/Node0ToString.qll diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index cd387d5137a..9391282411b 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -6,6 +6,7 @@ private import semmle.code.cpp.ir.internal.IRCppLanguage private import SsaInternals as Ssa private import DataFlowImplCommon as DataFlowImplCommon private import codeql.util.Unit +import Node0ToString cached private module Cached { @@ -138,11 +139,7 @@ abstract class InstructionNode0 extends Node0Impl { override DataFlowType getType() { result = getInstructionType(instr, _) } - override string toStringImpl() { - if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable - then result = "this" - else result = instr.getAst().toString() - } + override string toStringImpl() { result = instructionToString(instr) } override Location getLocationImpl() { if exists(instr.getAst().getLocation()) @@ -187,11 +184,7 @@ abstract class OperandNode0 extends Node0Impl { override DataFlowType getType() { result = getOperandType(op, _) } - override string toStringImpl() { - if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable - then result = "this" - else result = op.getDef().getAst().toString() - } + override string toStringImpl() { result = operandToString(op) } override Location getLocationImpl() { if exists(op.getDef().getAst().getLocation()) 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 392ccde1ae4..3e3517513ae 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 @@ -486,10 +486,13 @@ class Node extends TIRDataFlowNode { } private string toExprString(Node n) { - result = n.asExpr(0).toString() - or - not exists(n.asExpr()) and - result = n.asIndirectExpr(0, 1).toString() + " indirection" + isDebugMode() and + ( + result = n.asExpr(0).toString() + or + not exists(n.asExpr()) and + result = n.asIndirectExpr(0, 1).toString() + " indirection" + ) } /** diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DebugPrinting.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DebugPrinting.qll new file mode 100644 index 00000000000..1c958cf78d6 --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DebugPrinting.qll @@ -0,0 +1,9 @@ +/** + * This file activates debugging mode for dataflow node printing. + */ + +private import Node0ToString + +private class DebugNode0ToString extends Node0ToString { + final override predicate isDebugMode() { any() } +} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/Node0ToString.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/Node0ToString.qll new file mode 100644 index 00000000000..e43bff16b10 --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/Node0ToString.qll @@ -0,0 +1,75 @@ +/** + * This file contains the abstract class that serves as the base class for + * dataflow node printing. + * + * By default, a non-debug string is produced. However, a debug-friendly + * string can be produced by importing `DebugPrinting.qll`. + */ + +private import semmle.code.cpp.ir.IR +private import codeql.util.Unit + +/** + * A class to control whether a debugging version of instructions and operands + * should be printed as part of the `toString` output of dataflow nodes. + * + * To enable debug printing import the `DebugPrinting.ql` file. By default, + * non-debug output will be used. + */ +class Node0ToString extends Unit { + abstract predicate isDebugMode(); + + private string normalInstructionToString(Instruction i) { + not this.isDebugMode() and + if i.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable + then result = "this" + else result = i.getAst().toString() + } + + private string normalOperandToString(Operand op) { + not this.isDebugMode() and + if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable + then result = "this" + else result = op.getDef().getAst().toString() + } + + /** + * Gets the string that should be used by `InstructionNode.toString` + */ + string instructionToString(Instruction i) { + if this.isDebugMode() + then result = i.getDumpString() + else result = this.normalInstructionToString(i) + } + + /** + * Gets the string that should be used by `OperandNode.toString`. + */ + string operandToString(Operand op) { + if this.isDebugMode() + then result = op.getDumpString() + " @ " + op.getUse().getResultId() + else result = this.normalOperandToString(op) + } +} + +private class NoDebugNode0ToString extends Node0ToString { + final override predicate isDebugMode() { none() } +} + +/** + * Gets the string that should be used by `OperandNode.toString`. + */ +string operandToString(Operand op) { result = any(Node0ToString nts).operandToString(op) } + +/** + * Gets the string that should be used by `InstructionNode.toString` + */ +string instructionToString(Instruction i) { result = any(Node0ToString nts).instructionToString(i) } + +/** + * Holds if debugging mode is enabled. + * + * In debug mode the `toString` on dataflow nodes is more expensive to compute, + * but gives more precise information about the different dataflow nodes. + */ +predicate isDebugMode() { not any(Node0ToString nts).isDebugMode() }