Skip to content

Commit 797449c

Browse files
authored
Merge branch 'main' into lcartey/remove-old-is-excluded
2 parents cfe740d + 6c8ba57 commit 797449c

File tree

13 files changed

+189
-72
lines changed

13 files changed

+189
-72
lines changed

c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,35 @@
1414

1515
import cpp
1616
import codingstandards.c.misra
17+
import codingstandards.cpp.PreprocessorDirective
1718

1819
/* A controlling expression is evaluated if it is not excluded (guarded by another controlling expression that is not taken). This translates to it either being taken or not taken. */
1920
predicate isEvaluated(PreprocessorBranch b) { b.wasTaken() or b.wasNotTaken() }
2021

21-
class IfOrElifPreprocessorBranch extends PreprocessorBranch {
22-
IfOrElifPreprocessorBranch() {
23-
this instanceof PreprocessorIf or this instanceof PreprocessorElif
24-
}
25-
}
26-
2722
/**
2823
* Looks like it contains a single macro, which may be undefined
2924
*/
30-
class SimpleMacroPreprocessorBranch extends IfOrElifPreprocessorBranch {
25+
class SimpleMacroPreprocessorBranch extends PreprocessorIfOrElif {
3126
SimpleMacroPreprocessorBranch() { this.getHead().regexpMatch("[a-zA-Z_][a-zA-Z0-9_]+") }
3227
}
3328

34-
class SimpleNumericPreprocessorBranch extends IfOrElifPreprocessorBranch {
29+
class SimpleNumericPreprocessorBranch extends PreprocessorIfOrElif {
3530
SimpleNumericPreprocessorBranch() { this.getHead().regexpMatch("[0-9]+") }
3631
}
3732

3833
class ZeroOrOnePreprocessorBranch extends SimpleNumericPreprocessorBranch {
3934
ZeroOrOnePreprocessorBranch() { this.getHead().regexpMatch("[0|1]") }
4035
}
4136

42-
predicate containsOnlySafeOperators(IfOrElifPreprocessorBranch b) {
37+
predicate containsOnlySafeOperators(PreprocessorIfOrElif b) {
4338
containsOnlyDefinedOperator(b)
4439
or
4540
//logic: comparison operators eval last, so they make it safe?
4641
b.getHead().regexpMatch(".*[\\&\\&|\\|\\||>|<|==].*")
4742
}
4843

4944
//all defined operators is definitely safe
50-
predicate containsOnlyDefinedOperator(IfOrElifPreprocessorBranch b) {
45+
predicate containsOnlyDefinedOperator(PreprocessorIfOrElif b) {
5146
forall(string portion |
5247
portion =
5348
b.getHead()
@@ -65,7 +60,7 @@ class BinaryValuedMacro extends Macro {
6560
BinaryValuedMacro() { this.getBody().regexpMatch("\\(?(0|1)\\)?") }
6661
}
6762

68-
from IfOrElifPreprocessorBranch b, string msg
63+
from PreprocessorIfOrElif b, string msg
6964
where
7065
not isExcluded(b, Preprocessor3Package::controllingExpressionIfDirectiveQuery()) and
7166
isEvaluated(b) and
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
- `M16-1-1`:
1+
- `M16-1-1` - `DefinedPreProcessorOperatorGeneratedFromExpansionFound.ql`:
22
- Optimize query to improve performance
33
- Improve detection of macros whose body contains the `defined` operator after the start of the macro (e.g. `#define X Y || defined(Z)`).
44
- Enable exclusions to be applied for this rule.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
- `A8-4-8` - `OutParametersUsed.ql`
2+
- Fixes #370 - Non-member user-defined assignment operator and stream insertion/extraction parameters that are required to be out parameters are excluded.
3+
- Broadens the definition of out parameter by considering assignment and crement operators as modifications to an out parameter candidate.
4+
- `FIO51-CPP` - `CloseFilesWhenTheyAreNoLongerNeeded.ql`:
5+
- Broadened definition of `IStream` and `OStream` types may result in reduced false negatives.
6+
- `A5-1-1` - `LiteralValueUsedOutsideTypeInit.ql`:
7+
- Broadened definition of `IStream` types may result in reduced false positives because more file stream function calls may be detected as logging operations that will be excluded from the results.

cpp/autosar/src/rules/A8-4-8/OutputParametersUsed.ql

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,60 @@ import codingstandards.cpp.ConstHelpers
2323
import codingstandards.cpp.Operator
2424

2525
/**
26-
* Non-const T& and T* `Parameter`s to `Function`s
26+
* Holds if p is passed as a non-const reference or pointer and is modified.
27+
* This holds for in-out or out-only parameters.
2728
*/
28-
class NonConstReferenceOrPointerParameterCandidate extends FunctionParameter {
29-
NonConstReferenceOrPointerParameterCandidate() {
30-
this instanceof NonConstReferenceParameter
31-
or
32-
this instanceof NonConstPointerParameter
33-
}
29+
predicate isOutParameter(NonConstPointerorReferenceParameter p) {
30+
any(VariableEffect ve).getTarget() = p
31+
}
32+
33+
/**
34+
* Holds if parameter `p` is a parameter to a user defined assignment operator that
35+
* is defined outside of a class body.
36+
* These require an in-out parameter as the first argument.
37+
*/
38+
predicate isNonMemberUserAssignmentParameter(NonConstPointerorReferenceParameter p) {
39+
p.getFunction() instanceof UserAssignmentOperator and
40+
not p.isMember()
41+
}
42+
43+
/**
44+
* Holds if parameter `p` is a parameter to a stream insertion operator that
45+
* is defined outside of a class body.
46+
* These require an in-out parameter as the first argument.
47+
*
48+
* e.g., `std::ostream& operator<<(std::ostream& os, const T& obj)`
49+
*/
50+
predicate isStreamInsertionStreamParameter(NonConstPointerorReferenceParameter p) {
51+
exists(StreamInsertionOperator op | not op.isMember() | op.getParameter(0) = p)
3452
}
3553

36-
pragma[inline]
37-
predicate isFirstAccess(VariableAccess va) {
38-
not exists(VariableAccess otherVa |
39-
otherVa.getTarget() = va.getTarget() or
40-
otherVa.getQualifier().(VariableAccess).getTarget() = va.getTarget()
41-
|
42-
otherVa.getASuccessor() = va
54+
/**
55+
* Holds if parameter `p` is a parameter to a stream insertion operator that
56+
* is defined outside of a class body.
57+
* These require an in-out parameter as the first argument and an out parameter for the second.
58+
*
59+
* e.g., `std::istream& operator>>(std::istream& is, T& obj)`
60+
*/
61+
predicate isStreamExtractionParameter(NonConstPointerorReferenceParameter p) {
62+
exists(StreamExtractionOperator op | not op.isMember() |
63+
op.getParameter(0) = p
64+
or
65+
op.getParameter(1) = p
4366
)
4467
}
4568

46-
from NonConstReferenceOrPointerParameterCandidate p, VariableEffect ve
69+
predicate isException(NonConstPointerorReferenceParameter p) {
70+
isNonMemberUserAssignmentParameter(p) and p.getIndex() = 0
71+
or
72+
isStreamInsertionStreamParameter(p)
73+
or
74+
isStreamExtractionParameter(p)
75+
}
76+
77+
from NonConstPointerorReferenceParameter p
4778
where
4879
not isExcluded(p, ConstPackage::outputParametersUsedQuery()) and
49-
ve.getTarget() = p and
50-
isFirstAccess(ve.getAnAccess()) and
51-
not ve instanceof AnyAssignOperation and
52-
not ve instanceof CrementOperation
53-
select p, "Out parameter " + p.getName() + " that is modified before being read."
80+
isOutParameter(p) and
81+
not isException(p)
82+
select p, "Out parameter '" + p.getName() + "' used."

cpp/autosar/src/rules/M16-1-1/DefinedPreProcessorOperatorGeneratedFromExpansionFound.ql

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,9 @@
1414

1515
import cpp
1616
import codingstandards.cpp.autosar
17+
import codingstandards.cpp.PreprocessorDirective
1718
import DefinedMacro
1819

19-
/**
20-
* An `if` or `elif` preprocessor branch.
21-
*/
22-
class PreprocessorIfOrElif extends PreprocessorBranch {
23-
PreprocessorIfOrElif() {
24-
this instanceof PreprocessorIf or
25-
this instanceof PreprocessorElif
26-
}
27-
}
28-
2920
from PreprocessorIfOrElif e, MacroUsesDefined m
3021
where
3122
not isExcluded(e, MacrosPackage::definedPreProcessorOperatorInOneOfTheTwoStandardFormsQuery()) and

cpp/autosar/src/rules/M16-1-1/DefinedPreProcessorOperatorInOneOfTheTwoStandardForms.ql

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import cpp
1717
import codingstandards.cpp.autosar
18+
import codingstandards.cpp.PreprocessorDirective
1819

1920
//get what comes after each 'defined' used with or without parenth
2021
string matchesDefinedOperator(PreprocessorBranch e) {
@@ -34,12 +35,8 @@ string matchesDefinedOperator(PreprocessorBranch e) {
3435
)
3536
}
3637

37-
from PreprocessorBranch e, string arg
38+
from PreprocessorIfOrElif e, string arg
3839
where
39-
(
40-
e instanceof PreprocessorIf or
41-
e instanceof PreprocessorElif
42-
) and
4340
arg = matchesDefinedOperator(e) and
4441
not arg.regexpMatch("^\\w*$") and
4542
not isExcluded(e, MacrosPackage::definedPreProcessorOperatorInOneOfTheTwoStandardFormsQuery())
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
| test.cpp:5:22:5:24 | str | Out parameter str that is modified before being read. |
2-
| test.cpp:16:14:16:14 | i | Out parameter i that is modified before being read. |
3-
| test.cpp:21:14:21:14 | i | Out parameter i that is modified before being read. |
4-
| test.cpp:29:12:29:12 | a | Out parameter a that is modified before being read. |
5-
| test.cpp:33:12:33:12 | a | Out parameter a that is modified before being read. |
1+
| test.cpp:5:22:5:24 | str | Out parameter 'str' used. |
2+
| test.cpp:8:22:8:24 | str | Out parameter 'str' used. |
3+
| test.cpp:16:14:16:14 | i | Out parameter 'i' used. |
4+
| test.cpp:21:14:21:14 | i | Out parameter 'i' used. |
5+
| test.cpp:29:12:29:12 | a | Out parameter 'a' used. |
6+
| test.cpp:33:12:33:12 | a | Out parameter 'a' used. |

cpp/autosar/test/rules/A8-4-8/test.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ void f(int &i) { // COMPLIANT
55
void f1(std::string &str) { // NON_COMPLIANT
66
str = "replacement";
77
}
8-
void f2(std::string &str) { // COMPLIANT
8+
void f2(std::string &str) { // NON_COMPLIANT
99
str += "suffix";
1010
}
1111

@@ -37,3 +37,41 @@ void f7(A &a) { // NON_COMPLIANT
3737
void f8(int i) { // COMPLIANT
3838
i += 1;
3939
}
40+
41+
constexpr A &operator|=(
42+
A &lhs,
43+
const A &rhs) noexcept { // COMPLIANT - non-member user defined assignment
44+
// operators are considered an exception.
45+
return lhs;
46+
}
47+
48+
enum class byte : unsigned char {};
49+
constexpr byte &
50+
operator|(const byte &lhs,
51+
const byte &rhs) noexcept { // COMPLIANT - parameters are const
52+
// qualified references
53+
return lhs | rhs;
54+
}
55+
constexpr byte &operator|=(
56+
byte &lhs,
57+
const byte rhs) noexcept { // COMPLIANT - non-member user defined assignment
58+
// operators are considered an exception.
59+
lhs = (lhs | rhs);
60+
return lhs;
61+
}
62+
63+
#include <iostream>
64+
std::ostream &operator<<(std::ostream &os,
65+
const byte &obj) { // COMPLIANT - insertion operators
66+
// are considered an exception.
67+
std::ostream other;
68+
os = other; // simulate modification
69+
return os;
70+
}
71+
72+
std::istream &operator>>(std::istream &is,
73+
byte &obj) { // COMPLIANT - extraction operators are
74+
// considered an exception.
75+
obj = static_cast<byte>('a'); // simulate modification
76+
return is;
77+
}

cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ predicate filebufAccess(ControlFlowNode node, FileStreamSource fss) {
3838
//insertion or extraction operator calls
3939
node.(InsertionOperatorCall).getFStream() = fss.getAUse() or
4040
node.(ExtractionOperatorCall).getFStream() = fss.getAUse() or
41-
//methods inherited from istream or ostream
42-
node.(IOStreamFunctionCall).getFStream() = fss.getAUse()
41+
// Methods inherited from istream or ostream that access the file stream.
42+
// Exclude is_open as it is not a filebuf access
43+
any(IOStreamFunctionCall call | node = call and not call.getTarget().hasName("is_open"))
44+
.getFStream() = fss.getAUse()
4345
}
4446

4547
/**

cpp/common/src/codingstandards/cpp/Operator.qll

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import cpp
22
import Expr
3+
private import semmle.code.cpp.security.FileWrite
4+
private import codingstandards.cpp.standardlibrary.FileStreams
35

46
/**
57
* any assignment operator that also reads from the access
@@ -119,14 +121,16 @@ class UserAssignmentOperator extends AssignmentOperator {
119121
}
120122

121123
/** An assignment operator of any sort */
122-
class AssignmentOperator extends MemberFunction {
124+
class AssignmentOperator extends Function {
123125
AssignmentOperator() {
124126
// operator op, where op is =, +=, -=, *=, /=, %=, ^=, &=, |=, >>=, <<=
125127
exists(string op |
126128
"operator" + op = this.getName() and
127129
op in ["=", "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", ">>=", "<<="]
128130
)
129131
}
132+
133+
predicate isLValueRefQualified() { this.(MemberFunction).isLValueRefQualified() }
130134
}
131135

132136
class UserComparisonOperator extends Function {
@@ -265,6 +269,38 @@ class UserOverloadedOperator extends Function {
265269
}
266270
}
267271

272+
/** An implementation of a stream insertion operator. */
273+
class StreamInsertionOperator extends Function {
274+
StreamInsertionOperator() {
275+
this.hasName("operator<<") and
276+
(
277+
if this.isMember()
278+
then this.getNumberOfParameters() = 1
279+
else (
280+
this.getNumberOfParameters() = 2 and
281+
this.getParameter(0).getType() instanceof BasicOStreamClass
282+
)
283+
) and
284+
this.getType() instanceof BasicOStreamClass
285+
}
286+
}
287+
288+
/** An implementation of a stream extraction operator. */
289+
class StreamExtractionOperator extends Function {
290+
StreamExtractionOperator() {
291+
this.hasName("operator>>") and
292+
(
293+
if this.isMember()
294+
then this.getNumberOfParameters() = 1
295+
else (
296+
this.getNumberOfParameters() = 2 and
297+
this.getParameter(0).getType() instanceof IStream
298+
)
299+
) and
300+
this.getType() instanceof IStream
301+
}
302+
}
303+
268304
/** A user defined operator address of operator (`&`). */
269305
class UnaryAddressOfOperator extends Operator {
270306
UnaryAddressOfOperator() {

cpp/common/src/codingstandards/cpp/PreprocessorDirective.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,13 @@ PreprocessorDirective isLocatedInAMacroInvocation(MacroInvocation m) {
3030
result = p
3131
)
3232
}
33+
34+
/**
35+
* An `if` or `elif` preprocessor branch.
36+
*/
37+
class PreprocessorIfOrElif extends PreprocessorBranch {
38+
PreprocessorIfOrElif() {
39+
this instanceof PreprocessorIf or
40+
this instanceof PreprocessorElif
41+
}
42+
}

cpp/common/src/codingstandards/cpp/rules/undefinedmacroidentifiers/UndefinedMacroIdentifiers.qll

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import cpp
22
import codingstandards.cpp.Exclusions
3+
import codingstandards.cpp.PreprocessorDirective
34

45
abstract class UndefinedMacroIdentifiersSharedQuery extends Query { }
56

@@ -76,17 +77,10 @@ string getAnIfDefdMacroIdentifier(PreprocessorBranch pb) {
7677
)
7778
}
7879

79-
class IfAndElifs extends PreprocessorBranch {
80-
IfAndElifs() {
81-
this instanceof PreprocessorIf or
82-
this instanceof PreprocessorElif
83-
}
84-
}
85-
86-
class BadIfAndElifs extends IfAndElifs {
80+
class UndefinedIdIfOrElif extends PreprocessorIfOrElif {
8781
string undefinedMacroIdentifier;
8882

89-
BadIfAndElifs() {
83+
UndefinedIdIfOrElif() {
9084
exists(string defRM |
9185
defRM =
9286
this.getHead()
@@ -113,7 +107,7 @@ class BadIfAndElifs extends IfAndElifs {
113107
string getAnUndefinedMacroIdentifier() { result = undefinedMacroIdentifier }
114108
}
115109

116-
query predicate problems(BadIfAndElifs b, string message) {
110+
query predicate problems(UndefinedIdIfOrElif b, string message) {
117111
not isExcluded(b, getQuery()) and
118112
message =
119113
"#if/#elif that uses a macro identifier " + b.getAnUndefinedMacroIdentifier() +

0 commit comments

Comments
 (0)