Skip to content

Commit d2d8d6b

Browse files
authored
Merge branch 'main' into michaelrfairhurst/fix-path-problem-nodes-from-outside-workspace
2 parents 1dc9e5e + 1005c67 commit d2d8d6b

File tree

29 files changed

+2891
-103
lines changed

29 files changed

+2891
-103
lines changed

c/common/src/codingstandards/c/Objects.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import cpp
2-
import codingstandards.c.StorageDuration
2+
import codingstandards.cpp.lifetimes.StorageDuration
33
import codingstandards.c.IdentifierLinkage
44
import semmle.code.cpp.valuenumbering.HashCons
55
import codingstandards.cpp.Clvalues
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- `A-23-0-1`, `A-23-0-2`, `CTR-51-CPP`, `CTR-52-CPP`, `CTR-53-CPP`, `CTR-54-CPP`, `CTR-55-CPP`, `STR-52-CPP` - `IteratorImplicitlyConvertedToConstIterator.ql`, `ValidContainerElementAccess.ql`, `UsesValidContainerElementAccess.ql`, `GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql`, `UseValidIteratorRanges.ql`, `DoNotSubtractIteratorsForDifferentContainers.ql`, `DoNotUseAnAdditiveOperatorOnAnIterator.ql`, `UseValidReferencesForElementsOfString.ql`:
2+
- Iterator access methods `rbegin`, `rend`, `crbegin`, `crend` are now recognized on containers.
3+
- Shared library `Iterators.qll` has been refactored by splitting out container type logic into a separate library and add logic to differentiate types of containers, such as associative, indexed, and strings.
4+
- Shared library `Iterators.qll`, used by many queries, has been moved.

cpp/autosar/src/rules/A23-0-1/IteratorImplicitlyConvertedToConstIterator.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import cpp
1515
import codingstandards.cpp.autosar
16-
import codingstandards.cpp.Iterators
16+
import codingstandards.cpp.standardlibrary.Iterators
1717

1818
/*
1919
* Due to inconsistent typedefs across STL containers the way this is parsed

cpp/autosar/test/rules/A23-0-1/IteratorImplicitlyConvertedToConstIterator.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
| test.cpp:10:39:10:48 | call to __iterator | Non-const version of container call immediately converted to a `const_iterator`. |
22
| test.cpp:13:38:13:42 | call to begin | Non-const version of container call immediately converted to a `const_iterator`. |
33
| test.cpp:16:44:16:48 | call to begin | Non-const version of container call immediately converted to a `const_iterator`. |
4-
| test.cpp:19:43:19:47 | call to begin | Non-const version of container call immediately converted to a `const_iterator`. |
5-
| test.cpp:22:50:22:54 | call to begin | Non-const version of container call immediately converted to a `const_iterator`. |
4+
| test.cpp:19:41:19:50 | call to __iterator | Non-const version of container call immediately converted to a `const_iterator`. |
5+
| test.cpp:22:47:22:57 | call to __iterator | Non-const version of container call immediately converted to a `const_iterator`. |
66
| test.cpp:25:8:25:16 | call to __iterator | Non-const version of container call immediately converted to a `const_iterator`. |
77
| test.cpp:27:10:27:14 | call to begin | Non-const version of container call immediately converted to a `const_iterator`. |
88
| test.cpp:29:11:29:15 | call to begin | Non-const version of container call immediately converted to a `const_iterator`. |

cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import cpp
2020
import codingstandards.cpp.cert
21-
import codingstandards.cpp.Iterators
21+
import codingstandards.cpp.standardlibrary.Iterators
2222
import codingstandards.cpp.rules.containeraccesswithoutrangecheck.ContainerAccessWithoutRangeCheck as ContainerAccessWithoutRangeCheck
2323
import semmle.code.cpp.controlflow.Guards
2424
import semmle.code.cpp.dataflow.TaintTracking

cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import cpp
2020
import codingstandards.cpp.cert
21-
import codingstandards.cpp.Iterators
21+
import codingstandards.cpp.standardlibrary.Iterators
2222
import semmle.code.cpp.dataflow.DataFlow
2323

2424
predicate startEndArgumentsDoNotPointToTheSameContainer(

cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import cpp
2020
import codingstandards.cpp.cert
21-
import codingstandards.cpp.Iterators
21+
import codingstandards.cpp.standardlibrary.Iterators
2222

2323
/** Models the subtraction operator */
2424
class SubtractionOperator extends Function {

cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
import cpp
2020
import codingstandards.cpp.cert
21-
import codingstandards.cpp.Iterators
21+
import codingstandards.cpp.standardlibrary.Iterators
2222
import semmle.code.cpp.controlflow.Dominance
2323
import semmle.code.cpp.dataflow.DataFlow
2424

cpp/common/src/codingstandards/cpp/Iterators.qll

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -252,78 +252,6 @@ class AdditiveOperatorFunctionCall extends FunctionCall {
252252
}
253253
}
254254

255-
/**
256-
* Models a collection of STL container classes.
257-
*/
258-
class STLContainer extends Class {
259-
STLContainer() {
260-
getNamespace() instanceof StdNS and
261-
getSimpleName() in [
262-
"vector", "list", "deque", "set", "multiset", "map", "multimap", "stack", "queue",
263-
"priority_queue", "string", "forward_list", "unordered_set", "unordered_multiset",
264-
"unordered_map", "unordered_multimap", "valarray", "string", "basic_string"
265-
]
266-
or
267-
getSimpleName() = "string"
268-
or
269-
getSimpleName() = "basic_string"
270-
}
271-
272-
/**
273-
* Get a call to a named function of this class.
274-
*/
275-
FunctionCall getACallTo(string name) {
276-
exists(Function f |
277-
f = getAMemberFunction() and
278-
f.hasName(name) and
279-
result = f.getACallToThisFunction()
280-
)
281-
}
282-
283-
/**
284-
* Gets all calls to all functions of this class.
285-
*/
286-
FunctionCall getACallToAFunction() {
287-
exists(Function f |
288-
f = getAMemberFunction() and
289-
result = f.getACallToThisFunction()
290-
)
291-
}
292-
293-
FunctionCall getACallToSize() { result = getACallTo("size") }
294-
295-
FunctionCall getANonConstIteratorBeginFunctionCall() { result = getACallTo("begin") }
296-
297-
IteratorSource getAConstIteratorBeginFunctionCall() { result = getACallTo("cbegin") }
298-
299-
IteratorSource getANonConstIteratorEndFunctionCall() { result = getACallTo("end") }
300-
301-
IteratorSource getAConstIteratorEndFunctionCall() { result = getACallTo("cend") }
302-
303-
IteratorSource getANonConstIteratorFunctionCall() {
304-
result = getACallToAFunction() and
305-
result.getTarget().getType() instanceof NonConstIteratorType
306-
}
307-
308-
IteratorSource getAConstIteratorFunctionCall() {
309-
result = getACallToAFunction() and
310-
result.getTarget().getType() instanceof ConstIteratorType
311-
}
312-
313-
IteratorSource getAnIteratorFunctionCall() {
314-
result = getANonConstIteratorFunctionCall() or result = getAConstIteratorFunctionCall()
315-
}
316-
317-
IteratorSource getAnIteratorBeginFunctionCall() {
318-
result = getANonConstIteratorBeginFunctionCall() or
319-
result = getAConstIteratorBeginFunctionCall()
320-
}
321-
322-
IteratorSource getAnIteratorEndFunctionCall() {
323-
result = getANonConstIteratorEndFunctionCall() or result = getAConstIteratorEndFunctionCall()
324-
}
325-
}
326-
327255
/**
328256
* Models the set of iterator sources. Useful for encapsulating dataflow coming
329257
* from a function call producing an iterator.
@@ -338,13 +266,6 @@ class IteratorSource extends FunctionCall {
338266
Variable getOwner() { result = getQualifier().(VariableAccess).getTarget() }
339267
}
340268

341-
/**
342-
* Models a variable that is a `STLContainer`
343-
*/
344-
class STLContainerVariable extends Variable {
345-
STLContainerVariable() { getType() instanceof STLContainer }
346-
}
347-
348269
/**
349270
* Usually an iterator range consists of two sequential iterator arguments, for
350271
* example, the start and end. However, there are exceptions to this rule so
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import cpp
2+
3+
/**
4+
* The configuration signature for the FeasiblePath module.
5+
*
6+
* Typically, the `Node` type should be a `ControlFlowNode`, but it can be overridden to enable
7+
* other kinds of graphs.
8+
*/
9+
signature module FeasiblePathConfigSig {
10+
/** The state type used to carry context through the CFG exploration. */
11+
class State;
12+
13+
/** The node type used to represent CFG nodes. Overridable. */
14+
class Node {
15+
Node getASuccessor();
16+
}
17+
18+
predicate isStart(State state, Node node);
19+
20+
predicate isExcludedPath(State state, Node node);
21+
22+
predicate isEnd(State state, Node node);
23+
}
24+
25+
/**
26+
* A module that finds whether a feasible path exists between two control flow nodes, and
27+
* additionally support configuration that should not be traversed.
28+
*
29+
* Also accepts a state parameter to allow a context to flow through the CFG.
30+
*
31+
* ## Usage
32+
*
33+
* Implement the module `ConfigSig`, with some context type:
34+
*
35+
* ```ql
36+
* module MyConfig implements FeasiblePathConfigSig {
37+
* predicate isStart(SomeContext state, ControlFlowNode node) {
38+
* node = state.someStartCondition()
39+
* }
40+
*
41+
* predicate isExcludedPath(SomeContext state, ControlFlowNode node) {
42+
* node = state.someExcludedPathCondition()
43+
* }
44+
*
45+
* predicate isEnd(SomeContext state, ControlFlowNode node) {
46+
* node = state.someEndCondition()
47+
* }
48+
* }
49+
*
50+
* import FeasiblePath<MyConfig> as MyFeasiblePath
51+
* ```
52+
*
53+
* ## Rationale
54+
*
55+
* Why does this module exist? While it may be tempting to write:
56+
*
57+
* ```ql
58+
* exists(ControlFlowNode start, ControlFlowNode end) {
59+
* isStart(start) and
60+
* isEnd(end) and
61+
* end = start.getASuccessor*() and
62+
* not exists(ControlFlowNode mid |
63+
* mid = start.getASuccessor+() and
64+
* end = mid.getASuccessor*() and
65+
* isExcludedPath(mid)
66+
* )
67+
* }
68+
* ```
69+
*
70+
* This has an unintuitive trap case in looping CFGs:
71+
*
72+
* ```c
73+
* while (cond) {
74+
* start();
75+
* end();
76+
* excluded();
77+
* }
78+
* ```
79+
*
80+
* In the above code, `excluded()` is a successor of `start()`, and `end()` is also a successor of
81+
* `excluded()` (via the loop back edge). However, there is no path from `start()` to `end()` that
82+
* does not pass through `excluded()`.
83+
*
84+
* This module will correctly handle this case. Forward exploration through the graph will stop
85+
* at the `excluded()` nodes, such that only paths from `start()` to `end()` that do not pass
86+
* through `excluded()` nodes will be found.
87+
*/
88+
module FeasiblePath<FeasiblePathConfigSig Config> {
89+
predicate isSuccessor(Config::State state, Config::Node start, Config::Node end) {
90+
isMid(state, start, end) and
91+
Config::isEnd(state, end)
92+
}
93+
94+
private predicate isMid(Config::State state, Config::Node start, Config::Node mid) {
95+
// TODO: Explore if forward-reverse pruning would be beneficial for performance here.
96+
Config::isStart(state, start) and
97+
(
98+
mid = start
99+
or
100+
exists(Config::Node prevMid |
101+
isMid(state, start, prevMid) and
102+
mid = prevMid.getASuccessor() and
103+
not Config::isExcludedPath(state, mid) and
104+
not Config::isEnd(state, prevMid)
105+
)
106+
)
107+
}
108+
}

0 commit comments

Comments
 (0)