Skip to content

Commit e1ffc8d

Browse files
authored
Merge pull request github#14171 from MathiasVP/fix-dataflow-out-of-post-update-nodes
C++: Fix dataflow out of post update nodes
2 parents 354a55c + 9f89c63 commit e1ffc8d

File tree

7 files changed

+84
-13
lines changed

7 files changed

+84
-13
lines changed

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

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -638,12 +638,24 @@ private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
638638
)
639639
}
640640

641+
/**
642+
* Holds if `nodeFrom` flows to `nodeTo` because there is `def-use` or
643+
* `use-use` flow from `defOrUse` to `use`.
644+
*
645+
* `uncertain` is `true` if the `defOrUse` is an uncertain definition.
646+
*/
647+
private predicate localSsaFlow(
648+
SsaDefOrUse defOrUse, Node nodeFrom, UseOrPhi use, Node nodeTo, boolean uncertain
649+
) {
650+
nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
651+
adjacentDefRead(defOrUse, use) and
652+
useToNode(use, nodeTo) and
653+
nodeFrom != nodeTo
654+
}
655+
641656
private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
642657
exists(UseOrPhi use |
643-
nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
644-
adjacentDefRead(defOrUse, use) and
645-
useToNode(use, nodeTo) and
646-
nodeFrom != nodeTo
658+
localSsaFlow(defOrUse, nodeFrom, use, nodeTo, uncertain)
647659
or
648660
// Initial global variable value to a first use
649661
nodeFrom.(InitialGlobalValue).getGlobalDef() = defOrUse and
@@ -721,15 +733,62 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
721733
)
722734
}
723735

724-
/** Holds if there is def-use or use-use flow from `pun` to `nodeTo`. */
725-
predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
726-
exists(UseOrPhi use, Node preUpdate |
736+
/**
737+
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
738+
*/
739+
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
740+
exists(UseOrPhi use |
727741
adjustForPointerArith(pun, use) and
728-
useToNode(use, nodeTo) and
742+
useToNode(use, n)
743+
)
744+
}
745+
746+
private predicate stepUntilNotInCall(DataFlowCall call, Node n1, Node n2) {
747+
isArgumentOfCallable(call, n1) and
748+
exists(Node mid | localSsaFlow(_, n1, _, mid, _) |
749+
isArgumentOfCallable(call, mid) and
750+
stepUntilNotInCall(call, mid, n2)
751+
or
752+
not isArgumentOfCallable(call, mid) and
753+
mid = n2
754+
)
755+
}
756+
757+
bindingset[n1, n2]
758+
pragma[inline_late]
759+
private predicate isArgumentOfSameCall(DataFlowCall call, Node n1, Node n2) {
760+
isArgumentOfCallable(call, n1) and isArgumentOfCallable(call, n2)
761+
}
762+
763+
/**
764+
* Holds if there is def-use or use-use flow from `pun` to `nodeTo`.
765+
*
766+
* Note: This is more complex than it sounds. Consider a call such as:
767+
* ```cpp
768+
* write_first_argument(x, x);
769+
* sink(x);
770+
* ```
771+
* Assume flow comes out of the first argument to `write_first_argument`. We
772+
* don't want flow to go to the `x` that's also an argument to
773+
* `write_first_argument` (because we just flowed out of that function, and we
774+
* don't want to flow back into it again).
775+
*
776+
* We do, however, want flow from the output argument to `x` on the next line, and
777+
* similarly we want flow from the second argument of `write_first_argument` to `x`
778+
* on the next line.
779+
*/
780+
predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
781+
exists(Node preUpdate, Node mid |
729782
preUpdate = pun.getPreUpdateNode() and
730-
not exists(DataFlowCall call |
731-
isArgumentOfCallable(call, preUpdate) and isArgumentOfCallable(call, nodeTo)
783+
postUpdateNodeToFirstUse(pun, mid)
784+
|
785+
exists(DataFlowCall call |
786+
isArgumentOfSameCall(call, preUpdate, mid) and
787+
stepUntilNotInCall(call, mid, nodeTo)
732788
)
789+
or
790+
not isArgumentOfSameCall(_, preUpdate, mid) and
791+
nodeTo = mid
733792
)
734793
}
735794

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
WARNING: Module TaintedWithPath has been deprecated and may be removed in future (tainted.ql:10,8-47)
22
WARNING: Predicate tainted has been deprecated and may be removed in future (tainted.ql:21,3-28)
3-
failures
43
testFailures
4+
failures

cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,4 +788,12 @@ void test_sometimes_calls_sink_switch() {
788788
sometimes_calls_sink_switch(source(), 1);
789789
sometimes_calls_sink_switch(0, 0);
790790
sometimes_calls_sink_switch(source(), 0);
791+
}
792+
793+
void intPointerSource(int *ref_source, const int* another_arg);
794+
795+
void test() {
796+
MyStruct a;
797+
intPointerSource(a.content, a.content);
798+
indirect_sink(a.content); // $ ast ir
791799
}

cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ WARNING: Module DataFlow has been deprecated and may be removed in future (test.
55
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:40,25-33)
66
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:42,17-25)
77
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:46,20-28)
8-
failures
98
testFailures
9+
failures

cpp/ql/test/library-tests/dataflow/dataflow-tests/uninitialized.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@
4646
| test.cpp:595:8:595:9 | xs | test.cpp:597:9:597:10 | xs |
4747
| test.cpp:733:7:733:7 | x | test.cpp:734:41:734:41 | x |
4848
| test.cpp:733:7:733:7 | x | test.cpp:735:8:735:8 | x |
49+
| test.cpp:796:12:796:12 | a | test.cpp:797:20:797:20 | a |
50+
| test.cpp:796:12:796:12 | a | test.cpp:797:31:797:31 | a |
51+
| test.cpp:796:12:796:12 | a | test.cpp:798:17:798:17 | a |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
failures
21
testFailures
2+
failures

cpp/ql/test/query-tests/Security/CWE/CWE-119/semmle/tests/OverflowDestination.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edges
77
| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:15:53:17 | src indirection |
88
| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:54:9:54:12 | memcpy output argument |
99
| overflowdestination.cpp:53:9:53:12 | memcpy output argument | overflowdestination.cpp:54:9:54:12 | memcpy output argument |
10+
| overflowdestination.cpp:54:9:54:12 | memcpy output argument | overflowdestination.cpp:54:9:54:12 | memcpy output argument |
1011
| overflowdestination.cpp:57:52:57:54 | src indirection | overflowdestination.cpp:64:16:64:19 | src2 indirection |
1112
| overflowdestination.cpp:73:8:73:10 | fgets output argument | overflowdestination.cpp:75:30:75:32 | src indirection |
1213
| overflowdestination.cpp:73:8:73:10 | fgets output argument | overflowdestination.cpp:76:30:76:32 | src indirection |

0 commit comments

Comments
 (0)