Skip to content

Commit 5ad3e97

Browse files
committed
C++: Fix TODO by blocking summary flow through functions that don't preserve identity.
1 parent 1ac75de commit 5ad3e97

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

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

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ private import SsaInternals as Ssa
77
private import DataFlowImplCommon as DataFlowImplCommon
88
private import codeql.util.Unit
99
private import Node0ToString
10+
private import ModelUtil
11+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
12+
private import semmle.code.cpp.models.interfaces.DataFlow as DF
1013

1114
cached
1215
private module Cached {
@@ -1178,6 +1181,19 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
11781181
)
11791182
}
11801183

1184+
pragma[nomagic]
1185+
private predicate isInputOutput(
1186+
DF::DataFlowFunction target, Node node1, Node node2, IO::FunctionInput input,
1187+
IO::FunctionOutput output
1188+
) {
1189+
exists(CallInstruction call |
1190+
node1 = callInput(call, input) and
1191+
node2 = callOutput(call, output) and
1192+
call.getStaticCallTarget() = target and
1193+
target.hasDataFlow(input, output)
1194+
)
1195+
}
1196+
11811197
/**
11821198
* Holds if the data-flow step from `node1` to `node2` can be used to
11831199
* determine where side-effects may return from a callable.
@@ -1189,6 +1205,11 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
11891205
* int x = *p;
11901206
* ```
11911207
* does not preserve the identity of `*p`.
1208+
*
1209+
* Similarly, functions that copy the contents of a string into a new location
1210+
* does not also preserve the identity. For example, `strdup(p)` does not
1211+
* preserve the identity of `*p` (since it allocates new storage and copies
1212+
* the string into the new storage).
11921213
*/
11931214
bindingset[node1, node2]
11941215
pragma[inline_late]
@@ -1225,7 +1246,16 @@ predicate validParameterAliasStep(Node node1, Node node2) {
12251246
not exists(Operand operand |
12261247
node1.asOperand() = operand and
12271248
node2.asInstruction().(StoreInstruction).getSourceValueOperand() = operand
1249+
) and
1250+
(
1251+
// Either this is not a modeled flow.
1252+
not isInputOutput(_, node1, node2, _, _)
1253+
or
1254+
exists(DF::DataFlowFunction target, IO::FunctionInput input, IO::FunctionOutput output |
1255+
// Or it is a modeled flow and there's `*input` to `*output` flow
1256+
isInputOutput(target, node1, node2, input.getIndirectionInput(), output.getIndirectionOutput()) and
1257+
// and in that case there should also be `input` to `output` flow
1258+
target.hasDataFlow(input, output)
1259+
)
12281260
)
1229-
// TODO: Also block flow through models that don't preserve identity such
1230-
// as `strdup`.
12311261
}

cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ private newtype TFunctionInput =
2323
class FunctionInput extends TFunctionInput {
2424
abstract string toString();
2525

26+
/**
27+
* INTERNAL: Do not use.
28+
*
29+
* Gets the `FunctionInput` that represents the indirection of this input,
30+
* if any.
31+
*/
32+
FunctionInput getIndirectionInput() { none() }
33+
2634
/**
2735
* Holds if this is the input value of the parameter with index `index`.
2836
*
@@ -226,6 +234,8 @@ class InParameter extends FunctionInput, TInParameter {
226234
ParameterIndex getIndex() { result = index }
227235

228236
override predicate isParameter(ParameterIndex i) { i = index }
237+
238+
override FunctionInput getIndirectionInput() { result = TInParameterDeref(index, 1) }
229239
}
230240

231241
/**
@@ -257,6 +267,10 @@ class InParameterDeref extends FunctionInput, TInParameterDeref {
257267
override predicate isParameterDeref(ParameterIndex i, int indirection) {
258268
i = index and indirectionIndex = indirection
259269
}
270+
271+
override FunctionInput getIndirectionInput() {
272+
result = TInParameterDeref(index, indirectionIndex + 1)
273+
}
260274
}
261275

262276
/**
@@ -275,6 +289,8 @@ class InQualifierObject extends FunctionInput, TInQualifierObject {
275289
override string toString() { result = "InQualifierObject" }
276290

277291
override predicate isQualifierObject() { any() }
292+
293+
override FunctionInput getIndirectionInput() { none() }
278294
}
279295

280296
/**
@@ -293,6 +309,8 @@ class InQualifierAddress extends FunctionInput, TInQualifierAddress {
293309
override string toString() { result = "InQualifierAddress" }
294310

295311
override predicate isQualifierAddress() { any() }
312+
313+
override FunctionInput getIndirectionInput() { result = TInQualifierObject() }
296314
}
297315

298316
/**
@@ -321,6 +339,8 @@ class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
321339
override string toString() { result = "InReturnValueDeref" }
322340

323341
override predicate isReturnValueDeref() { any() }
342+
343+
override FunctionInput getIndirectionInput() { none() }
324344
}
325345

326346
private newtype TFunctionOutput =
@@ -340,6 +360,14 @@ private newtype TFunctionOutput =
340360
class FunctionOutput extends TFunctionOutput {
341361
abstract string toString();
342362

363+
/**
364+
* INTERNAL: Do not use.
365+
*
366+
* Gets the `FunctionOutput` that represents the indirection of this output,
367+
* if any.
368+
*/
369+
FunctionOutput getIndirectionOutput() { none() }
370+
343371
/**
344372
* Holds if this is the output value pointed to by a pointer parameter to a function, or the
345373
* output value referred to by a reference parameter to a function, where the parameter has
@@ -512,6 +540,10 @@ class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
512540
override predicate isParameterDeref(ParameterIndex i, int ind) {
513541
i = index and ind = indirectionIndex
514542
}
543+
544+
override FunctionOutput getIndirectionOutput() {
545+
result = TOutParameterDeref(index, indirectionIndex + 1)
546+
}
515547
}
516548

517549
/**
@@ -530,6 +562,8 @@ class OutQualifierObject extends FunctionOutput, TOutQualifierObject {
530562
override string toString() { result = "OutQualifierObject" }
531563

532564
override predicate isQualifierObject() { any() }
565+
566+
override FunctionOutput getIndirectionOutput() { none() }
533567
}
534568

535569
/**
@@ -552,6 +586,8 @@ class OutReturnValue extends FunctionOutput, TOutReturnValue {
552586
override string toString() { result = "OutReturnValue" }
553587

554588
override predicate isReturnValue() { any() }
589+
590+
override FunctionOutput getIndirectionOutput() { result = TOutReturnValueDeref(1) }
555591
}
556592

557593
/**
@@ -571,11 +607,19 @@ class OutReturnValue extends FunctionOutput, TOutReturnValue {
571607
* of `getInt()` is neither a pointer nor a reference.
572608
*/
573609
class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
610+
int indirectionIndex;
611+
612+
OutReturnValueDeref() { this = TOutReturnValueDeref(indirectionIndex) }
613+
574614
override string toString() { result = "OutReturnValueDeref" }
575615

576616
override predicate isReturnValueDeref() { any() }
577617

578-
override predicate isReturnValueDeref(int indirectionIndex) {
579-
this = TOutReturnValueDeref(indirectionIndex)
618+
override predicate isReturnValueDeref(int indirectionIndex_) {
619+
indirectionIndex = indirectionIndex_
620+
}
621+
622+
override FunctionOutput getIndirectionOutput() {
623+
result = TOutReturnValueDeref(indirectionIndex + 1)
580624
}
581625
}

0 commit comments

Comments
 (0)