Skip to content

Commit bcedf68

Browse files
authored
Merge pull request #16246 from MathiasVP/parameter-nodes-for-functions-without-bodies
C++: Add Parameter nodes for functions without bodies
2 parents 57796d6 + bcda4a1 commit bcedf68

File tree

6 files changed

+217
-85
lines changed

6 files changed

+217
-85
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Parameters of functions without definitions now have `ParameterNode`s.

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

+4-2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ module NodeStars {
7878
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
7979
or
8080
result = n.(FinalParameterNode).getIndirectionIndex()
81+
or
82+
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
8183
}
8284

8385
/**
@@ -1247,7 +1249,7 @@ module IsUnreachableInCall {
12471249

12481250
predicate isUnreachableInCall(Node n, DataFlowCall call) {
12491251
exists(
1250-
DirectParameterNode paramNode, ConstantIntegralTypeArgumentNode arg,
1252+
InstructionDirectParameterNode paramNode, ConstantIntegralTypeArgumentNode arg,
12511253
IntegerConstantInstruction constant, int k, Operand left, Operand right, IRBlock block
12521254
|
12531255
// arg flows into `paramNode`
@@ -1461,7 +1463,7 @@ private predicate getAdditionalFlowIntoCallNodeTermStep(Node node1, Node node2)
14611463
/** Gets the `IRVariable` associated with the parameter node `p`. */
14621464
pragma[nomagic]
14631465
private IRVariable getIRVariableForParameterNode(ParameterNode p) {
1464-
result = p.(DirectParameterNode).getIRVariable()
1466+
result = p.(InstructionDirectParameterNode).getIRVariable()
14651467
or
14661468
result.getAst() = p.(IndirectParameterNode).getParameter()
14671469
}

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

+180-83
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ private newtype TIRDataFlowNode =
6161
} or
6262
TFinalGlobalValue(Ssa::GlobalUse globalUse) or
6363
TInitialGlobalValue(Ssa::GlobalDef globalUse) or
64+
TBodyLessParameterNodeImpl(Parameter p, int indirectionIndex) {
65+
// Rule out parameters of catch blocks.
66+
not exists(p.getCatchBlock()) and
67+
// We subtract one because `getMaxIndirectionsForType` returns the maximum
68+
// indirection for a glvalue of a given type, and this doesn't apply to
69+
// parameters.
70+
indirectionIndex = [0 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
71+
not any(InitializeParameterInstruction init).getParameter() = p
72+
} or
6473
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
6574

6675
/**
@@ -389,7 +398,7 @@ class Node extends TIRDataFlowNode {
389398
index = 0 and
390399
result = this.(ExplicitParameterNode).getParameter()
391400
or
392-
this.(IndirectParameterNode).hasInstructionAndIndirectionIndex(_, index) and
401+
this.(IndirectParameterNode).getIndirectionIndex() = index and
393402
result = this.(IndirectParameterNode).getParameter()
394403
}
395404

@@ -737,6 +746,40 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
737746
override string toStringImpl() { result = globalDef.toString() }
738747
}
739748

749+
/**
750+
* INTERNAL: do not use.
751+
*
752+
* A node representing a parameter for a function with no body.
753+
*/
754+
class BodyLessParameterNodeImpl extends Node, TBodyLessParameterNodeImpl {
755+
Parameter p;
756+
int indirectionIndex;
757+
758+
BodyLessParameterNodeImpl() { this = TBodyLessParameterNodeImpl(p, indirectionIndex) }
759+
760+
override Declaration getEnclosingCallable() { result = this.getFunction() }
761+
762+
override Declaration getFunction() { result = p.getFunction() }
763+
764+
/** Gets the indirection index of this node. */
765+
int getIndirectionIndex() { result = indirectionIndex }
766+
767+
override DataFlowType getType() {
768+
result = getTypeImpl(p.getUnderlyingType(), this.getIndirectionIndex())
769+
}
770+
771+
final override Location getLocationImpl() {
772+
result = unique( | | p.getLocation())
773+
or
774+
count(p.getLocation()) != 1 and
775+
result instanceof UnknownDefaultLocation
776+
}
777+
778+
final override string toStringImpl() {
779+
exists(string prefix | prefix = stars(this) | result = prefix + p.toString())
780+
}
781+
}
782+
740783
/**
741784
* A data-flow node used to model flow summaries. That is, a dataflow node
742785
* that is synthesized to represent a parameter, return value, or other part
@@ -767,42 +810,6 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
767810
override string toStringImpl() { result = this.getSummaryNode().toString() }
768811
}
769812

770-
/**
771-
* INTERNAL: do not use.
772-
*
773-
* A node representing an indirection of a parameter.
774-
*/
775-
class IndirectParameterNode extends Node instanceof IndirectInstruction {
776-
InitializeParameterInstruction init;
777-
778-
IndirectParameterNode() { IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _) }
779-
780-
int getArgumentIndex() { init.hasIndex(result) }
781-
782-
/** Gets the parameter whose indirection is initialized. */
783-
Parameter getParameter() { result = init.getParameter() }
784-
785-
override Declaration getEnclosingCallable() { result = this.getFunction() }
786-
787-
override Declaration getFunction() { result = init.getEnclosingFunction() }
788-
789-
/** Gets the underlying operand and the underlying indirection index. */
790-
predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
791-
IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
792-
}
793-
794-
override Location getLocationImpl() { result = this.getParameter().getLocation() }
795-
796-
override string toStringImpl() {
797-
exists(string prefix | prefix = stars(this) |
798-
result = prefix + this.getParameter().toString()
799-
or
800-
not exists(this.getParameter()) and
801-
result = prefix + "this"
802-
)
803-
}
804-
}
805-
806813
/**
807814
* INTERNAL: do not use.
808815
*
@@ -1655,6 +1662,88 @@ class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
16551662
}
16561663
}
16571664

1665+
abstract private class AbstractParameterNode extends Node {
1666+
/**
1667+
* Holds if this node is the parameter of `f` at the specified position. The
1668+
* implicit `this` parameter is considered to have position `-1`, and
1669+
* pointer-indirection parameters are at further negative positions.
1670+
*/
1671+
abstract predicate isParameterOf(DataFlowCallable f, ParameterPosition pos);
1672+
1673+
/** Gets the `Parameter` associated with this node, if it exists. */
1674+
Parameter getParameter() { none() } // overridden by subclasses
1675+
}
1676+
1677+
abstract private class AbstractIndirectParameterNode extends AbstractParameterNode {
1678+
/** Gets the indirection index of this parameter node. */
1679+
abstract int getIndirectionIndex();
1680+
}
1681+
1682+
/**
1683+
* INTERNAL: do not use.
1684+
*
1685+
* A node representing an indirection of a parameter.
1686+
*/
1687+
final class IndirectParameterNode = AbstractIndirectParameterNode;
1688+
1689+
pragma[noinline]
1690+
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
1691+
IndirectInstructionParameterNode node, int argumentIndex, int indirectionIndex
1692+
) {
1693+
node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
1694+
node.getArgumentIndex() = argumentIndex
1695+
}
1696+
1697+
pragma[noinline]
1698+
private predicate indirectPositionHasArgumentIndexAndIndex(
1699+
IndirectionPosition pos, int argumentIndex, int indirectionIndex
1700+
) {
1701+
pos.getArgumentIndex() = argumentIndex and
1702+
pos.getIndirectionIndex() = indirectionIndex
1703+
}
1704+
1705+
private class IndirectInstructionParameterNode extends AbstractIndirectParameterNode instanceof IndirectInstruction
1706+
{
1707+
InitializeParameterInstruction init;
1708+
1709+
IndirectInstructionParameterNode() {
1710+
IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _)
1711+
}
1712+
1713+
int getArgumentIndex() { init.hasIndex(result) }
1714+
1715+
override string toStringImpl() {
1716+
exists(string prefix | prefix = stars(this) |
1717+
result = prefix + this.getParameter().toString()
1718+
or
1719+
not exists(this.getParameter()) and
1720+
result = prefix + "this"
1721+
)
1722+
}
1723+
1724+
/** Gets the parameter whose indirection is initialized. */
1725+
override Parameter getParameter() { result = init.getParameter() }
1726+
1727+
override Declaration getEnclosingCallable() { result = this.getFunction() }
1728+
1729+
override Declaration getFunction() { result = init.getEnclosingFunction() }
1730+
1731+
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
1732+
this.getEnclosingCallable() = f.getUnderlyingCallable() and
1733+
exists(int argumentIndex, int indirectionIndex |
1734+
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
1735+
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
1736+
)
1737+
}
1738+
1739+
/** Gets the underlying operand and the underlying indirection index. */
1740+
predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
1741+
IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
1742+
}
1743+
1744+
final override int getIndirectionIndex() { this.hasInstructionAndIndirectionIndex(init, result) }
1745+
}
1746+
16581747
/**
16591748
* The value of a parameter at function entry, viewed as a node in a data
16601749
* flow graph. This includes both explicit parameters such as `x` in `f(x)`
@@ -1664,42 +1753,38 @@ class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
16641753
* `ExplicitParameterNode`, `ThisParameterNode`, or
16651754
* `ParameterIndirectionNode`.
16661755
*/
1667-
class ParameterNode extends Node {
1668-
ParameterNode() {
1669-
// To avoid making this class abstract, we enumerate its values here
1670-
this.asInstruction() instanceof InitializeParameterInstruction
1671-
or
1672-
this instanceof IndirectParameterNode
1673-
or
1674-
FlowSummaryImpl::Private::summaryParameterNode(this.(FlowSummaryNode).getSummaryNode(), _)
1675-
}
1756+
final class ParameterNode = AbstractParameterNode;
16761757

1677-
/**
1678-
* Holds if this node is the parameter of `f` at the specified position. The
1679-
* implicit `this` parameter is considered to have position `-1`, and
1680-
* pointer-indirection parameters are at further negative positions.
1681-
*/
1682-
predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) { none() } // overridden by subclasses
1683-
1684-
/** Gets the `Parameter` associated with this node, if it exists. */
1685-
Parameter getParameter() { none() } // overridden by subclasses
1686-
}
1758+
abstract private class AbstractDirectParameterNode extends AbstractParameterNode { }
16871759

16881760
/** An explicit positional parameter, including `this`, but not `...`. */
1689-
class DirectParameterNode extends InstructionNode {
1690-
override InitializeParameterInstruction instr;
1761+
final class DirectParameterNode = AbstractDirectParameterNode;
1762+
1763+
/**
1764+
* INTERNAL: Do not use.
1765+
*
1766+
* A non-indirect parameter node that is represented as an `Instruction`.
1767+
*/
1768+
abstract class InstructionDirectParameterNode extends InstructionNode, AbstractDirectParameterNode {
1769+
final override InitializeParameterInstruction instr;
16911770

16921771
/**
16931772
* INTERNAL: Do not use.
16941773
*
16951774
* Gets the `IRVariable` that this parameter references.
16961775
*/
1697-
IRVariable getIRVariable() { result = instr.getIRVariable() }
1776+
final IRVariable getIRVariable() { result = instr.getIRVariable() }
16981777
}
16991778

1779+
abstract private class AbstractExplicitParameterNode extends AbstractDirectParameterNode { }
1780+
1781+
final class ExplicitParameterNode = AbstractExplicitParameterNode;
1782+
17001783
/** An explicit positional parameter, not including `this` or `...`. */
1701-
private class ExplicitParameterNode extends ParameterNode, DirectParameterNode {
1702-
ExplicitParameterNode() { exists(instr.getParameter()) }
1784+
private class ExplicitParameterInstructionNode extends AbstractExplicitParameterNode,
1785+
InstructionDirectParameterNode
1786+
{
1787+
ExplicitParameterInstructionNode() { exists(instr.getParameter()) }
17031788

17041789
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
17051790
f.getUnderlyingCallable().(Function).getParameter(pos.(DirectPosition).getIndex()) =
@@ -1712,8 +1797,10 @@ private class ExplicitParameterNode extends ParameterNode, DirectParameterNode {
17121797
}
17131798

17141799
/** An implicit `this` parameter. */
1715-
class ThisParameterNode extends ParameterNode, DirectParameterNode {
1716-
ThisParameterNode() { instr.getIRVariable() instanceof IRThisVariable }
1800+
class ThisParameterInstructionNode extends AbstractExplicitParameterNode,
1801+
InstructionDirectParameterNode
1802+
{
1803+
ThisParameterInstructionNode() { instr.getIRVariable() instanceof IRThisVariable }
17171804

17181805
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
17191806
pos.(DirectPosition).getIndex() = -1 and
@@ -1726,7 +1813,7 @@ class ThisParameterNode extends ParameterNode, DirectParameterNode {
17261813
/**
17271814
* A parameter node that is part of a summary.
17281815
*/
1729-
class SummaryParameterNode extends ParameterNode, FlowSummaryNode {
1816+
class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
17301817
SummaryParameterNode() {
17311818
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
17321819
}
@@ -1741,31 +1828,41 @@ class SummaryParameterNode extends ParameterNode, FlowSummaryNode {
17411828
}
17421829
}
17431830

1744-
pragma[noinline]
1745-
private predicate indirectPositionHasArgumentIndexAndIndex(
1746-
IndirectionPosition pos, int argumentIndex, int indirectionIndex
1747-
) {
1748-
pos.getArgumentIndex() = argumentIndex and
1749-
pos.getIndirectionIndex() = indirectionIndex
1750-
}
1831+
private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
1832+
BodyLessParameterNodeImpl
1833+
{
1834+
DirectBodyLessParameterNode() { indirectionIndex = 0 }
17511835

1752-
pragma[noinline]
1753-
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
1754-
IndirectParameterNode node, int argumentIndex, int indirectionIndex
1755-
) {
1756-
node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
1757-
node.getArgumentIndex() = argumentIndex
1836+
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
1837+
exists(Function func |
1838+
this.getFunction() = func and
1839+
f.asSourceCallable() = func and
1840+
func.getParameter(pos.(DirectPosition).getIndex()) = p
1841+
)
1842+
}
1843+
1844+
override Parameter getParameter() { result = p }
17581845
}
17591846

1760-
/** A synthetic parameter to model the pointed-to object of a pointer parameter. */
1761-
class ParameterIndirectionNode extends ParameterNode instanceof IndirectParameterNode {
1847+
private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNode,
1848+
BodyLessParameterNodeImpl
1849+
{
1850+
IndirectBodyLessParameterNode() { not this instanceof DirectBodyLessParameterNode }
1851+
17621852
override predicate isParameterOf(DataFlowCallable f, ParameterPosition pos) {
1763-
IndirectParameterNode.super.getEnclosingCallable() = f.getUnderlyingCallable() and
1764-
exists(int argumentIndex, int indirectionIndex |
1765-
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
1766-
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
1853+
exists(Function func, int argumentPosition |
1854+
this.getFunction() = func and
1855+
f.asSourceCallable() = func and
1856+
indirectPositionHasArgumentIndexAndIndex(pos, argumentPosition, indirectionIndex) and
1857+
func.getParameter(argumentPosition) = p
17671858
)
17681859
}
1860+
1861+
override int getIndirectionIndex() {
1862+
result = BodyLessParameterNodeImpl.super.getIndirectionIndex()
1863+
}
1864+
1865+
override Parameter getParameter() { result = p }
17691866
}
17701867

17711868
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
void sink(int); // $ ir
2+
void indirect_sink(int*); // $ ir
3+
int source();
4+
5+
void test() {
6+
int x = source();
7+
sink(x);
8+
9+
int* p = &x;
10+
indirect_sink(p);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
testFailures
2+
failures

0 commit comments

Comments
 (0)