Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9aa9187

Browse files
authored
Merge pull request #12141 from MathiasVP/fix-multiple-out-nodes
C++: Deduplicate `OutNode`s
2 parents 9d6098a + 4719fd5 commit 9aa9187

6 files changed

Lines changed: 86 additions & 39 deletions

File tree

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

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -404,14 +404,18 @@ class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode {
404404
}
405405
}
406406

407-
private Operand fullyConvertedCallStep(Operand op) {
407+
private Operand fullyConvertedCallStepImpl(Operand op) {
408408
not exists(getANonConversionUse(op)) and
409409
exists(Instruction instr |
410410
conversionFlow(op, instr, _, _) and
411411
result = getAUse(instr)
412412
)
413413
}
414414

415+
private Operand fullyConvertedCallStep(Operand op) {
416+
result = unique( | | fullyConvertedCallStepImpl(op))
417+
}
418+
415419
/**
416420
* Gets the instruction that uses this operand, if the instruction is not
417421
* ignored for dataflow purposes.
@@ -438,10 +442,21 @@ private Instruction getANonConversionUse(Operand operand) {
438442
}
439443

440444
/**
441-
* Gets the operand that represents the first use of the value of `call` following
445+
* Gets an operand that represents the use of the value of `call` following
442446
* a sequence of conversion-like instructions.
447+
*
448+
* Note that `operand` is not functionally determined by `call` since there
449+
* can be multiple sequences of disjoint conversions following a call. For example,
450+
* consider an example like:
451+
* ```cpp
452+
* long f();
453+
* int y;
454+
* long x = (long)(y = (int)f());
455+
* ```
456+
* in this case, there'll be a long-to-int conversion on `f()` before the value is assigned to `y`,
457+
* and there will be an int-to-long conversion on `(int)f()` before the value is assigned to `x`.
443458
*/
444-
predicate operandForFullyConvertedCall(Operand operand, CallInstruction call) {
459+
private predicate operandForFullyConvertedCallImpl(Operand operand, CallInstruction call) {
445460
exists(getANonConversionUse(operand)) and
446461
(
447462
operand = getAUse(call)
@@ -450,6 +465,24 @@ predicate operandForFullyConvertedCall(Operand operand, CallInstruction call) {
450465
)
451466
}
452467

468+
/**
469+
* Gets the operand that represents the use of the value of `call` following
470+
* a sequence of conversion-like instructions, if a unique operand exists.
471+
*/
472+
predicate operandForFullyConvertedCall(Operand operand, CallInstruction call) {
473+
operand = unique(Operand cand | operandForFullyConvertedCallImpl(cand, call))
474+
}
475+
476+
private predicate instructionForFullyConvertedCallWithConversions(
477+
Instruction instr, CallInstruction call
478+
) {
479+
instr =
480+
getUse(unique(Operand operand |
481+
operand = fullyConvertedCallStep*(getAUse(call)) and
482+
not exists(fullyConvertedCallStep(operand))
483+
))
484+
}
485+
453486
/**
454487
* Gets the instruction that represents the first use of the value of `call` following
455488
* a sequence of conversion-like instructions.
@@ -458,16 +491,15 @@ predicate operandForFullyConvertedCall(Operand operand, CallInstruction call) {
458491
* conversion instruction) to use to represent the value of `call` after conversions.
459492
*/
460493
predicate instructionForFullyConvertedCall(Instruction instr, CallInstruction call) {
494+
// Only pick an instruction for the call if we cannot pick a unique operand.
461495
not operandForFullyConvertedCall(_, call) and
462496
(
463497
// If there is no use of the call then we pick the call instruction
464-
not exists(getAUse(call)) and
498+
not instructionForFullyConvertedCallWithConversions(_, call) and
465499
instr = call
466500
or
467-
// Otherwise, flow to the first non-conversion use.
468-
exists(Operand operand | operand = fullyConvertedCallStep*(getAUse(call)) |
469-
instr = getANonConversionUse(operand)
470-
)
501+
// Otherwise, flow to the first instruction that defines multiple operands.
502+
instructionForFullyConvertedCallWithConversions(instr, call)
471503
)
472504
}
473505

cpp/ql/test/library-tests/dataflow/dataflow-tests/test-number-of-outnodes.expected

Whitespace-only changes.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import TestUtilities.InlineExpectationsTest
2+
import cpp
3+
4+
module AstTest {
5+
private import semmle.code.cpp.dataflow.old.DataFlow::DataFlow
6+
private import semmle.code.cpp.dataflow.old.internal.DataFlowPrivate
7+
8+
class ASTMultipleOutNodesTest extends InlineExpectationsTest {
9+
ASTMultipleOutNodesTest() { this = "ASTMultipleOutNodesTest" }
10+
11+
override string getARelevantTag() { result = "ast-count(" + any(ReturnKind k).toString() + ")" }
12+
13+
override predicate hasActualResult(Location location, string element, string tag, string value) {
14+
exists(DataFlowCall call, int n, ReturnKind kind |
15+
call.getLocation() = location and
16+
n = strictcount(getAnOutNode(call, kind)) and
17+
n > 1 and
18+
element = call.toString() and
19+
tag = "ast-count(" + kind.toString() + ")" and
20+
value = n.toString()
21+
)
22+
}
23+
}
24+
}
25+
26+
module IRTest {
27+
private import semmle.code.cpp.ir.dataflow.DataFlow
28+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
29+
30+
class IRMultipleOutNodesTest extends InlineExpectationsTest {
31+
IRMultipleOutNodesTest() { this = "IRMultipleOutNodesTest" }
32+
33+
override string getARelevantTag() { result = "ir-count(" + any(ReturnKind k).toString() + ")" }
34+
35+
override predicate hasActualResult(Location location, string element, string tag, string value) {
36+
exists(DataFlowCall call, int n, ReturnKind kind |
37+
call.getLocation() = location and
38+
n = strictcount(getAnOutNode(call, kind)) and
39+
n > 1 and
40+
element = call.toString() and
41+
tag = "ir-count(" + kind.toString() + ")" and
42+
value = n.toString()
43+
)
44+
}
45+
}
46+
}

cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,6 @@ compatibleTypesReflexive
1212
unreachableNodeCCtx
1313
localCallNodes
1414
postIsNotPre
15-
| A.cpp:98:12:98:18 | new indirection | PostUpdateNode should not equal its pre-update node. |
16-
| B.cpp:6:15:6:24 | new indirection | PostUpdateNode should not equal its pre-update node. |
17-
| B.cpp:15:15:15:27 | new indirection | PostUpdateNode should not equal its pre-update node. |
18-
| C.cpp:22:12:22:21 | new indirection | PostUpdateNode should not equal its pre-update node. |
19-
| C.cpp:24:16:24:25 | new indirection | PostUpdateNode should not equal its pre-update node. |
20-
| D.cpp:28:15:28:24 | new indirection | PostUpdateNode should not equal its pre-update node. |
21-
| D.cpp:35:15:35:24 | new indirection | PostUpdateNode should not equal its pre-update node. |
22-
| D.cpp:42:15:42:24 | new indirection | PostUpdateNode should not equal its pre-update node. |
23-
| D.cpp:49:15:49:24 | new indirection | PostUpdateNode should not equal its pre-update node. |
24-
| D.cpp:56:15:56:24 | new indirection | PostUpdateNode should not equal its pre-update node. |
2515
postHasUniquePre
2616
uniquePostUpdate
2717
| aliasing.cpp:70:11:70:11 | definition of w indirection | Node has multiple PostUpdateNodes. |
@@ -42,16 +32,6 @@ postIsInSameCallable
4232
reverseRead
4333
argHasPostUpdate
4434
postWithInFlow
45-
| A.cpp:98:12:98:18 | new indirection | PostUpdateNode should not be the target of local flow. |
46-
| B.cpp:6:15:6:24 | new indirection | PostUpdateNode should not be the target of local flow. |
47-
| B.cpp:15:15:15:27 | new indirection | PostUpdateNode should not be the target of local flow. |
48-
| C.cpp:22:12:22:21 | new indirection | PostUpdateNode should not be the target of local flow. |
49-
| C.cpp:24:16:24:25 | new indirection | PostUpdateNode should not be the target of local flow. |
50-
| D.cpp:28:15:28:24 | new indirection | PostUpdateNode should not be the target of local flow. |
51-
| D.cpp:35:15:35:24 | new indirection | PostUpdateNode should not be the target of local flow. |
52-
| D.cpp:42:15:42:24 | new indirection | PostUpdateNode should not be the target of local flow. |
53-
| D.cpp:49:15:49:24 | new indirection | PostUpdateNode should not be the target of local flow. |
54-
| D.cpp:56:15:56:24 | new indirection | PostUpdateNode should not be the target of local flow. |
5535
| realistic.cpp:54:16:54:47 | memcpy output argument | PostUpdateNode should not be the target of local flow. |
5636
| realistic.cpp:60:16:60:18 | memcpy output argument | PostUpdateNode should not be the target of local flow. |
5737
viableImplInCallContextTooLarge

cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ edges
3131
| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new indirection [c] |
3232
| A.cpp:57:11:57:24 | new indirection [c] | A.cpp:28:8:28:10 | this indirection [c] |
3333
| A.cpp:57:11:57:24 | new indirection [c] | A.cpp:57:10:57:32 | call to get |
34-
| A.cpp:57:11:57:24 | new indirection [c] | A.cpp:57:11:57:24 | new indirection [c] |
3534
| A.cpp:57:17:57:23 | new | A.cpp:23:10:23:10 | c |
3635
| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] |
3736
| A.cpp:57:17:57:23 | new | A.cpp:57:17:57:23 | new |

cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,6 @@ compatibleTypesReflexive
223223
unreachableNodeCCtx
224224
localCallNodes
225225
postIsNotPre
226-
| condition_decls.cpp:3:13:3:22 | new indirection | PostUpdateNode should not equal its pre-update node. |
227-
| defdestructordeleteexpr.cpp:4:9:4:15 | new indirection | PostUpdateNode should not equal its pre-update node. |
228-
| deleteexpr.cpp:7:9:7:15 | new indirection | PostUpdateNode should not equal its pre-update node. |
229-
| ir.cpp:943:3:943:11 | new indirection | PostUpdateNode should not equal its pre-update node. |
230-
| ir.cpp:947:3:947:25 | new indirection | PostUpdateNode should not equal its pre-update node. |
231226
postHasUniquePre
232227
uniquePostUpdate
233228
| cpp11.cpp:82:17:82:17 | this indirection | Node has multiple PostUpdateNodes. |
@@ -251,19 +246,14 @@ postIsInSameCallable
251246
reverseRead
252247
argHasPostUpdate
253248
postWithInFlow
254-
| condition_decls.cpp:3:13:3:22 | new indirection | PostUpdateNode should not be the target of local flow. |
255249
| cpp11.cpp:77:19:77:21 | call to Val | PostUpdateNode should not be the target of local flow. |
256250
| cpp11.cpp:82:11:82:14 | call to Val | PostUpdateNode should not be the target of local flow. |
257251
| cpp11.cpp:82:45:82:48 | call to Val | PostUpdateNode should not be the target of local flow. |
258252
| cpp11.cpp:82:51:82:51 | call to Val | PostUpdateNode should not be the target of local flow. |
259-
| defdestructordeleteexpr.cpp:4:9:4:15 | new indirection | PostUpdateNode should not be the target of local flow. |
260-
| deleteexpr.cpp:7:9:7:15 | new indirection | PostUpdateNode should not be the target of local flow. |
261253
| ir.cpp:809:7:809:13 | call to Base | PostUpdateNode should not be the target of local flow. |
262254
| ir.cpp:810:7:810:26 | call to Base | PostUpdateNode should not be the target of local flow. |
263255
| ir.cpp:823:7:823:13 | call to Base | PostUpdateNode should not be the target of local flow. |
264256
| ir.cpp:824:7:824:26 | call to Base | PostUpdateNode should not be the target of local flow. |
265-
| ir.cpp:943:3:943:11 | new indirection | PostUpdateNode should not be the target of local flow. |
266-
| ir.cpp:947:3:947:25 | new indirection | PostUpdateNode should not be the target of local flow. |
267257
| try_catch.cpp:7:8:7:8 | call to exception | PostUpdateNode should not be the target of local flow. |
268258
viableImplInCallContextTooLarge
269259
uniqueParameterNodeAtPosition

0 commit comments

Comments
 (0)