Skip to content

Commit ac38e79

Browse files
committed
CTR55-CPP: predicate renaming, variable clarity
1 parent 4a6661b commit ac38e79

File tree

3 files changed

+44
-23
lines changed

3 files changed

+44
-23
lines changed

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

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,54 +17,66 @@ import codingstandards.cpp.Iterators
1717
import semmle.code.cpp.controlflow.Dominance
1818

1919
/**
20-
* Get a derived one passed the end element for `containerReference`.
20+
* Models a call to an iterator's `operator+`
21+
*/
22+
class AdditionOperatorFunctionCall extends AdditiveOperatorFunctionCall {
23+
AdditionOperatorFunctionCall() { this.getTarget().hasName("operator+") }
24+
}
25+
26+
/**
27+
* There exists a calculation for the reference one passed the end of some container
2128
* An example derivation is:
2229
* `end = begin() + size()`
2330
*/
24-
Expr calculatedEndCheck(AdditiveOperatorFunctionCall calc) {
31+
Expr getDerivedReferenceToOnePassedTheEndElement(Expr containerReference) {
2532
exists(
2633
ContainerAccessWithoutRangeCheck::ContainerSizeCall size,
27-
ContainerAccessWithoutRangeCheck::ContainerBeginCall begin
34+
ContainerAccessWithoutRangeCheck::ContainerBeginCall begin, AdditionOperatorFunctionCall calc
2835
|
29-
calc.getTarget().hasName("operator+") and
30-
DataFlow::localFlow(DataFlow::exprNode(size), DataFlow::exprNode(calc.getAChild*())) and
31-
DataFlow::localFlow(DataFlow::exprNode(begin), DataFlow::exprNode(calc.getAChild*())) and
36+
result = calc
37+
|
38+
DataFlow::localFlow(DataFlow::exprNode(size), DataFlow::exprNode(calc.getAChild+())) and
39+
DataFlow::localFlow(DataFlow::exprNode(begin), DataFlow::exprNode(calc.getAChild+())) and
3240
//make sure its the same container providing its size as giving the begin
3341
globalValueNumber(begin.getQualifier()) = globalValueNumber(size.getQualifier()) and
34-
result = begin.getQualifier()
42+
containerReference = begin.getQualifier()
3543
)
3644
}
3745

38-
Expr validEndCheck(FunctionCall end) {
39-
end instanceof ContainerAccessWithoutRangeCheck::ContainerEndCall and
40-
result = end.getQualifier()
46+
/**
47+
* a wrapper predicate for a couple of types of permitted end bounds checks
48+
*/
49+
Expr getReferenceToOnePassedTheEndElement(Expr containerReference) {
50+
//a container end access - v.end()
51+
result instanceof ContainerAccessWithoutRangeCheck::ContainerEndCall and
52+
containerReference = result.(FunctionCall).getQualifier()
4153
or
42-
result = calculatedEndCheck(end)
54+
result = getDerivedReferenceToOnePassedTheEndElement(containerReference)
4355
}
4456

4557
/**
4658
* some guard exists like: `iterator != end`
4759
* where a relevant`.end()` call flowed into end
4860
*/
49-
predicate validEndBoundCheck(ContainerIteratorAccess it, IteratorSource source) {
61+
predicate isUpperBoundEndCheckedIteratorAccess(IteratorSource source, ContainerIteratorAccess it) {
5062
exists(
51-
FunctionCall end, BasicBlock b, GuardCondition l, ContainerIteratorAccess otherAccess,
52-
Expr qualifierToCheck
63+
Expr referenceToOnePassedTheEndElement, BasicBlock basicBlockOfIteratorAccess, GuardCondition upperBoundCheck,
64+
ContainerIteratorAccess checkedIteratorAccess, Expr containerReferenceFromEndGuard
5365
|
5466
//sufficient end guard
55-
qualifierToCheck = validEndCheck(end) and
67+
referenceToOnePassedTheEndElement = getReferenceToOnePassedTheEndElement(containerReferenceFromEndGuard) and
5668
//guard controls the access
57-
l.controls(b, _) and
58-
b.contains(it) and
69+
upperBoundCheck.controls(basicBlockOfIteratorAccess, _) and
70+
basicBlockOfIteratorAccess.contains(it) and
5971
//guard is comprised of end check and an iterator access
60-
DataFlow::localFlow(DataFlow::exprNode(end), DataFlow::exprNode(l.getChild(_))) and
61-
l.getChild(_) = otherAccess and
72+
DataFlow::localFlow(DataFlow::exprNode(referenceToOnePassedTheEndElement), DataFlow::exprNode(upperBoundCheck.getChild(_))) and
73+
upperBoundCheck.getChild(_) = checkedIteratorAccess and
6274
//make sure its the same iterator being checked in the guard as accessed
63-
otherAccess.getOwningContainer() = it.getOwningContainer() and
75+
checkedIteratorAccess.getOwningContainer() = it.getOwningContainer() and
6476
//if its the end call itself (or its parts), make sure its the same container providing its end as giving the iterator
65-
globalValueNumber(qualifierToCheck) = globalValueNumber(source.getQualifier()) and
77+
globalValueNumber(containerReferenceFromEndGuard) = globalValueNumber(source.getQualifier()) and
6678
// and the guard call we match must be after the assignment call (to avoid valid guards protecting new iterator accesses further down)
67-
source.getASuccessor*() = l
79+
source.getASuccessor*() = upperBoundCheck
6880
)
6981
}
7082

@@ -74,6 +86,6 @@ where
7486
it.isAdditiveOperation() and
7587
not exists(RangeBasedForStmt fs | fs.getUpdate().getAChild*() = it) and
7688
source = it.getANearbyAssigningIteratorCall() and
77-
not validEndBoundCheck(it, source) and
89+
not isUpperBoundEndCheckedIteratorAccess(source, it) and
7890
not sizeCompareBoundsChecked(source, it)
7991
select it, "Increment of iterator may overflow since its bounds are not checked."

cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
| test.cpp:22:18:22:18 | i | Increment of iterator may overflow since its bounds are not checked. |
55
| test.cpp:28:31:28:31 | i | Increment of iterator may overflow since its bounds are not checked. |
66
| test.cpp:41:5:41:8 | end2 | Increment of iterator may overflow since its bounds are not checked. |
7+
| test.cpp:50:42:50:42 | i | Increment of iterator may overflow since its bounds are not checked. |

cpp/cert/test/rules/CTR55-CPP/test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,12 @@ void test_fp_reported_in_374(std::vector<int> &v) {
4242
for (auto i = v.begin(); i != end2; ++i) { // NON_COMPLIANT[FALSE_NEGATIVE]
4343
}
4444
}
45+
}
46+
47+
void test(std::vector<int> &v, std::vector<int> &v2) {
48+
{
49+
auto end = v2.end();
50+
for (auto i = v.begin(); i != end; ++i) { // NON_COMPLIANT - wrong check
51+
}
52+
}
4553
}

0 commit comments

Comments
 (0)