Skip to content

Commit 3295d5c

Browse files
committed
C++: Add more QLDoc.
1 parent fc9919a commit 3295d5c

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed

cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ predicate isSourceImpl(DataFlow::Node source, Class state) {
163163
)
164164
}
165165

166+
/**
167+
* The `RelevantStateConfig` configuration is used to find the set of
168+
* states for the `BadConfig` and `GoodConfig`. The flow computed by
169+
* `RelevantStateConfig` is used to implement the `relevantState` predicate
170+
* which is used to avoid a cartesian product in `isSinkImpl`.
171+
*/
166172
module RelevantStateConfig implements DataFlow::ConfigSig {
167173
predicate isSource(DataFlow::Node source) { isSourceImpl(source, _) }
168174

@@ -204,9 +210,16 @@ predicate isSinkImpl(DataFlow::Node sink, Class state, Type convertedType, boole
204210
)
205211
}
206212

213+
/**
214+
* The `BadConfig` configuration tracks flow from an allocation to an
215+
* incompatible cast.
216+
*
217+
* We use `FlowState` to track the type of the source, and compare the
218+
* flow state to the target of the cast in the `isSink` definition.
219+
*/
207220
module BadConfig implements DataFlow::StateConfigSig {
208221
class FlowState extends Class {
209-
FlowState() { isSourceImpl(_, this) }
222+
FlowState() { relevantState(_, this) }
210223
}
211224

212225
predicate isSource(DataFlow::Node source, FlowState state) { isSourceImpl(source, state) }
@@ -220,6 +233,45 @@ module BadConfig implements DataFlow::StateConfigSig {
220233

221234
module BadFlow = DataFlow::GlobalWithState<BadConfig>;
222235

236+
/**
237+
* The `GoodConfig` configuration tracks flow from an allocation to a
238+
* compatible cast.
239+
*
240+
* We use `GoodConfig` to reduce the number of FPs from infeasible paths.
241+
* For example, consider the following example:
242+
* ```cpp
243+
* struct Animal { virtual ~Animal(); };
244+
*
245+
* struct Cat : public Animal {
246+
* Cat();
247+
* ~Cat();
248+
* };
249+
*
250+
* struct Dog : public Animal {
251+
* Dog();
252+
* ~Dog();
253+
* };
254+
*
255+
* void test9(bool b) {
256+
* Animal* a;
257+
* if(b) {
258+
* a = new Cat;
259+
* } else {
260+
* a = new Dog;
261+
* }
262+
* if(b) {
263+
* Cat* d = static_cast<Cat*>(a);
264+
* }
265+
* }
266+
* ```
267+
* Here, `BadConfig` finds a flow from `a = new Dog` to `static_cast<Cat*>(a)`.
268+
* However, that path is never realized in an actual execution path. So in
269+
* order to remove this result we exclude results where there exists an
270+
* allocation of a type that's compatible with `static_cast<Cat*>(a)`.
271+
*
272+
* We use `FlowState` to track the type of the source, and compare the
273+
* flow state to the target of the cast in the `isSink` definition.
274+
*/
223275
module GoodConfig implements DataFlow::StateConfigSig {
224276
class FlowState = BadConfig::FlowState;
225277

0 commit comments

Comments
 (0)