Skip to content

Commit 072adaa

Browse files
committed
C++: Require that no override of the called pure virtual function exists in any base class. This removes the false positive in the testcase. Based on the results on LGTM we have agreed to set the @precision to very-high.
1 parent 4a7f910 commit 072adaa

File tree

3 files changed

+15
-18
lines changed

3 files changed

+15
-18
lines changed

cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* @kind path-problem
77
* @id cpp/unsafe-use-of-this
88
* @problem.severity error
9-
* @precision high
9+
* @precision very-high
1010
* @tags correctness
1111
* language-features
1212
* security
@@ -67,12 +67,11 @@ predicate getThisArgumentInitParam(
6767
init.getIRVariable() instanceof IRThisVariable
6868
}
6969

70-
/** Holds if `instr` is a `this` pointer of type `c` used by the call instruction `call`. */
71-
predicate isSink(Instruction instr, CallInstruction call, Class c) {
70+
/** Holds if `instr` is a `this` pointer used by the call instruction `call`. */
71+
predicate isSink(Instruction instr, CallInstruction call) {
7272
exists(PureVirtualFunction func |
7373
call.getStaticCallTarget() = func and
7474
call.getThisArgument() = instr and
75-
instr.getResultType().stripType() = c and
7675
// Weed out implicit calls to destructors of a base class
7776
not func instanceof Destructor
7877
)
@@ -95,13 +94,12 @@ predicate isSource(InitializeParameterInstruction init, string msg, Class c) {
9594
}
9695

9796
/**
98-
* Holds if `instr` flows to a sink (which is a use of the value of `instr` as a `this` pointer
99-
* of type `sinkClass`).
97+
* Holds if `instr` flows to a sink (which is a use of the value of `instr` as a `this` pointer).
10098
*/
10199
predicate flowsToSink(Instruction instr, Instruction sink) {
102100
flowsFromSource(instr) and
103101
(
104-
isSink(instr, _, _) and instr = sink
102+
isSink(instr, _) and instr = sink
105103
or
106104
exists(Instruction mid |
107105
successor(instr, mid) and
@@ -180,17 +178,16 @@ predicate successor(Instruction instr, Instruction succ) {
180178
/**
181179
* Holds if:
182180
* - `source` is an initialization of a `this` pointer of type `sourceClass`, and
183-
* - `sink` is a use of the `this` pointer as type `sinkClass`, and
181+
* - `sink` is a use of the `this` pointer, and
184182
* - `call` invokes a pure virtual function using `sink` as the `this` pointer, and
185183
* - `msg` is a string describing whether `source` is from a constructor or destructor.
186184
*/
187185
predicate flows(
188-
Instruction source, string msg, Class sourceClass, Instruction sink, CallInstruction call,
189-
Class sinkClass
186+
Instruction source, string msg, Class sourceClass, Instruction sink, CallInstruction call
190187
) {
191188
isSource(source, msg, sourceClass) and
192189
flowsToSink(source, sink) and
193-
isSink(sink, call, sinkClass)
190+
isSink(sink, call)
194191
}
195192

196193
query predicate edges(Instruction a, Instruction b) { successor(a, b) and flowsToSink(b, _) }
@@ -201,11 +198,12 @@ query predicate nodes(Instruction n, string key, string val) {
201198
val = n.toString()
202199
}
203200

204-
from
205-
Instruction source, Instruction sink, CallInstruction call, string msg, Class sourceClass,
206-
Class sinkClass
201+
from Instruction source, Instruction sink, CallInstruction call, string msg, Class sourceClass
207202
where
208-
flows(source, msg, sourceClass, sink, call, sinkClass) and
209-
sourceClass.getABaseClass+() = sinkClass
203+
flows(source, msg, sourceClass, sink, call) and
204+
// Only raise an alert if there is no override of the pure virtual function in any base class.
205+
not exists(Class c | c = sourceClass.getABaseClass*() |
206+
c.getAMemberFunction().getAnOverriddenFunction() = call.getStaticCallTarget()
207+
)
210208
select call.getUnconvertedResultExpression(), source, sink,
211209
"Call to pure virtual function during " + msg

cpp/ql/test/query-tests/Critical/UnsafeUseOfThis/UnsafeUseOfThis.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,3 @@ nodes
5959
| test.cpp:25:13:25:13 | call to f | test.cpp:21:3:21:3 | InitializeParameter: C | test.cpp:25:7:25:10 | ConvertToNonVirtualBase: (A *)... | Call to pure virtual function during construction |
6060
| test.cpp:35:6:35:6 | call to f | test.cpp:7:3:7:3 | InitializeParameter: B | test.cpp:35:3:35:3 | ConvertToNonVirtualBase: (A *)... | Call to pure virtual function during construction |
6161
| test.cpp:35:6:35:6 | call to f | test.cpp:21:3:21:3 | InitializeParameter: C | test.cpp:35:3:35:3 | ConvertToNonVirtualBase: (A *)... | Call to pure virtual function during construction |
62-
| test.cpp:48:17:48:17 | call to f | test.cpp:47:3:47:3 | InitializeParameter: F | test.cpp:48:6:48:13 | ConvertToNonVirtualBase: (A *)... | Call to pure virtual function during construction |

cpp/ql/test/query-tests/Critical/UnsafeUseOfThis/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ struct E : public A {
4545

4646
struct F : public E {
4747
F() {
48-
((A*)this)->f(); // GOOD: Will call `E::f` [FALSE POSITIVE]
48+
((A*)this)->f(); // GOOD: Will call `E::f`
4949
}
5050
};

0 commit comments

Comments
 (0)