From 4ddf12119ddfbd1c222c845e1bf0c8c5162fb921 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 30 Apr 2020 15:58:00 +0200 Subject: [PATCH 1/6] C++: Don't suppress consistency checks for calls See https://github.com/github/codeql/pull/3162#discussion_r400849713. --- .../code/cpp/dataflow/internal/DataFlowPrivate.qll | 3 --- .../dataflow-tests/dataflow-consistency.expected | 1 + .../dataflow/fields/dataflow-consistency.expected | 11 +++++++++++ .../syntax-zoo/dataflow-consistency.expected | 4 ++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 1c6ab9a8c46b..43359fb329be 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -311,9 +311,6 @@ predicate isImmutableOrUnobservable(Node n) { or dt.getBaseType() instanceof RoutineType ) - or - // Isn't something we can track - n.asExpr() instanceof Call // The above list of cases isn't exhaustive, but it narrows down the // consistency alerts enough that most of them are interesting. } diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index 10dc6d411b7c..ee4b184b413a 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -23,6 +23,7 @@ postIsInSameCallable reverseRead storeIsPostUpdate argHasPostUpdate +| dispatch.cpp:77:21:77:34 | call to allocateBottom | ArgumentNode is missing PostUpdateNode. | | dispatch.cpp:78:23:78:39 | * ... | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index cdf03b905082..caf730a426bc 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -43,16 +43,27 @@ storeIsPostUpdate argHasPostUpdate | A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. | +| A.cpp:56:13:56:15 | call to get | ArgumentNode is missing PostUpdateNode. | | A.cpp:57:17:57:23 | new | ArgumentNode is missing PostUpdateNode. | +| A.cpp:57:28:57:30 | call to get | ArgumentNode is missing PostUpdateNode. | | A.cpp:64:21:64:28 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:73:25:73:32 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:126:12:126:18 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:160:32:160:59 | new | ArgumentNode is missing PostUpdateNode. | +| D.cpp:22:25:22:31 | call to getElem | ArgumentNode is missing PostUpdateNode. | | D.cpp:29:24:29:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:36:24:36:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:43:24:43:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:50:24:50:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:57:25:57:41 | new | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:50:17:50:26 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:51:8:51:8 | s | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:51:10:51:20 | call to getDirectly | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:56:19:56:28 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:57:8:57:8 | s | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:57:10:57:22 | call to getIndirectly | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:62:25:62:34 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:63:8:63:8 | s | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:68:21:68:30 | call to user_input | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index 52963b455e2f..ca1e7924286e 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -92,6 +92,10 @@ reverseRead storeIsPostUpdate argHasPostUpdate | builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:33:9:33:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:39:9:39:13 | call to C2 | ArgumentNode is missing PostUpdateNode. | +| conditional_destructors.cpp:42:9:42:13 | call to C2 | ArgumentNode is missing PostUpdateNode. | | cpp11.cpp:77:5:77:17 | unaryFunction | ArgumentNode is missing PostUpdateNode. | | destructors.cpp:52:14:52:16 | ref | ArgumentNode is missing PostUpdateNode. | | ir.cpp:623:5:623:5 | r | ArgumentNode is missing PostUpdateNode. | From 5f74c24d4d021d9ba80070968ae1cdf91d406e3f Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 21 Apr 2020 11:30:07 +0200 Subject: [PATCH 2/6] C++: Test definitions through &, *, ... --- .../dataflow/fields/by_reference.cpp | 67 +++++++++++ .../fields/dataflow-consistency.expected | 7 ++ .../fields/dataflow-ir-consistency.expected | 7 +- .../dataflow/fields/flow.expected | 105 ++++++++++++++++++ .../dataflow/fields/ir-flow.expected | 38 +++++++ .../dataflow/fields/qualifiers.cpp | 50 +++++++++ 6 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index f0e099a06e61..098f13f6a131 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -68,3 +68,70 @@ void test_nonMemberSetA() { nonMemberSetA(&s, user_input()); sink(nonMemberGetA(&s)); // flow } + +//////////////////// + +struct Inner { + void *a; +}; + +struct Outer { + Inner inner_nested, *inner_ptr; + void *a; +}; + +void taint_inner_a_ptr(Inner *inner) { + inner->a = user_input(); +} + +void taint_inner_a_ref(Inner &inner) { + inner.a = user_input(); +} + +void taint_a_ptr(void **pa) { + *pa = user_input(); +} + +void taint_a_ref(void *&pa) { + pa = user_input(); +} + +void test_outer_with_ptr(Outer *pouter) { + Outer outer; + + taint_inner_a_ptr(&outer.inner_nested); + taint_inner_a_ptr(outer.inner_ptr); + taint_a_ptr(&outer.a); + + taint_inner_a_ptr(&pouter->inner_nested); + taint_inner_a_ptr(pouter->inner_ptr); + taint_a_ptr(&pouter->a); + + sink(outer.inner_nested.a); // flow [NOT DETECTED by AST] + sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] + sink(outer.a); // flow [NOT DETECTED] + + sink(pouter->inner_nested.a); // flow [NOT DETECTED by AST] + sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] + sink(pouter->a); // flow [NOT DETECTED] +} + +void test_outer_with_ref(Outer *pouter) { + Outer outer; + + taint_inner_a_ref(outer.inner_nested); + taint_inner_a_ref(*outer.inner_ptr); + taint_a_ref(outer.a); + + taint_inner_a_ref(pouter->inner_nested); + taint_inner_a_ref(*pouter->inner_ptr); + taint_a_ref(pouter->a); + + sink(outer.inner_nested.a); // flow + sink(outer.inner_ptr->a); // flow [NOT DETECTED] + sink(outer.a); // flow [NOT DETECTED by IR] + + sink(pouter->inner_nested.a); // flow + sink(pouter->inner_ptr->a); // flow [NOT DETECTED] + sink(pouter->a); // flow [NOT DETECTED by IR] +} diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index caf730a426bc..c8f0c9094d80 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -67,3 +67,10 @@ argHasPostUpdate | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:68:21:68:30 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:123:21:123:36 | * ... | ArgumentNode is missing PostUpdateNode. | +| by_reference.cpp:127:21:127:38 | * ... | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:27:28:27:37 | call to user_input | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:32:23:32:30 | call to getInner | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:32:35:32:44 | call to user_input | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:37:19:37:35 | * ... | ArgumentNode is missing PostUpdateNode. | +| qualifiers.cpp:37:38:37:47 | call to user_input | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected index 227023fda166..9d0470bd4b25 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-ir-consistency.expected @@ -1,13 +1,16 @@ uniqueEnclosingCallable uniqueTypeBound +| by_reference.cpp:106:21:106:41 | Chi | Node should have one type bound but has 2. | +| by_reference.cpp:126:21:126:40 | Chi | Node should have one type bound but has 2. | uniqueTypeRepr uniqueNodeLocation -| D.cpp:1:17:1:17 | o | Node should have one location but has 2. | -| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 2. | +| D.cpp:1:17:1:17 | o | Node should have one location but has 3. | +| by_reference.cpp:1:17:1:17 | o | Node should have one location but has 3. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | | file://:0:0:0:0 | p#0 | Node should have one location but has 0. | +| qualifiers.cpp:1:17:1:17 | o | Node should have one location but has 3. | missingLocation | Nodes without location: 4 | uniqueNodeToString diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 650b5dcc0735..51228f4482f2 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -167,6 +167,42 @@ edges | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | | by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | +| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | | complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] | | complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] | | complex.cpp:44:8:44:8 | b [f, a_] | complex.cpp:44:10:44:10 | f [a_] | @@ -205,6 +241,17 @@ edges | constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | | constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | | constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | +| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a | +| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a | | simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | @@ -448,6 +495,43 @@ nodes | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | | by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:87:31:87:35 | inner [a] | semmle.label | inner [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] | +| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | +| by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:111:25:111:25 | a | semmle.label | a | +| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:115:27:115:27 | a | semmle.label | a | +| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] | +| by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | +| by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a | +| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] | +| by_reference.cpp:132:14:132:14 | a | semmle.label | a | +| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | +| by_reference.cpp:136:16:136:16 | a | semmle.label | a | | complex.cpp:34:15:34:15 | b [f, a_] | semmle.label | b [f, a_] | | complex.cpp:34:15:34:15 | b [f, b_] | semmle.label | b [f, b_] | | complex.cpp:44:8:44:8 | b [f, a_] | semmle.label | b [f, a_] | @@ -490,6 +574,19 @@ nodes | constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | | constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | | constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | +| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | +| qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:23:23:23:23 | a | semmle.label | a | +| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | +| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:28:23:28:23 | a | semmle.label | a | | simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | @@ -577,6 +674,12 @@ nodes | by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | +| by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input | | complex.cpp:45:12:45:12 | call to b | complex.cpp:56:13:56:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:56:13:56:22 | call to user_input | call to user_input | @@ -585,6 +688,8 @@ nodes | constructors.cpp:28:12:28:12 | call to a | constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:28:12:28:12 | call to a | call to a flows from $@ | constructors.cpp:36:11:36:20 | call to user_input | call to user_input | | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:35:14:35:23 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:35:14:35:23 | call to user_input | call to user_input | | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | +| qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input | +| qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected index 4286d556cb9a..2d29d3333c2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-flow.expected @@ -25,6 +25,22 @@ edges | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:84:3:84:25 | Store | by_reference.cpp:84:3:84:25 | Chi [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Store | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | +| by_reference.cpp:88:3:88:24 | Store | by_reference.cpp:88:3:88:24 | Chi [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Store | +| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | | simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | | simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | @@ -66,6 +82,24 @@ nodes | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | +| by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:84:3:84:25 | Store | semmle.label | Store | +| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:88:3:88:24 | Store | semmle.label | Store | +| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | +| by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:134:29:134:29 | a | semmle.label | a | | simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | @@ -85,6 +119,10 @@ nodes | aliasing.cpp:80:12:80:13 | m1 | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | m1 flows from $@ | aliasing.cpp:79:11:79:20 | call to user_input | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | m1 flows from $@ | aliasing.cpp:86:10:86:19 | call to user_input | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | struct_init.c:22:11:22:11 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:31:23:31:23 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp new file mode 100644 index 000000000000..790ee7ee1e70 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp @@ -0,0 +1,50 @@ +void sink(void *o); +void *user_input(void); + +namespace qualifiers { + + struct Inner { + void *a; + + void setA(void *value) { this->a = value; } + }; + + void pointerSetA(Inner *inner, void *value) { inner->a = value; } + void referenceSetA(Inner &inner, void *value) { inner.a = value; } + + struct Outer { + Inner *inner; + + Inner *getInner() { return inner; } + }; + + void assignToGetter(Outer outer) { + outer.getInner()->a = user_input(); + sink(outer.inner->a); // flow [NOT DETECTED by IR] + } + + void getterArgument1(Outer outer) { + outer.getInner()->setA(user_input()); + sink(outer.inner->a); // flow [NOT DETECTED by IR] + } + + void getterArgument2(Outer outer) { + pointerSetA(outer.getInner(), user_input()); + sink(outer.inner->a); // flow [NOT DETECTED] + } + + void getterArgument2Ref(Outer outer) { + referenceSetA(*outer.getInner(), user_input()); + sink(outer.inner->a); // flow [NOT DETECTED] + } + + void assignToGetterStar(Outer outer) { + (*outer.getInner()).a = user_input(); + sink(outer.inner->a); // flow [NOT DETECTED] + } + + void assignToGetterAmp(Outer outer) { + (&outer)->getInner()->a = user_input(); + sink(outer.inner->a); // flow [NOT DETECTED] + } +} \ No newline at end of file From 1b1095ee75ee59158b1f925fb21e5d8a8c270620 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 21 Apr 2020 13:58:01 +0200 Subject: [PATCH 3/6] C++: Post-update flow through &, *, +, ... Flow from a definition by reference of a field into its object was working inconsistently and in a very syntax-dependent way. For a function `f` receiving a reference, `f(a->x)` could propagate data back to `a` via the _reverse read_ mechanism in the shared data-flow library, but for a function `g` receiving a pointer, `g(&a->x)` would not work. And `f((*a).x)` would not work either. In all cases, the issue was that the shared data-flow library propagates data backwards between `PostUpdateNode`s only, but there is no `PostUpdateNode` for `a->x` in `g(&a->x)`. This pull request inserts such post-update nodes where appropriate and links them to their neighbors. In this exapmle, flow back from the output parameter of `g` passes first to the `PostUpdateNode` of `&`, then to the (new) `PostUpdateNode` of `a->x`, and finally, as a _reverse read_ with the appropriate field projection, to `a`. --- .../semmle/code/cpp/dataflow/EscapesTree.qll | 8 + .../cpp/dataflow/internal/AddressFlow.qll | 235 ++++++++++++++++++ .../cpp/dataflow/internal/DataFlowUtil.qll | 55 ++-- .../code/cpp/dataflow/internal/FlowVar.qll | 115 ++------- .../internal/AddressConstantExpression.qll | 8 + .../dataflow-consistency.expected | 3 +- .../dataflow-tests/localFlow.expected | 10 +- .../dataflow/fields/by_reference.cpp | 8 +- .../fields/dataflow-consistency.expected | 19 +- .../dataflow/fields/flow.expected | 226 ++++++++++++----- .../dataflow/fields/qualifiers.cpp | 8 +- .../partialdefinitions.expected | 5 +- .../partialdefinitions/partialdefinitions.ql | 2 +- .../dataflow/taint-tests/localTaint.expected | 76 +++--- 14 files changed, 547 insertions(+), 231 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll index 8a99a71f6afe..082b27e727e3 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll @@ -4,6 +4,14 @@ * passed to a function, or similar. */ +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + private import cpp /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll new file mode 100644 index 000000000000..9cb1122a1d8e --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -0,0 +1,235 @@ +/** + * Provides a local analysis for identifying where a variable address + * is effectively taken. Array-like offsets are allowed to pass through but + * not field-like offsets. + * + * This library is specialized to meet the needs of `FlowVar.qll`. + */ + +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + +private import cpp + +/** + * Holds if `f` is an instantiation of the `std::move` or `std::forward` + * template functions, these functions are essentially casts, so we treat them + * as such. + */ +private predicate stdIdentityFunction(Function f) { + f.getNamespace().getParentNamespace() instanceof GlobalNamespace and + f.getNamespace().getName() = "std" and + ( + f.getName() = "move" + or + f.getName() = "forward" + ) +} + +private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { + lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr) + or + // When an object is implicitly converted to a reference to one of its base + // classes, it gets two `Conversion`s: there is first an implicit + // `CStyleCast` to its base class followed by a `ReferenceToExpr` to a + // reference to its base class. Whereas an explicit cast to the base class + // would produce an rvalue, which would not be convertible to an lvalue + // reference, this implicit cast instead produces an lvalue. The following + // case ensures that we propagate the property of being an lvalue through + // such casts. + lvalueIn.getConversion() = lvalueOut and + lvalueOut.(CStyleCast).isImplicit() + or + // C++ only + lvalueIn = lvalueOut.(PrefixCrementOperation).getOperand().getFullyConverted() + or + // C++ only + lvalueIn = lvalueOut.(Assignment).getLValue().getFullyConverted() +} + +private predicate pointerToLvalueStep(Expr pointerIn, Expr lvalueOut) { + pointerIn = lvalueOut.(ArrayExpr).getArrayBase().getFullyConverted() + or + pointerIn = lvalueOut.(PointerDereferenceExpr).getOperand().getFullyConverted() +} + +private predicate lvalueToPointerStep(Expr lvalueIn, Expr pointerOut) { + lvalueIn.getConversion() = pointerOut.(ArrayToPointerConversion) + or + lvalueIn = pointerOut.(AddressOfExpr).getOperand().getFullyConverted() +} + +private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) { + ( + pointerOut instanceof PointerAddExpr + or + pointerOut instanceof PointerSubExpr + ) and + pointerIn = pointerOut.getAChild().getFullyConverted() and + pointerIn.getUnspecifiedType() instanceof PointerType + or + pointerIn = pointerOut.(UnaryPlusExpr).getOperand().getFullyConverted() + or + pointerIn.getConversion() = pointerOut.(Cast) + or + pointerIn.getConversion() = pointerOut.(ParenthesisExpr) + or + pointerIn = pointerOut.(ConditionalExpr).getThen().getFullyConverted() + or + pointerIn = pointerOut.(ConditionalExpr).getElse().getFullyConverted() + or + pointerIn = pointerOut.(CommaExpr).getRightOperand().getFullyConverted() + or + pointerIn = pointerOut.(StmtExpr).getResultExpr().getFullyConverted() +} + +private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) { + lvalueIn.getConversion() = referenceOut.(ReferenceToExpr) +} + +private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { + referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) +} + +private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { + referenceOut = + any(FunctionCall call | + stdIdentityFunction(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) + or + referenceIn.getConversion() = referenceOut.(Cast) + or + referenceIn.getConversion() = referenceOut.(ParenthesisExpr) +} + +private predicate assignmentTo(Expr updated, ControlFlowNode node) { + updated = node.(Assignment).getLValue().getFullyConverted() + or + updated = node.(CrementOperation).getOperand().getFullyConverted() +} + +private predicate lvalueToUpdate(Expr lvalue, Expr outer, ControlFlowNode node) { + ( + exists(Call call | node = call | + outer = call.getQualifier().getFullyConverted() and + outer.getUnspecifiedType() instanceof Class and + not call.getTarget().hasSpecifier("const") + ) + or + assignmentTo(outer, node) + or + exists(DotFieldAccess fa | + // `fa.otherField = ...` or `f(&fa)` or similar + outer = fa.getQualifier().getFullyConverted() and + valueToUpdate(fa, _, node) + ) + ) and + lvalue = outer + or + exists(Expr lvalueMid | + lvalueToLvalueStep(lvalue, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr pointerMid | + lvalueToPointerStep(lvalue, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) + or + exists(Expr referenceMid | + lvalueToReferenceStep(lvalue, referenceMid) and + referenceToUpdate(referenceMid, outer, node) + ) +} + +private predicate pointerToUpdate(Expr pointer, Expr outer, ControlFlowNode node) { + ( + exists(Call call | node = call | + outer = call.getAnArgument().getFullyConverted() and + exists(PointerType pt | pt = outer.getType().stripTopLevelSpecifiers() | + not pt.getBaseType().isConst() + ) + or + outer = call.getQualifier().getFullyConverted() and + outer.getUnspecifiedType() instanceof PointerType and + not call.getTarget().hasSpecifier("const") + ) + or + exists(PointerFieldAccess fa | + // `fa.otherField = ...` or `f(&fa)` or similar + outer = fa.getQualifier().getFullyConverted() and + valueToUpdate(fa, _, node) + ) + ) and + pointer = outer + or + exists(Expr lvalueMid | + pointerToLvalueStep(pointer, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr pointerMid | + pointerToPointerStep(pointer, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) +} + +private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode node) { + exists(Call call | + node = call and + outer = call.getAnArgument().getFullyConverted() and + not stdIdentityFunction(call.getTarget()) and + exists(ReferenceType rt | rt = outer.getType().stripTopLevelSpecifiers() | + not rt.getBaseType().isConst() + ) + ) and + reference = outer + or + exists(Expr lvalueMid | + referenceToLvalueStep(reference, lvalueMid) and + lvalueToUpdate(lvalueMid, outer, node) + ) + or + exists(Expr referenceMid | + referenceToReferenceStep(reference, referenceMid) and + referenceToUpdate(referenceMid, outer, node) + ) +} + +/** + * Holds if `node` is a control-flow node that may modify `inner` (or what it + * points to) through `outer`. The two expressions may be `Conversion`s. Plain + * assignments to variables are not included in this predicate since they are + * assumed to be analyzed by SSA or similar means. + * + * For example, in `f(& (*a).x)`, there are two results: + * - `inner` = `... .x`, `outer` = `&...`, `node` = `f(...)`. + * - `inner` = `a`, `outer` = `(...)`, `node` = `f(...)`. + */ +cached +predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) { + ( + lvalueToUpdate(inner, outer, node) + or + pointerToUpdate(inner, outer, node) + or + referenceToUpdate(inner, outer, node) + ) and + ( + inner instanceof VariableAccess and + // Don't track non-field assignments + (assignmentTo(outer, _) implies inner instanceof FieldAccess) + or + inner instanceof ThisExpr + or + inner instanceof Call + // `baseValue` could also be `*` or `ReferenceDereferenceExpr`, but we + // can't do anything useful with those at the moment. + ) +} diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index d10046226571..cb8eaa5dbfb6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -20,10 +20,12 @@ private newtype TNode = TInstanceParameterNode(MemberFunction f) { exists(f.getBlock()) and not f.isStatic() } or TPreConstructorInitThis(ConstructorFieldInit cfi) or TPostConstructorInitThis(ConstructorFieldInit cfi) or - TThisArgumentPostUpdate(ThisExpr ta) { - exists(Call c, int i | - ta = c.getArgument(i) and - not c.getTarget().getParameter(i).getUnderlyingType().(PointerType).getBaseType().isConst() + TInnerPartialDefinitionNode(Expr e) { + exists(PartialDefinition def, Expr outer | + def.definesExpressions(e, outer) and + // This condition ensures that we don't get two post-update nodes sharing + // the same pre-update node. + e != outer ) } or TUninitializedNode(LocalVariable v) { not v.hasInitializer() } or @@ -66,7 +68,7 @@ class Node extends TNode { * a partial definition of `&x`). */ Expr asPartialDefinition() { - result = this.(PartialDefinitionNode).getPartialDefinition().getDefinedExpr() + this.(PartialDefinitionNode).getPartialDefinition().definesExpressions(_, result) } /** @@ -198,25 +200,23 @@ class ImplicitParameterNode extends ParameterNode, TInstanceParameterNode { * returned. This node will have its `getArgument()` equal to `&x`. */ class DefinitionByReferenceNode extends PartialDefinitionNode { - VariableAccess va; + Expr inner; Expr argument; DefinitionByReferenceNode() { - exists(DefinitionByReference def | - def = this.getPartialDefinition() and - argument = def.getDefinedExpr() and - va = def.getVariableAccess() - ) + this.getPartialDefinition().(DefinitionByReference).definesExpressions(inner, argument) } - override Function getFunction() { result = va.getEnclosingFunction() } + override Function getFunction() { result = inner.getEnclosingFunction() } - override Type getType() { result = va.getType() } + override Type getType() { result = inner.getType() } override string toString() { result = "ref arg " + argument.toString() } override Location getLocation() { result = argument.getLocation() } + override ExprNode getPreUpdateNode() { result.getExpr() = argument } + /** Gets the argument corresponding to this node. */ Expr getArgument() { result = argument } @@ -297,7 +297,7 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } - override Node getPreUpdateNode() { result.asExpr() = pd.getDefinedExpr() } + override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) } override Location getLocation() { result = pd.getActualLocation() } @@ -306,14 +306,23 @@ private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNo override string toString() { result = getPreUpdateNode().toString() + " [post update]" } } -private class ThisArgumentPostUpdateNode extends PostUpdateNode, TThisArgumentPostUpdate { - ThisExpr thisExpr; +/** + * A post-update node on the `e->f` in `f(&e->f)` (and other forms). + */ +private class InnerPartialDefinitionNode extends TInnerPartialDefinitionNode, PostUpdateNode { + Expr e; + + InnerPartialDefinitionNode() { this = TInnerPartialDefinitionNode(e) } - ThisArgumentPostUpdateNode() { this = TThisArgumentPostUpdate(thisExpr) } + override ExprNode getPreUpdateNode() { result.getExpr() = e } - override Node getPreUpdateNode() { result.asExpr() = thisExpr } + override Function getFunction() { result = e.getEnclosingFunction() } - override string toString() { result = "ref arg this" } + override Type getType() { result = e.getType() } + + override string toString() { result = e.toString() + " [inner post update]" } + + override Location getLocation() { result = e.getLocation() } } /** @@ -520,6 +529,14 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or // post-update-`this` -> following-`this`-ref ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) + or + // In `f(&x->a)`, this step provides the flow from post-`&` to post-`x->a`, + // from which there is field flow to `x` via reverse read. + exists(PartialDefinition def, Expr inner, Expr outer | + def.definesExpressions(inner, outer) and + inner = nodeTo.(InnerPartialDefinitionNode).getPreUpdateNode().asExpr() and + outer = nodeFrom.(PartialDefinitionNode).getPreUpdateNode().asExpr() + ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll index d35bc4533b91..72033b0f72df 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/FlowVar.qll @@ -5,6 +5,7 @@ import cpp private import semmle.code.cpp.controlflow.SSA private import semmle.code.cpp.dataflow.internal.SubBasicBlocks +private import semmle.code.cpp.dataflow.internal.AddressFlow /** * A conceptual variable that is assigned only once, like an SSA variable. This @@ -56,15 +57,9 @@ class FlowVar extends TFlowVar { abstract predicate definedByExpr(Expr e, ControlFlowNode node); /** - * Holds if this `FlowVar` corresponds to the data written by a call that - * passes a variable as argument `arg`. - */ - cached - abstract predicate definedByReference(Expr arg); - - /** - * Holds if this `FlowVar` is a `PartialDefinition` whose defined expression - * is `e`. + * Holds if this `FlowVar` is a `PartialDefinition` whose outer defined + * expression is `e`. For example, in `f(&x)`, the outer defined expression + * is `&x`. */ cached abstract predicate definedPartiallyAt(Expr e); @@ -113,39 +108,21 @@ class FlowVar extends TFlowVar { * ``` */ private module PartialDefinitions { - private predicate isInstanceFieldWrite(FieldAccess fa, ControlFlowNode node) { - assignmentLikeOperation(node, _, fa, _) - } - class PartialDefinition extends Expr { + Expr innerDefinedExpr; ControlFlowNode node; PartialDefinition() { - exists(FieldAccess fa | this = fa.getQualifier() | - // `fa = ...`, `fa += ...`, etc. - isInstanceFieldWrite(fa, node) - or - // `fa.a = ...`, `f(&fa)`, etc. - exists(PartialDefinition pd | - node = pd.getSubBasicBlockStart() and - fa = pd.getDefinedExpr() - ) + exists(Expr convertedInner | + valueToUpdate(convertedInner, this.getFullyConverted(), node) and + innerDefinedExpr = convertedInner.getUnconverted() and + not this instanceof Conversion ) - or - // `e.f(...)` - exists(Call call | - this = call.getQualifier() and - not call.getTarget().hasSpecifier("const") - ) and - node = this - or - // `f(e)`, `f(&e)`, etc. - referenceArgument(node, this) } - predicate partiallyDefines(Variable v) { this = v.getAnAccess() } + predicate partiallyDefines(Variable v) { innerDefinedExpr = v.getAnAccess() } - predicate partiallyDefinesThis(ThisExpr e) { this = e } + predicate partiallyDefinesThis(ThisExpr e) { innerDefinedExpr = e } /** * Gets the subBasicBlock where this `PartialDefinition` is defined. @@ -153,14 +130,17 @@ private module PartialDefinitions { ControlFlowNode getSubBasicBlockStart() { result = node } /** - * Gets the expression that is being partially defined. For example in the - * following code: - * ``` - * x.y = 1; - * ``` - * The expression `x` is being partially defined. + * Holds if this partial definition may modify `inner` (or what it points + * to) through `outer`. These expressions will never be `Conversion`s. + * + * For example, in `f(& (*a).x)`, there are two results: + * - `inner` = `... .x`, `outer` = `&...` + * - `inner` = `a`, `outer` = `*` */ - Expr getDefinedExpr() { result = this } + predicate definesExpressions(Expr inner, Expr outer) { + inner = innerDefinedExpr and + outer = this + } /** * Gets the location of this element, adjusted to avoid unknown locations @@ -180,38 +160,7 @@ private module PartialDefinitions { * A partial definition that's a definition by reference. */ class DefinitionByReference extends PartialDefinition { - VariableAccess va; - - DefinitionByReference() { referenceArgument(va, this) } - - VariableAccess getVariableAccess() { result = va } - - override predicate partiallyDefines(Variable v) { va = v.getAnAccess() } - } - - private predicate referenceArgument(VariableAccess va, Expr argument) { - argument = any(Call c).getAnArgument() and - exists(Type argumentType | - argumentType = argument.getFullyConverted().getType().stripTopLevelSpecifiers() - | - argumentType instanceof ReferenceType and - not argumentType.(ReferenceType).getBaseType().isConst() and - va = argument - or - argumentType instanceof PointerType and - not argumentType.(PointerType).getBaseType().isConst() and - ( - // f(variable) - va = argument - or - // f(&variable) - va = argument.(AddressOfExpr).getOperand() - or - // f(&array[0]) - va.getType().getUnspecifiedType() instanceof ArrayType and - va = argument.(AddressOfExpr).getOperand().(ArrayExpr).getArrayBase() - ) - ) + DefinitionByReference() { exists(Call c | this = c.getAnArgument() or this = c.getQualifier()) } } } @@ -328,10 +277,6 @@ module FlowVar_internal { ) } - override predicate definedByReference(Expr arg) { - none() // Not supported for SSA. See `fullySupportedSsaVariable`. - } - override predicate definedPartiallyAt(Expr e) { none() } override predicate definedByInitialValue(StackVariable param) { @@ -416,19 +361,11 @@ module FlowVar_internal { node = sbb.getANode() } - override predicate definedByReference(Expr arg) { - exists(DefinitionByReference def | - def.partiallyDefines(v) and - sbb = def.getSubBasicBlockStart() and - arg = def.getDefinedExpr() - ) - } - override predicate definedPartiallyAt(Expr e) { exists(PartialDefinition p | p.partiallyDefines(v) and sbb = p.getSubBasicBlockStart() and - e = p.getDefinedExpr() + p.definesExpressions(_, e) ) } @@ -441,11 +378,6 @@ module FlowVar_internal { this.definedByInitialValue(_) and result = "initial value of " + v or - exists(Expr arg | - this.definedByReference(arg) and - result = "definition by reference of " + v - ) - or exists(Expr partialDef | this.definedPartiallyAt(partialDef) and result = "partial definition at " + partialDef @@ -454,7 +386,6 @@ module FlowVar_internal { // impossible case not this.definedByExpr(_, _) and not this.definedByInitialValue(_) and - not this.definedByReference(_) and not this.definedPartiallyAt(_) and result = "undefined " + v } diff --git a/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll b/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll index 5152e3005f37..436be8384e87 100644 --- a/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll +++ b/cpp/ql/src/semmle/code/cpp/internal/AddressConstantExpression.qll @@ -1,3 +1,11 @@ +/* + * Maintainer note: this file is one of several files that are similar but not + * identical. Many changes to this file will also apply to the others: + * - AddressConstantExpression.qll + * - AddressFlow.qll + * - EscapesTree.qll + */ + private import cpp predicate addressConstantExpression(Expr e) { diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index ee4b184b413a..cde1b3595b21 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -23,10 +23,9 @@ postIsInSameCallable reverseRead storeIsPostUpdate argHasPostUpdate -| dispatch.cpp:77:21:77:34 | call to allocateBottom | ArgumentNode is missing PostUpdateNode. | -| dispatch.cpp:78:23:78:39 | * ... | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:32:2:32:2 | c | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. | +| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected index c88a62fc2f1f..beda213e5f5c 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/localFlow.expected @@ -14,8 +14,12 @@ | example.c:24:24:24:30 | ... + ... | example.c:24:13:24:30 | ... = ... | | example.c:26:13:26:16 | call to getX | example.c:26:2:26:25 | ... = ... | | example.c:26:18:26:24 | ref arg & ... | example.c:26:2:26:7 | coords | +| example.c:26:18:26:24 | ref arg & ... | example.c:26:19:26:24 | coords [inner post update] | | example.c:26:19:26:24 | coords | example.c:26:18:26:24 | & ... | +| example.c:26:19:26:24 | coords [inner post update] | example.c:26:18:26:24 | & ... | +| example.c:28:22:28:25 | ref arg & ... | example.c:28:23:28:25 | pos [inner post update] | | example.c:28:23:28:25 | pos | example.c:28:22:28:25 | & ... | +| example.c:28:23:28:25 | pos [inner post update] | example.c:28:22:28:25 | & ... | | test.cpp:6:12:6:17 | call to source | test.cpp:7:8:7:9 | t1 | | test.cpp:6:12:6:17 | call to source | test.cpp:8:8:8:9 | t1 | | test.cpp:6:12:6:17 | call to source | test.cpp:9:8:9:9 | t1 | @@ -45,9 +49,10 @@ | test.cpp:383:12:383:13 | 0 | test.cpp:385:8:385:10 | tmp | | test.cpp:384:10:384:13 | & ... | test.cpp:384:3:384:8 | call to memcpy | | test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:3:384:8 | call to memcpy | -| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:33:384:35 | tmp | +| test.cpp:384:10:384:13 | ref arg & ... | test.cpp:384:11:384:13 | tmp [inner post update] | | test.cpp:384:10:384:13 | ref arg & ... | test.cpp:385:8:385:10 | tmp | | test.cpp:384:11:384:13 | tmp | test.cpp:384:10:384:13 | & ... | +| test.cpp:384:11:384:13 | tmp [inner post update] | test.cpp:384:10:384:13 | & ... | | test.cpp:384:17:384:23 | source1 | test.cpp:384:10:384:13 | ref arg & ... | | test.cpp:384:17:384:23 | source1 | test.cpp:384:16:384:23 | & ... | | test.cpp:388:53:388:59 | source1 | test.cpp:391:17:391:23 | source1 | @@ -60,9 +65,10 @@ | test.cpp:390:19:390:21 | tmp | test.cpp:390:18:390:21 | & ... | | test.cpp:391:10:391:13 | & ... | test.cpp:391:3:391:8 | call to memcpy | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:3:391:8 | call to memcpy | -| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:33:391:35 | tmp | +| test.cpp:391:10:391:13 | ref arg & ... | test.cpp:391:11:391:13 | tmp [inner post update] | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:392:8:392:10 | tmp | | test.cpp:391:10:391:13 | ref arg & ... | test.cpp:394:10:394:12 | tmp | | test.cpp:391:11:391:13 | tmp | test.cpp:391:10:391:13 | & ... | +| test.cpp:391:11:391:13 | tmp [inner post update] | test.cpp:391:10:391:13 | & ... | | test.cpp:391:17:391:23 | source1 | test.cpp:391:10:391:13 | ref arg & ... | | test.cpp:391:17:391:23 | source1 | test.cpp:391:16:391:23 | & ... | diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index 098f13f6a131..da9e53723abd 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -107,11 +107,11 @@ void test_outer_with_ptr(Outer *pouter) { taint_inner_a_ptr(pouter->inner_ptr); taint_a_ptr(&pouter->a); - sink(outer.inner_nested.a); // flow [NOT DETECTED by AST] + sink(outer.inner_nested.a); // flow sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] sink(outer.a); // flow [NOT DETECTED] - sink(pouter->inner_nested.a); // flow [NOT DETECTED by AST] + sink(pouter->inner_nested.a); // flow sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] sink(pouter->a); // flow [NOT DETECTED] } @@ -128,10 +128,10 @@ void test_outer_with_ref(Outer *pouter) { taint_a_ref(pouter->a); sink(outer.inner_nested.a); // flow - sink(outer.inner_ptr->a); // flow [NOT DETECTED] + sink(outer.inner_ptr->a); // flow [NOT DETECTED by IR] sink(outer.a); // flow [NOT DETECTED by IR] sink(pouter->inner_nested.a); // flow - sink(pouter->inner_ptr->a); // flow [NOT DETECTED] + sink(pouter->inner_ptr->a); // flow [NOT DETECTED by IR] sink(pouter->a); // flow [NOT DETECTED by IR] } diff --git a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected index c8f0c9094d80..96e05febc523 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -43,34 +43,17 @@ storeIsPostUpdate argHasPostUpdate | A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. | -| A.cpp:56:13:56:15 | call to get | ArgumentNode is missing PostUpdateNode. | +| A.cpp:57:11:57:24 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:57:17:57:23 | new | ArgumentNode is missing PostUpdateNode. | -| A.cpp:57:28:57:30 | call to get | ArgumentNode is missing PostUpdateNode. | | A.cpp:64:21:64:28 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:73:25:73:32 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:126:12:126:18 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:160:32:160:59 | new | ArgumentNode is missing PostUpdateNode. | -| D.cpp:22:25:22:31 | call to getElem | ArgumentNode is missing PostUpdateNode. | | D.cpp:29:24:29:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:36:24:36:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:43:24:43:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:50:24:50:40 | new | ArgumentNode is missing PostUpdateNode. | | D.cpp:57:25:57:41 | new | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:50:17:50:26 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:51:8:51:8 | s | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:51:10:51:20 | call to getDirectly | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:56:19:56:28 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:57:8:57:8 | s | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:57:10:57:22 | call to getIndirectly | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:62:25:62:34 | call to user_input | ArgumentNode is missing PostUpdateNode. | | by_reference.cpp:63:8:63:8 | s | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:68:21:68:30 | call to user_input | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:123:21:123:36 | * ... | ArgumentNode is missing PostUpdateNode. | -| by_reference.cpp:127:21:127:38 | * ... | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:27:28:27:37 | call to user_input | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:32:23:32:30 | call to getInner | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:32:35:32:44 | call to user_input | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:37:19:37:35 | * ... | ArgumentNode is missing PostUpdateNode. | -| qualifiers.cpp:37:38:37:47 | call to user_input | ArgumentNode is missing PostUpdateNode. | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 51228f4482f2..0cc0187b6d09 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -4,8 +4,8 @@ edges | A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] | | A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] | | A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c | -| A.cpp:55:5:55:5 | b [post update] [c] | A.cpp:56:10:56:10 | b [c] | -| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | b [post update] [c] | +| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] | +| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] | | A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get | | A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] | | A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get | @@ -24,8 +24,8 @@ edges | A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] | | A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a | | A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a | -| A.cpp:126:5:126:5 | b [post update] [c] | A.cpp:131:8:131:8 | ref arg b [c] | -| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | b [post update] [c] | +| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] | +| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] | | A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] | | A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c | | A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] | @@ -99,18 +99,18 @@ edges | D.cpp:31:14:31:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:35:15:35:24 | new | D.cpp:37:21:37:21 | e | | D.cpp:37:5:37:5 | b [post update] [box, elem] | D.cpp:38:14:38:14 | b [box, elem] | -| D.cpp:37:8:37:10 | box [post update] [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | -| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | box [post update] [elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | D.cpp:37:5:37:5 | b [post update] [box, elem] | +| D.cpp:37:21:37:21 | e | D.cpp:37:8:37:10 | ref arg box [elem] | | D.cpp:38:14:38:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:42:15:42:24 | new | D.cpp:44:5:44:26 | ... = ... | -| D.cpp:44:5:44:5 | b [post update] [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | D.cpp:45:14:45:14 | b [box, elem] | | D.cpp:44:5:44:26 | ... = ... | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | -| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | b [post update] [box, elem] | +| D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | D.cpp:44:5:44:5 | ref arg b [box, elem] | | D.cpp:45:14:45:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:49:15:49:24 | new | D.cpp:51:27:51:27 | e | -| D.cpp:51:5:51:5 | b [post update] [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | -| D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | D.cpp:51:5:51:5 | b [post update] [box, elem] | -| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | D.cpp:52:14:52:14 | b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | D.cpp:51:5:51:5 | ref arg b [box, elem] | +| D.cpp:51:27:51:27 | e | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | | D.cpp:52:14:52:14 | b [box, elem] | D.cpp:21:30:21:31 | b2 [box, elem] | | D.cpp:56:15:56:24 | new | D.cpp:58:5:58:27 | ... = ... | | D.cpp:58:5:58:12 | boxfield [post update] [box, elem] | D.cpp:58:5:58:12 | this [post update] [boxfield, box, ... (3)] | @@ -155,53 +155,79 @@ edges | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... | | aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] | | aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 | -| by_reference.cpp:50:3:50:3 | s [post update] [a] | by_reference.cpp:51:8:51:8 | s [a] | -| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | s [post update] [a] | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | by_reference.cpp:51:8:51:8 | s [a] | +| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] | | by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly | -| by_reference.cpp:56:3:56:3 | s [post update] [a] | by_reference.cpp:57:8:57:8 | s [a] | -| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | s [post update] [a] | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] | +| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] | | by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | s [post update] [a] | by_reference.cpp:63:8:63:8 | s [a] | -| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | s [post update] [a] | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] | +| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] | | by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] | | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] | | by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] | | by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | +| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] | | by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | | by_reference.cpp:84:3:84:25 | ... = ... | by_reference.cpp:84:3:84:7 | inner [post update] [a] | | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | ... = ... | | by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | | by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:87:31:87:35 | inner [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | | by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:87:31:87:35 | inner [a] | | by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:123:21:123:36 | ref arg * ... [a] | | by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | +| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] | | by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] | | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... | | by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a | | by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a | | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:95:25:95:26 | pa | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a | | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] | | by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a | | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] | | by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a | | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | | by_reference.cpp:124:15:124:19 | outer [post update] [a] | by_reference.cpp:132:8:132:12 | outer [a] | | by_reference.cpp:124:21:124:21 | ref arg a | by_reference.cpp:124:15:124:19 | outer [post update] [a] | | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | by_reference.cpp:136:8:136:13 | pouter [a] | | by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] | | by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | by_reference.cpp:131:14:131:22 | inner_ptr [a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | by_reference.cpp:131:25:131:25 | a | | by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a | | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] | | by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a | | complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] | | complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] | @@ -210,17 +236,17 @@ edges | complex.cpp:45:8:45:8 | b [f, b_] | complex.cpp:45:10:45:10 | f [b_] | | complex.cpp:45:10:45:10 | f [b_] | complex.cpp:45:12:45:12 | call to b | | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | complex.cpp:61:7:61:8 | b1 [f, a_] | -| complex.cpp:55:6:55:6 | f [post update] [a_] | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | -| complex.cpp:55:13:55:22 | call to user_input | complex.cpp:55:6:55:6 | f [post update] [a_] | +| complex.cpp:55:6:55:6 | ref arg f [a_] | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | +| complex.cpp:55:13:55:22 | call to user_input | complex.cpp:55:6:55:6 | ref arg f [a_] | | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | complex.cpp:64:7:64:8 | b2 [f, b_] | -| complex.cpp:56:6:56:6 | f [post update] [b_] | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | -| complex.cpp:56:13:56:22 | call to user_input | complex.cpp:56:6:56:6 | f [post update] [b_] | +| complex.cpp:56:6:56:6 | ref arg f [b_] | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | +| complex.cpp:56:13:56:22 | call to user_input | complex.cpp:56:6:56:6 | ref arg f [b_] | | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | complex.cpp:67:7:67:8 | b3 [f, a_] | -| complex.cpp:57:6:57:6 | f [post update] [a_] | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | -| complex.cpp:57:13:57:22 | call to user_input | complex.cpp:57:6:57:6 | f [post update] [a_] | +| complex.cpp:57:6:57:6 | ref arg f [a_] | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | +| complex.cpp:57:13:57:22 | call to user_input | complex.cpp:57:6:57:6 | ref arg f [a_] | | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | complex.cpp:67:7:67:8 | b3 [f, b_] | -| complex.cpp:58:6:58:6 | f [post update] [b_] | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | -| complex.cpp:58:13:58:22 | call to user_input | complex.cpp:58:6:58:6 | f [post update] [b_] | +| complex.cpp:58:6:58:6 | ref arg f [b_] | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | +| complex.cpp:58:13:58:22 | call to user_input | complex.cpp:58:6:58:6 | ref arg f [b_] | | complex.cpp:61:7:61:8 | b1 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | | complex.cpp:64:7:64:8 | b2 [f, b_] | complex.cpp:34:15:34:15 | b [f, b_] | | complex.cpp:67:7:67:8 | b3 [f, a_] | complex.cpp:34:15:34:15 | b [f, a_] | @@ -241,29 +267,53 @@ edges | constructors.cpp:43:9:43:9 | g [b_] | constructors.cpp:26:15:26:15 | f [b_] | | constructors.cpp:46:9:46:9 | h [a_] | constructors.cpp:26:15:26:15 | f [a_] | | constructors.cpp:46:9:46:9 | h [b_] | constructors.cpp:26:15:26:15 | f [b_] | -| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | qualifiers.cpp:23:10:23:14 | outer [inner, a] | | qualifiers.cpp:22:5:22:38 | ... = ... | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | -| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | +| qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... | | qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] | | qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a | -| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | -| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | -| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | +| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | | qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] | | qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | qualifiers.cpp:43:10:43:14 | outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | qualifiers.cpp:43:16:43:20 | inner [a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | qualifiers.cpp:43:23:43:23 | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | qualifiers.cpp:48:10:48:14 | outer [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a | | simple.cpp:26:15:26:15 | f [a_] | simple.cpp:28:10:28:10 | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | simple.cpp:29:10:29:10 | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | simple.cpp:28:12:28:12 | call to a | | simple.cpp:29:10:29:10 | f [b_] | simple.cpp:29:12:29:12 | call to b | -| simple.cpp:39:5:39:5 | f [post update] [a_] | simple.cpp:45:9:45:9 | f [a_] | -| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | f [post update] [a_] | -| simple.cpp:40:5:40:5 | g [post update] [b_] | simple.cpp:48:9:48:9 | g [b_] | -| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | g [post update] [b_] | -| simple.cpp:41:5:41:5 | h [post update] [a_] | simple.cpp:51:9:51:9 | h [a_] | -| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | h [post update] [a_] | -| simple.cpp:42:5:42:5 | h [post update] [b_] | simple.cpp:51:9:51:9 | h [b_] | -| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | h [post update] [b_] | +| simple.cpp:39:5:39:5 | ref arg f [a_] | simple.cpp:45:9:45:9 | f [a_] | +| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:39:5:39:5 | ref arg f [a_] | +| simple.cpp:40:5:40:5 | ref arg g [b_] | simple.cpp:48:9:48:9 | g [b_] | +| simple.cpp:40:12:40:21 | call to user_input | simple.cpp:40:5:40:5 | ref arg g [b_] | +| simple.cpp:41:5:41:5 | ref arg h [a_] | simple.cpp:51:9:51:9 | h [a_] | +| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:41:5:41:5 | ref arg h [a_] | +| simple.cpp:42:5:42:5 | ref arg h [b_] | simple.cpp:51:9:51:9 | h [b_] | +| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | ref arg h [b_] | | simple.cpp:45:9:45:9 | f [a_] | simple.cpp:26:15:26:15 | f [a_] | | simple.cpp:48:9:48:9 | g [b_] | simple.cpp:26:15:26:15 | f [b_] | | simple.cpp:51:9:51:9 | h [a_] | simple.cpp:26:15:26:15 | f [a_] | @@ -307,7 +357,7 @@ nodes | A.cpp:48:20:48:20 | c | semmle.label | c | | A.cpp:49:10:49:10 | b [c] | semmle.label | b [c] | | A.cpp:49:13:49:13 | c | semmle.label | c | -| A.cpp:55:5:55:5 | b [post update] [c] | semmle.label | b [post update] [c] | +| A.cpp:55:5:55:5 | ref arg b [c] | semmle.label | ref arg b [c] | | A.cpp:55:12:55:19 | new | semmle.label | new | | A.cpp:56:10:56:10 | b [c] | semmle.label | b [c] | | A.cpp:56:13:56:15 | call to get | semmle.label | call to get | @@ -332,7 +382,7 @@ nodes | A.cpp:107:16:107:16 | a | semmle.label | a | | A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] | | A.cpp:120:16:120:16 | a | semmle.label | a | -| A.cpp:126:5:126:5 | b [post update] [c] | semmle.label | b [post update] [c] | +| A.cpp:126:5:126:5 | ref arg b [c] | semmle.label | ref arg b [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | | A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] | | A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] | @@ -416,17 +466,17 @@ nodes | D.cpp:31:14:31:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:35:15:35:24 | new | semmle.label | new | | D.cpp:37:5:37:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:37:8:37:10 | box [post update] [elem] | semmle.label | box [post update] [elem] | +| D.cpp:37:8:37:10 | ref arg box [elem] | semmle.label | ref arg box [elem] | | D.cpp:37:21:37:21 | e | semmle.label | e | | D.cpp:38:14:38:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:42:15:42:24 | new | semmle.label | new | -| D.cpp:44:5:44:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | +| D.cpp:44:5:44:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | | D.cpp:44:5:44:26 | ... = ... | semmle.label | ... = ... | | D.cpp:44:8:44:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | | D.cpp:45:14:45:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:49:15:49:24 | new | semmle.label | new | -| D.cpp:51:5:51:5 | b [post update] [box, elem] | semmle.label | b [post update] [box, elem] | -| D.cpp:51:8:51:14 | call to getBox1 [post update] [elem] | semmle.label | call to getBox1 [post update] [elem] | +| D.cpp:51:5:51:5 | ref arg b [box, elem] | semmle.label | ref arg b [box, elem] | +| D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] | semmle.label | ref arg call to getBox1 [elem] | | D.cpp:51:27:51:27 | e | semmle.label | e | | D.cpp:52:14:52:14 | b [box, elem] | semmle.label | b [box, elem] | | D.cpp:56:15:56:24 | new | semmle.label | new | @@ -479,15 +529,15 @@ nodes | aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] | | aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| by_reference.cpp:50:3:50:3 | s [post update] [a] | semmle.label | s [post update] [a] | +| by_reference.cpp:50:3:50:3 | ref arg s [a] | semmle.label | ref arg s [a] | | by_reference.cpp:50:17:50:26 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:51:8:51:8 | s [a] | semmle.label | s [a] | | by_reference.cpp:51:10:51:20 | call to getDirectly | semmle.label | call to getDirectly | -| by_reference.cpp:56:3:56:3 | s [post update] [a] | semmle.label | s [post update] [a] | +| by_reference.cpp:56:3:56:3 | ref arg s [a] | semmle.label | ref arg s [a] | | by_reference.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:57:8:57:8 | s [a] | semmle.label | s [a] | | by_reference.cpp:57:10:57:22 | call to getIndirectly | semmle.label | call to getIndirectly | -| by_reference.cpp:62:3:62:3 | s [post update] [a] | semmle.label | s [post update] [a] | +| by_reference.cpp:62:3:62:3 | ref arg s [a] | semmle.label | ref arg s [a] | | by_reference.cpp:62:25:62:34 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:63:8:63:8 | s [a] | semmle.label | s [a] | | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | semmle.label | call to getThroughNonMember | @@ -504,32 +554,56 @@ nodes | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:95:25:95:26 | pa | semmle.label | pa | | by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:102:22:102:26 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | +| by_reference.cpp:102:28:102:39 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | | by_reference.cpp:103:21:103:25 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:106:21:106:41 | ref arg & ... [a] | semmle.label | ref arg & ... [a] | +| by_reference.cpp:106:22:106:27 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | +| by_reference.cpp:106:30:106:41 | inner_nested [inner post update] [a] | semmle.label | inner_nested [inner post update] [a] | | by_reference.cpp:107:21:107:26 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] | semmle.label | ref arg inner_ptr [a] | +| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | +| by_reference.cpp:110:14:110:25 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:110:27:110:27 | a | semmle.label | a | | by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | | by_reference.cpp:111:14:111:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | | by_reference.cpp:111:25:111:25 | a | semmle.label | a | +| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | +| by_reference.cpp:114:16:114:27 | inner_nested [a] | semmle.label | inner_nested [a] | +| by_reference.cpp:114:29:114:29 | a | semmle.label | a | | by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | | by_reference.cpp:115:16:115:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | | by_reference.cpp:115:27:115:27 | a | semmle.label | a | | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | semmle.label | outer [post update] [inner_nested, a] | | by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:123:22:123:26 | outer [post update] [inner_ptr, a] | semmle.label | outer [post update] [inner_ptr, a] | +| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | | by_reference.cpp:124:15:124:19 | outer [post update] [a] | semmle.label | outer [post update] [a] | | by_reference.cpp:124:21:124:21 | ref arg a | semmle.label | ref arg a | | by_reference.cpp:126:21:126:26 | pouter [post update] [inner_nested, a] | semmle.label | pouter [post update] [inner_nested, a] | | by_reference.cpp:126:29:126:40 | ref arg inner_nested [a] | semmle.label | ref arg inner_nested [a] | +| by_reference.cpp:127:21:127:38 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| by_reference.cpp:127:22:127:27 | pouter [post update] [inner_ptr, a] | semmle.label | pouter [post update] [inner_ptr, a] | +| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] [a] | semmle.label | inner_ptr [inner post update] [a] | | by_reference.cpp:128:15:128:20 | pouter [post update] [a] | semmle.label | pouter [post update] [a] | | by_reference.cpp:128:23:128:23 | ref arg a | semmle.label | ref arg a | | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | semmle.label | outer [inner_nested, a] | | by_reference.cpp:130:14:130:25 | inner_nested [a] | semmle.label | inner_nested [a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | +| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | semmle.label | outer [inner_ptr, a] | +| by_reference.cpp:131:14:131:22 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:131:25:131:25 | a | semmle.label | a | | by_reference.cpp:132:8:132:12 | outer [a] | semmle.label | outer [a] | | by_reference.cpp:132:14:132:14 | a | semmle.label | a | | by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | semmle.label | pouter [inner_nested, a] | | by_reference.cpp:134:16:134:27 | inner_nested [a] | semmle.label | inner_nested [a] | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | +| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | semmle.label | pouter [inner_ptr, a] | +| by_reference.cpp:135:16:135:24 | inner_ptr [a] | semmle.label | inner_ptr [a] | +| by_reference.cpp:135:27:135:27 | a | semmle.label | a | | by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | | complex.cpp:34:15:34:15 | b [f, a_] | semmle.label | b [f, a_] | @@ -541,16 +615,16 @@ nodes | complex.cpp:45:10:45:10 | f [b_] | semmle.label | f [b_] | | complex.cpp:45:12:45:12 | call to b | semmle.label | call to b | | complex.cpp:55:3:55:4 | b1 [post update] [f, a_] | semmle.label | b1 [post update] [f, a_] | -| complex.cpp:55:6:55:6 | f [post update] [a_] | semmle.label | f [post update] [a_] | +| complex.cpp:55:6:55:6 | ref arg f [a_] | semmle.label | ref arg f [a_] | | complex.cpp:55:13:55:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:56:3:56:4 | b2 [post update] [f, b_] | semmle.label | b2 [post update] [f, b_] | -| complex.cpp:56:6:56:6 | f [post update] [b_] | semmle.label | f [post update] [b_] | +| complex.cpp:56:6:56:6 | ref arg f [b_] | semmle.label | ref arg f [b_] | | complex.cpp:56:13:56:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:57:3:57:4 | b3 [post update] [f, a_] | semmle.label | b3 [post update] [f, a_] | -| complex.cpp:57:6:57:6 | f [post update] [a_] | semmle.label | f [post update] [a_] | +| complex.cpp:57:6:57:6 | ref arg f [a_] | semmle.label | ref arg f [a_] | | complex.cpp:57:13:57:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:58:3:58:4 | b3 [post update] [f, b_] | semmle.label | b3 [post update] [f, b_] | -| complex.cpp:58:6:58:6 | f [post update] [b_] | semmle.label | f [post update] [b_] | +| complex.cpp:58:6:58:6 | ref arg f [b_] | semmle.label | ref arg f [b_] | | complex.cpp:58:13:58:22 | call to user_input | semmle.label | call to user_input | | complex.cpp:61:7:61:8 | b1 [f, a_] | semmle.label | b1 [f, a_] | | complex.cpp:64:7:64:8 | b2 [f, b_] | semmle.label | b2 [f, b_] | @@ -574,32 +648,60 @@ nodes | constructors.cpp:43:9:43:9 | g [b_] | semmle.label | g [b_] | | constructors.cpp:46:9:46:9 | h [a_] | semmle.label | h [a_] | | constructors.cpp:46:9:46:9 | h [b_] | semmle.label | h [b_] | -| qualifiers.cpp:22:5:22:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | +| qualifiers.cpp:22:5:22:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | | qualifiers.cpp:22:5:22:38 | ... = ... | semmle.label | ... = ... | | qualifiers.cpp:22:11:22:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | | qualifiers.cpp:22:27:22:36 | call to user_input | semmle.label | call to user_input | | qualifiers.cpp:23:10:23:14 | outer [inner, a] | semmle.label | outer [inner, a] | | qualifiers.cpp:23:16:23:20 | inner [a] | semmle.label | inner [a] | | qualifiers.cpp:23:23:23:23 | a | semmle.label | a | -| qualifiers.cpp:27:5:27:9 | outer [post update] [inner, a] | semmle.label | outer [post update] [inner, a] | -| qualifiers.cpp:27:11:27:18 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | | qualifiers.cpp:27:28:27:37 | call to user_input | semmle.label | call to user_input | | qualifiers.cpp:28:10:28:14 | outer [inner, a] | semmle.label | outer [inner, a] | | qualifiers.cpp:28:16:28:20 | inner [a] | semmle.label | inner [a] | | qualifiers.cpp:28:23:28:23 | a | semmle.label | a | +| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | semmle.label | ref arg call to getInner [a] | +| qualifiers.cpp:32:35:32:44 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:33:10:33:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:33:16:33:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:33:23:33:23 | a | semmle.label | a | +| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | semmle.label | ref arg * ... [a] | +| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:37:38:37:47 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:38:10:38:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:38:16:38:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:38:23:38:23 | a | semmle.label | a | +| qualifiers.cpp:42:5:42:40 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | semmle.label | * ... [post update] [a] | +| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | semmle.label | ref arg outer [inner, a] | +| qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] | semmle.label | call to getInner [inner post update] [a] | +| qualifiers.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:43:10:43:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:43:16:43:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:43:23:43:23 | a | semmle.label | a | +| qualifiers.cpp:47:5:47:42 | ... = ... | semmle.label | ... = ... | +| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | semmle.label | ref arg & ... [inner, a] | +| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | semmle.label | call to getInner [post update] [a] | +| qualifiers.cpp:47:31:47:40 | call to user_input | semmle.label | call to user_input | +| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] | +| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] | +| qualifiers.cpp:48:23:48:23 | a | semmle.label | a | | simple.cpp:26:15:26:15 | f [a_] | semmle.label | f [a_] | | simple.cpp:26:15:26:15 | f [b_] | semmle.label | f [b_] | | simple.cpp:28:10:28:10 | f [a_] | semmle.label | f [a_] | | simple.cpp:28:12:28:12 | call to a | semmle.label | call to a | | simple.cpp:29:10:29:10 | f [b_] | semmle.label | f [b_] | | simple.cpp:29:12:29:12 | call to b | semmle.label | call to b | -| simple.cpp:39:5:39:5 | f [post update] [a_] | semmle.label | f [post update] [a_] | +| simple.cpp:39:5:39:5 | ref arg f [a_] | semmle.label | ref arg f [a_] | | simple.cpp:39:12:39:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:40:5:40:5 | g [post update] [b_] | semmle.label | g [post update] [b_] | +| simple.cpp:40:5:40:5 | ref arg g [b_] | semmle.label | ref arg g [b_] | | simple.cpp:40:12:40:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:41:5:41:5 | h [post update] [a_] | semmle.label | h [post update] [a_] | +| simple.cpp:41:5:41:5 | ref arg h [a_] | semmle.label | ref arg h [a_] | | simple.cpp:41:12:41:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:42:5:42:5 | h [post update] [b_] | semmle.label | h [post update] [b_] | +| simple.cpp:42:5:42:5 | ref arg h [b_] | semmle.label | ref arg h [b_] | | simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | | simple.cpp:45:9:45:9 | f [a_] | semmle.label | f [a_] | | simple.cpp:48:9:48:9 | g [b_] | semmle.label | g [b_] | @@ -674,11 +776,15 @@ nodes | by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input | | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | call to nonMemberGetA flows from $@ | by_reference.cpp:68:21:68:30 | call to user_input | call to user_input | +| by_reference.cpp:110:27:110:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:110:27:110:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:111:25:111:25 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:111:25:111:25 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | +| by_reference.cpp:114:29:114:29 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:114:29:114:29 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:115:27:115:27 | a | by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:115:27:115:27 | a | a flows from $@ | by_reference.cpp:84:14:84:23 | call to user_input | call to user_input | | by_reference.cpp:130:27:130:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:130:27:130:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:131:25:131:25 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:131:25:131:25 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | +| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input | | by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input | | complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input | @@ -690,6 +796,10 @@ nodes | constructors.cpp:29:12:29:12 | call to b | constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:29:12:29:12 | call to b | call to b flows from $@ | constructors.cpp:36:25:36:34 | call to user_input | call to user_input | | qualifiers.cpp:23:23:23:23 | a | qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:23:23:23:23 | a | a flows from $@ | qualifiers.cpp:22:27:22:36 | call to user_input | call to user_input | | qualifiers.cpp:28:23:28:23 | a | qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:28:23:28:23 | a | a flows from $@ | qualifiers.cpp:27:28:27:37 | call to user_input | call to user_input | +| qualifiers.cpp:33:23:33:23 | a | qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:33:23:33:23 | a | a flows from $@ | qualifiers.cpp:32:35:32:44 | call to user_input | call to user_input | +| qualifiers.cpp:38:23:38:23 | a | qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:38:23:38:23 | a | a flows from $@ | qualifiers.cpp:37:38:37:47 | call to user_input | call to user_input | +| qualifiers.cpp:43:23:43:23 | a | qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:43:23:43:23 | a | a flows from $@ | qualifiers.cpp:42:29:42:38 | call to user_input | call to user_input | +| qualifiers.cpp:48:23:48:23 | a | qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:48:23:48:23 | a | a flows from $@ | qualifiers.cpp:47:31:47:40 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:39:12:39:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:39:12:39:21 | call to user_input | call to user_input | | simple.cpp:28:12:28:12 | call to a | simple.cpp:41:12:41:21 | call to user_input | simple.cpp:28:12:28:12 | call to a | call to a flows from $@ | simple.cpp:41:12:41:21 | call to user_input | call to user_input | | simple.cpp:29:12:29:12 | call to b | simple.cpp:40:12:40:21 | call to user_input | simple.cpp:29:12:29:12 | call to b | call to b flows from $@ | simple.cpp:40:12:40:21 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp index 790ee7ee1e70..c786fb32c643 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/qualifiers.cpp @@ -30,21 +30,21 @@ namespace qualifiers { void getterArgument2(Outer outer) { pointerSetA(outer.getInner(), user_input()); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } void getterArgument2Ref(Outer outer) { referenceSetA(*outer.getInner(), user_input()); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } void assignToGetterStar(Outer outer) { (*outer.getInner()).a = user_input(); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } void assignToGetterAmp(Outer outer) { (&outer)->getInner()->a = user_input(); - sink(outer.inner->a); // flow [NOT DETECTED] + sink(outer.inner->a); // flow [NOT DETECTED by IR] } } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected index aba01f080724..99ef7f36736e 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.expected @@ -1,5 +1,8 @@ | partialdefinitions.cpp:14:2:14:2 | partial def of s | partialdefinitions.cpp:14:2:14:2 | s | partialdefinitions.cpp:14:2:14:8 | ... = ... | +| partialdefinitions.cpp:14:4:14:4 | partial def of x | partialdefinitions.cpp:14:4:14:4 | x | partialdefinitions.cpp:14:2:14:8 | ... = ... | | partialdefinitions.cpp:15:2:15:2 | partial def of s | partialdefinitions.cpp:15:2:15:2 | s | partialdefinitions.cpp:15:2:15:10 | ... = ... | | partialdefinitions.cpp:15:4:15:4 | partial def of y | partialdefinitions.cpp:15:4:15:4 | y | partialdefinitions.cpp:15:2:15:10 | ... = ... | +| partialdefinitions.cpp:15:6:15:6 | partial def of z | partialdefinitions.cpp:15:6:15:6 | z | partialdefinitions.cpp:15:2:15:10 | ... = ... | +| partialdefinitions.cpp:22:29:22:32 | partial def of data | partialdefinitions.cpp:22:29:22:32 | data | partialdefinitions.cpp:22:29:22:40 | ... = ... | | partialdefinitions.cpp:22:29:22:32 | partial def of this | file://:0:0:0:0 | this | partialdefinitions.cpp:22:29:22:40 | ... = ... | -| partialdefinitions.cpp:27:3:27:7 | partial def of myInt | partialdefinitions.cpp:27:3:27:7 | myInt | partialdefinitions.cpp:27:3:27:7 | myInt | +| partialdefinitions.cpp:27:3:27:7 | partial def of myInt | partialdefinitions.cpp:27:3:27:7 | myInt | partialdefinitions.cpp:27:9:27:15 | call to setData | diff --git a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql index bc14c6551592..0fa8c99fde16 100644 --- a/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql +++ b/cpp/ql/test/library-tests/dataflow/partialdefinitions/partialdefinitions.ql @@ -1,5 +1,5 @@ import semmle.code.cpp.dataflow.internal.FlowVar from PartialDefinition def -select def.getActualLocation().toString(), "partial def of " + def.toString(), def.getDefinedExpr(), +select def.getActualLocation().toString(), "partial def of " + def.toString(), def, def.getSubBasicBlockStart() diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index ec88e5bc628e..e75247eb3e1f 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -89,22 +89,30 @@ | format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | | | format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | | | format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | | +| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:116:29:116:29 | i [inner post update] | | | format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | | | format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | | +| format.cpp:116:29:116:29 | i [inner post update] | format.cpp:116:28:116:29 | & ... | | | format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | | | format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | | +| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:121:40:121:40 | i [inner post update] | | | format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | | | format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | | +| format.cpp:121:40:121:40 | i [inner post update] | format.cpp:121:39:121:40 | & ... | | | format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | | | format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | | | format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT | +| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:126:32:126:37 | buffer [inner post update] | | | format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | | | format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | | +| format.cpp:126:32:126:37 | buffer [inner post update] | format.cpp:126:31:126:37 | & ... | | | format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | | | format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | | | format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT | +| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:131:40:131:45 | buffer [inner post update] | | | format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | | | format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | | +| format.cpp:131:40:131:45 | buffer [inner post update] | format.cpp:131:39:131:45 | & ... | | | stl.cpp:67:12:67:17 | call to source | stl.cpp:71:7:71:7 | a | | | stl.cpp:68:16:68:20 | 123 | stl.cpp:68:16:68:21 | call to basic_string | TAINT | | stl.cpp:68:16:68:21 | call to basic_string | stl.cpp:72:7:72:7 | b | | @@ -148,10 +156,10 @@ | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:106:2:106:4 | ss2 | | | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:109:7:109:9 | ss2 | | | stl.cpp:103:25:103:27 | call to basic_stringstream | stl.cpp:111:7:111:9 | ss2 | | -| stl.cpp:105:2:105:4 | ss1 [post update] | stl.cpp:108:7:108:9 | ss1 | | -| stl.cpp:105:2:105:4 | ss1 [post update] | stl.cpp:110:7:110:9 | ss1 | | -| stl.cpp:106:2:106:4 | ss2 [post update] | stl.cpp:109:7:109:9 | ss2 | | -| stl.cpp:106:2:106:4 | ss2 [post update] | stl.cpp:111:7:111:9 | ss2 | | +| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:108:7:108:9 | ss1 | | +| stl.cpp:105:2:105:4 | ref arg ss1 | stl.cpp:110:7:110:9 | ss1 | | +| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:109:7:109:9 | ss2 | | +| stl.cpp:106:2:106:4 | ref arg ss2 | stl.cpp:111:7:111:9 | ss2 | | | stl.cpp:124:16:124:28 | call to basic_string | stl.cpp:125:7:125:11 | path1 | | | stl.cpp:124:17:124:26 | call to user_input | stl.cpp:124:16:124:28 | call to basic_string | TAINT | | stl.cpp:125:7:125:11 | path1 | stl.cpp:125:13:125:17 | call to c_str | TAINT | @@ -226,10 +234,10 @@ | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:93:7:93:9 | mc2 | | | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:94:7:94:9 | mc2 | | | taint.cpp:84:15:84:17 | call to MyClass | taint.cpp:95:7:95:9 | mc2 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:88:7:88:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:89:7:89:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:90:7:90:9 | mc1 | | -| taint.cpp:86:2:86:4 | mc1 [post update] | taint.cpp:91:7:91:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:88:7:88:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:89:7:89:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:90:7:90:9 | mc1 | | +| taint.cpp:86:2:86:4 | ref arg mc1 | taint.cpp:91:7:91:9 | mc1 | | | taint.cpp:100:21:100:21 | i | taint.cpp:106:7:106:7 | i | | | taint.cpp:100:21:100:21 | i | taint.cpp:110:12:110:12 | i | | | taint.cpp:100:21:100:21 | i | taint.cpp:112:12:112:12 | i | | @@ -315,14 +323,18 @@ | taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | | | taint.cpp:181:9:181:9 | p | taint.cpp:181:8:181:9 | * ... | TAINT | | taint.cpp:185:11:185:16 | call to source | taint.cpp:186:11:186:11 | x | | +| taint.cpp:186:10:186:11 | ref arg & ... | taint.cpp:186:11:186:11 | x [inner post update] | | | taint.cpp:186:11:186:11 | x | taint.cpp:186:10:186:11 | & ... | | +| taint.cpp:186:11:186:11 | x [inner post update] | taint.cpp:186:10:186:11 | & ... | | | taint.cpp:192:23:192:28 | source | taint.cpp:194:13:194:18 | source | | | taint.cpp:193:6:193:6 | x | taint.cpp:194:10:194:10 | x | | | taint.cpp:193:6:193:6 | x | taint.cpp:195:7:195:7 | x | | | taint.cpp:194:9:194:10 | & ... | taint.cpp:194:2:194:7 | call to memcpy | | | taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:194:2:194:7 | call to memcpy | | +| taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:194:10:194:10 | x [inner post update] | | | taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:195:7:195:7 | x | | | taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | | +| taint.cpp:194:10:194:10 | x [inner post update] | taint.cpp:194:9:194:10 | & ... | | | taint.cpp:194:13:194:18 | source | taint.cpp:194:2:194:7 | call to memcpy | TAINT | | taint.cpp:194:13:194:18 | source | taint.cpp:194:9:194:10 | ref arg & ... | TAINT | | taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:2:194:7 | call to memcpy | TAINT | @@ -480,10 +492,14 @@ | taint.cpp:344:15:344:15 | ref arg t | taint.cpp:348:17:348:17 | t | | | taint.cpp:344:15:344:15 | ref arg t | taint.cpp:350:7:350:7 | t | | | taint.cpp:345:12:345:12 | ref arg b | taint.cpp:352:7:352:7 | b | | +| taint.cpp:346:12:346:13 | ref arg & ... | taint.cpp:346:13:346:13 | c [inner post update] | | | taint.cpp:346:12:346:13 | ref arg & ... | taint.cpp:353:7:353:7 | c | | | taint.cpp:346:13:346:13 | c | taint.cpp:346:12:346:13 | & ... | | +| taint.cpp:346:13:346:13 | c [inner post update] | taint.cpp:346:12:346:13 | & ... | | +| taint.cpp:347:12:347:13 | ref arg & ... | taint.cpp:347:13:347:13 | d [inner post update] | | | taint.cpp:347:12:347:13 | ref arg & ... | taint.cpp:354:7:354:7 | d | | | taint.cpp:347:13:347:13 | d | taint.cpp:347:12:347:13 | & ... | | +| taint.cpp:347:13:347:13 | d [inner post update] | taint.cpp:347:12:347:13 | & ... | | | taint.cpp:348:14:348:14 | ref arg e | taint.cpp:355:7:355:7 | e | | | taint.cpp:348:17:348:17 | ref arg t | taint.cpp:350:7:350:7 | t | | | taint.cpp:365:24:365:29 | source | taint.cpp:369:13:369:18 | source | | @@ -526,15 +542,15 @@ | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:445:2:445:2 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:446:7:446:7 | d | | | taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:447:7:447:7 | d | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:422:2:422:2 | a | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:423:7:423:7 | a | | -| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:424:7:424:7 | a | | -| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:423:7:423:7 | a | | -| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:424:7:424:7 | a | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:428:2:428:2 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:429:7:429:7 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:430:7:430:7 | b | | -| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:431:7:431:7 | b | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:422:2:422:2 | a | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:423:7:423:7 | a | | +| taint.cpp:421:7:421:7 | ref arg a | taint.cpp:424:7:424:7 | a | | +| taint.cpp:422:2:422:2 | ref arg a | taint.cpp:423:7:423:7 | a | | +| taint.cpp:422:2:422:2 | ref arg a | taint.cpp:424:7:424:7 | a | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:428:2:428:2 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:429:7:429:7 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:430:7:430:7 | b | | +| taint.cpp:427:7:427:7 | ref arg b | taint.cpp:431:7:431:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:429:7:429:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:430:7:430:7 | b | | | taint.cpp:428:2:428:2 | b [post update] | taint.cpp:431:7:431:7 | b | | @@ -553,22 +569,22 @@ | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:438:7:438:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:439:7:439:7 | c | | | taint.cpp:435:7:435:7 | ref arg c | taint.cpp:441:9:441:9 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:437:2:437:2 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:438:7:438:7 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:439:7:439:7 | c | | -| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:441:9:441:9 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:438:7:438:7 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:439:7:439:7 | c | | -| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:441:9:441:9 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:437:2:437:2 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:438:7:438:7 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:439:7:439:7 | c | | +| taint.cpp:436:7:436:7 | ref arg c | taint.cpp:441:9:441:9 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:438:7:438:7 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:439:7:439:7 | c | | +| taint.cpp:437:2:437:2 | ref arg c | taint.cpp:441:9:441:9 | c | | | taint.cpp:438:7:438:7 | ref arg c | taint.cpp:439:7:439:7 | c | | | taint.cpp:438:7:438:7 | ref arg c | taint.cpp:441:9:441:9 | c | | -| taint.cpp:439:7:439:7 | c [post update] | taint.cpp:441:9:441:9 | c | | +| taint.cpp:439:7:439:7 | ref arg c | taint.cpp:441:9:441:9 | c | | | taint.cpp:441:9:441:9 | c | taint.cpp:441:2:441:9 | delete | TAINT | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:445:2:445:2 | d | | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:446:7:446:7 | d | | -| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:447:7:447:7 | d | | -| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:446:7:446:7 | d | | -| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:447:7:447:7 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:445:2:445:2 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:446:7:446:7 | d | | +| taint.cpp:444:7:444:7 | ref arg d | taint.cpp:447:7:447:7 | d | | +| taint.cpp:445:2:445:2 | ref arg d | taint.cpp:446:7:446:7 | d | | +| taint.cpp:445:2:445:2 | ref arg d | taint.cpp:447:7:447:7 | d | | | taint.cpp:452:16:452:16 | a | taint.cpp:454:10:454:10 | a | | | taint.cpp:452:24:452:24 | b | taint.cpp:455:6:455:6 | b | | | taint.cpp:454:10:454:10 | a | taint.cpp:456:6:456:6 | c | | From 32e04b40335bbc37b367aca7d20778a21e98e498 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 6 May 2020 11:17:13 +0200 Subject: [PATCH 4/6] C++: Support std::addressof I didn't add this support in `AddressConstantExpression.qll` since I think it would require extra work and testing to get the constexprness right. My long-term plan for `AddressConstantExpression.qll` is to move its functionality to the extractor. --- .../semmle/code/cpp/dataflow/EscapesTree.qll | 36 ++++++++++++------- .../cpp/dataflow/internal/AddressFlow.qll | 30 +++++++++++----- .../test/library-tests/defuse/addressOf.cpp | 15 ++++++++ .../defuse/isAddressOfAccess.expected | 4 +++ 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll index 082b27e727e3..198bb6b0c4e2 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll @@ -19,15 +19,13 @@ private import cpp * template functions, these functions are essentially casts, so we treat them * as such. */ -private predicate stdIdentityFunction(Function f) { - f.getNamespace().getParentNamespace() instanceof GlobalNamespace and - f.getNamespace().getName() = "std" and - ( - f.getName() = "move" - or - f.getName() = "forward" - ) -} +private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) } + +/** + * Holds if `f` is an instantiation of `std::addressof`, which effectively + * converts a reference to a pointer. + */ +private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") } private predicate lvalueToLvalueStepPure(Expr lvalueIn, Expr lvalueOut) { lvalueIn = lvalueOut.(DotFieldAccess).getQualifier().getFullyConverted() @@ -99,12 +97,17 @@ private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) { } private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { - // This probably cannot happen. It would require an expression to be - // converted to a reference and back again without an intermediate variable - // assignment. referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) } +private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) { + pointerOut = + any(FunctionCall call | + stdAddressOf(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) +} + private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { referenceOut = any(FunctionCall call | @@ -153,6 +156,12 @@ private predicate pointerFromVariableAccess(VariableAccess va, Expr pointer) { pointerToPointerStep(prev, pointer) ) or + // reference -> pointer + exists(Expr prev | + referenceFromVariableAccess(va, prev) and + referenceToPointerStep(prev, pointer) + ) + or // lvalue -> pointer exists(Expr prev | lvalueFromVariableAccess(va, prev) and @@ -177,7 +186,8 @@ private predicate referenceFromVariableAccess(VariableAccess va, Expr reference) private predicate valueMayEscapeAt(Expr e) { exists(Call call | e = call.getAnArgument().getFullyConverted() and - not stdIdentityFunction(call.getTarget()) + not stdIdentityFunction(call.getTarget()) and + not stdAddressOf(call.getTarget()) ) or exists(AssignExpr assign | e = assign.getRValue().getFullyConverted()) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll index 9cb1122a1d8e..3ef6a22bc26b 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -21,15 +21,13 @@ private import cpp * template functions, these functions are essentially casts, so we treat them * as such. */ -private predicate stdIdentityFunction(Function f) { - f.getNamespace().getParentNamespace() instanceof GlobalNamespace and - f.getNamespace().getName() = "std" and - ( - f.getName() = "move" - or - f.getName() = "forward" - ) -} +private predicate stdIdentityFunction(Function f) { f.hasQualifiedName("std", ["move", "forward"]) } + +/** + * Holds if `f` is an instantiation of `std::addressof`, which effectively + * converts a reference to a pointer. + */ +private predicate stdAddressOf(Function f) { f.hasQualifiedName("std", "addressof") } private predicate lvalueToLvalueStep(Expr lvalueIn, Expr lvalueOut) { lvalueIn.getConversion() = lvalueOut.(ParenthesisExpr) @@ -96,6 +94,14 @@ private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) { referenceIn.getConversion() = lvalueOut.(ReferenceDereferenceExpr) } +private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) { + pointerOut = + any(FunctionCall call | + stdAddressOf(call.getTarget()) and + referenceIn = call.getArgument(0).getFullyConverted() + ) +} + private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) { referenceOut = any(FunctionCall call | @@ -185,6 +191,7 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode node = call and outer = call.getAnArgument().getFullyConverted() and not stdIdentityFunction(call.getTarget()) and + not stdAddressOf(call.getTarget()) and exists(ReferenceType rt | rt = outer.getType().stripTopLevelSpecifiers() | not rt.getBaseType().isConst() ) @@ -196,6 +203,11 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode lvalueToUpdate(lvalueMid, outer, node) ) or + exists(Expr pointerMid | + referenceToPointerStep(reference, pointerMid) and + pointerToUpdate(pointerMid, outer, node) + ) + or exists(Expr referenceMid | referenceToReferenceStep(reference, referenceMid) and referenceToUpdate(referenceMid, outer, node) diff --git a/cpp/ql/test/library-tests/defuse/addressOf.cpp b/cpp/ql/test/library-tests/defuse/addressOf.cpp index 6d6c1265b679..4954159c13d8 100644 --- a/cpp/ql/test/library-tests/defuse/addressOf.cpp +++ b/cpp/ql/test/library-tests/defuse/addressOf.cpp @@ -63,3 +63,18 @@ void nonexamples(int *ptr, int &ref) { nonexamples(&*ptr, ref); } } + + +namespace std { + template + constexpr T *addressof(T &obj) noexcept { + return __builtin_addressof(obj); + } +} + +void use_std_addressof() { + int x = 0; + int *y = std::addressof(x) + *std::addressof(x); +} + +// semmle-extractor-options: --clang diff --git a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected index ff7ee26843d5..e85614e48a8a 100644 --- a/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected +++ b/cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected @@ -25,6 +25,10 @@ | addressOf.cpp:62:11:62:13 | ptr | | | addressOf.cpp:63:19:63:21 | ptr | | | addressOf.cpp:63:24:63:26 | ref | non-const address | +| addressOf.cpp:71:32:71:34 | obj | | +| addressOf.cpp:71:32:71:34 | obj | | +| addressOf.cpp:77:27:77:27 | x | non-const address | +| addressOf.cpp:77:48:77:48 | x | | | file://:0:0:0:0 | captured | | | file://:0:0:0:0 | captured | | | file://:0:0:0:0 | captured | non-const address | From 5e8bd0a72442dce5b9d048631bf72617810551e3 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Thu, 7 May 2020 16:38:15 +0200 Subject: [PATCH 5/6] C++: Fix variable name in comment --- cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll index 3ef6a22bc26b..b3f8cd02828b 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/AddressFlow.qll @@ -241,7 +241,7 @@ predicate valueToUpdate(Expr inner, Expr outer, ControlFlowNode node) { inner instanceof ThisExpr or inner instanceof Call - // `baseValue` could also be `*` or `ReferenceDereferenceExpr`, but we + // `inner` could also be `*` or `ReferenceDereferenceExpr`, but we // can't do anything useful with those at the moment. ) } From 71c21e6eca4377f064446459de356335ac213812 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 11 May 2020 08:10:51 +0200 Subject: [PATCH 6/6] C++: Accept test changes forgotten in 32e04b403 Adding a new test case leads to changes in all `.expected` files in its directory. The new results show that the `DefinitionsAndUses` library does not model `std::addressof` correctly, but that library is not intended to be used for new code. --- cpp/ql/test/library-tests/defuse/definition.expected | 2 ++ cpp/ql/test/library-tests/defuse/definitionUsePair.expected | 1 + cpp/ql/test/library-tests/defuse/exprDefinition.expected | 2 ++ cpp/ql/test/library-tests/defuse/parameterUsePair.expected | 2 ++ cpp/ql/test/library-tests/defuse/useOfVar.expected | 3 +++ cpp/ql/test/library-tests/defuse/useOfVarActual.expected | 2 ++ 6 files changed, 12 insertions(+) diff --git a/cpp/ql/test/library-tests/defuse/definition.expected b/cpp/ql/test/library-tests/defuse/definition.expected index 35d91efd916f..cf7ff1942e2c 100644 --- a/cpp/ql/test/library-tests/defuse/definition.expected +++ b/cpp/ql/test/library-tests/defuse/definition.expected @@ -17,6 +17,8 @@ | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:57:18:57:45 | ... + ... | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:58:18:58:18 | a | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | +| addressOf.cpp:77:8:77:8 | y | addressOf.cpp:77:12:77:49 | ... + ... | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:26:5:26:7 | ... -- | diff --git a/cpp/ql/test/library-tests/defuse/definitionUsePair.expected b/cpp/ql/test/library-tests/defuse/definitionUsePair.expected index 7c0e5bd3f8e4..963895272656 100644 --- a/cpp/ql/test/library-tests/defuse/definitionUsePair.expected +++ b/cpp/ql/test/library-tests/defuse/definitionUsePair.expected @@ -12,6 +12,7 @@ | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:49:12:49:39 | [...](...){...} | addressOf.cpp:50:3:50:4 | f2 | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:56:13:56:28 | {...} | addressOf.cpp:57:19:57:19 | a | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:57:18:57:45 | ... + ... | addressOf.cpp:58:18:58:18 | a | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | addressOf.cpp:77:27:77:27 | x | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | indirect_use.cpp:26:5:26:5 | p | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:26:5:26:7 | ... -- | indirect_use.cpp:27:17:27:17 | p | diff --git a/cpp/ql/test/library-tests/defuse/exprDefinition.expected b/cpp/ql/test/library-tests/defuse/exprDefinition.expected index ec45bd97f2b7..c2431284bfaa 100644 --- a/cpp/ql/test/library-tests/defuse/exprDefinition.expected +++ b/cpp/ql/test/library-tests/defuse/exprDefinition.expected @@ -1,6 +1,8 @@ | addressOf.cpp:47:8:47:9 | f1 | addressOf.cpp:47:12:47:31 | [...](...){...} | addressOf.cpp:47:12:47:31 | [...](...){...} | | addressOf.cpp:49:8:49:9 | f2 | addressOf.cpp:49:12:49:39 | [...](...){...} | addressOf.cpp:49:12:49:39 | [...](...){...} | | addressOf.cpp:56:7:56:7 | a | addressOf.cpp:56:13:56:28 | {...} | addressOf.cpp:56:13:56:28 | {...} | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:76:10:76:11 | 0 | addressOf.cpp:76:10:76:11 | 0 | +| addressOf.cpp:77:8:77:8 | y | addressOf.cpp:77:12:77:49 | ... + ... | addressOf.cpp:77:12:77:49 | ... + ... | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:20:14:20:15 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:25:10:25:10 | p | indirect_use.cpp:25:14:25:19 | ... + ... | indirect_use.cpp:25:14:25:19 | ... + ... | | indirect_use.cpp:35:10:35:10 | p | indirect_use.cpp:35:14:35:15 | ip | indirect_use.cpp:35:14:35:15 | ip | diff --git a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected index c2eff5fac121..7b3cdc26e5fc 100644 --- a/cpp/ql/test/library-tests/defuse/parameterUsePair.expected +++ b/cpp/ql/test/library-tests/defuse/parameterUsePair.expected @@ -6,6 +6,8 @@ | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | | indirect_use.cpp:30:28:30:30 | ppp | indirect_use.cpp:31:19:31:21 | ppp | diff --git a/cpp/ql/test/library-tests/defuse/useOfVar.expected b/cpp/ql/test/library-tests/defuse/useOfVar.expected index 1efe7e5dac7b..79a0524ec9d4 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVar.expected +++ b/cpp/ql/test/library-tests/defuse/useOfVar.expected @@ -23,6 +23,9 @@ | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | | addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:27:77:27 | x | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip | diff --git a/cpp/ql/test/library-tests/defuse/useOfVarActual.expected b/cpp/ql/test/library-tests/defuse/useOfVarActual.expected index 0cd9366f1999..c17bbfd6203b 100644 --- a/cpp/ql/test/library-tests/defuse/useOfVarActual.expected +++ b/cpp/ql/test/library-tests/defuse/useOfVarActual.expected @@ -10,6 +10,8 @@ | addressOf.cpp:55:17:55:17 | i | addressOf.cpp:56:24:56:24 | i | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:62:11:62:13 | ptr | | addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr | +| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj | +| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x | | indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip | | indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p | | indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |