Skip to content

Commit 0de9092

Browse files
authored
Merge branch 'main' into michaelrfairhurst/deadcode-5-rule-0-1-1
2 parents df9d666 + d20c643 commit 0de9092

File tree

49 files changed

+2769
-126
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2769
-126
lines changed

c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import cpp
1717
import codingstandards.c.misra
1818
import codingstandards.c.Objects
19+
import codingstandards.cpp.Expr
1920

2021
/**
2122
* Holds if the value of an expression is used or stored.
@@ -37,32 +38,14 @@ predicate isUsedOrStored(Expr e) {
3738
e = any(ClassAggregateLiteral l).getAFieldExpr(_)
3839
}
3940

40-
/**
41-
* Find expressions that defer their value directly to an inner expression
42-
* value.
43-
*
44-
* When an array is on the rhs of a comma expr, or in the then/else branch of a
45-
* ternary expr, and the result us used as a pointer, then the ArrayToPointer
46-
* conversion is marked inside comma expr/ternary expr, on the operands. These
47-
* conversions are only non-compliant if they flow into an operation or store.
48-
*
49-
* Full flow analysis with localFlowStep should not be necessary, and may cast a
50-
* wider net than needed for some queries, potentially resulting in false
51-
* positives.
52-
*/
53-
Expr temporaryObjectFlowStep(Expr e) {
54-
e = result.(CommaExpr).getRightOperand()
55-
or
56-
e = result.(ConditionalExpr).getThen()
57-
or
58-
e = result.(ConditionalExpr).getElse()
59-
}
60-
6141
from FieldAccess fa, TemporaryObjectIdentity temporary, ArrayToPointerConversion conversion
6242
where
6343
not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and
6444
fa = temporary.getASubobjectAccess() and
6545
conversion.getExpr() = fa and
66-
isUsedOrStored(temporaryObjectFlowStep*(conversion.getExpr()))
46+
exists(Expr useOrStore |
47+
temporaryObjectFlowStep*(conversion.getExpr(), useOrStore) and
48+
isUsedOrStored(useOrStore)
49+
)
6750
select conversion, "Array to pointer conversion of array $@ from temporary object $@.",
6851
fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- All queries related to integer suffixes:
2+
- No visible changes expected: the regex for parsing integer suffixes, and how they are treated after lexing, has been refactored.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- `RULE-18-9` - `ArraytoPointerConversionOfTemporaryObject.ql`
2+
- The behavior for finding flow steps of temporary objects (for example, from ternary branches to the ternary expr result) has been extracted for reuse in other rules, no visible changes expected.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `A3-3-2` - `StaticOrThreadLocalObjectsNonConstantInit`:
2+
- The checks for non-constant initialization have been moved to be usable in other queries, such as MISRA C++23 Rule 6.7.2.
3+
- No visible changes in query results expected.

cpp/autosar/src/rules/A3-3-2/StaticOrThreadLocalObjectsNonConstantInit.ql

Lines changed: 1 addition & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -15,100 +15,7 @@
1515

1616
import cpp
1717
import codingstandards.cpp.autosar
18-
19-
/**
20-
* Holds if `e` is a full expression or `AggregateLiteral` in the initializer of a
21-
* `StaticStorageDurationVariable`.
22-
*
23-
* Although `AggregateLiteral`s are expressions according to our model, they are not considered
24-
* expressions from the perspective of the standard. Therefore, we should consider components of
25-
* aggregate literals within static initializers to also be full expressions.
26-
*/
27-
private predicate isFullExprOrAggregateInStaticInitializer(Expr e) {
28-
exists(StaticStorageDurationVariable var | e = var.getInitializer().getExpr())
29-
or
30-
isFullExprOrAggregateInStaticInitializer(e.getParent().(AggregateLiteral))
31-
}
32-
33-
/**
34-
* Holds if `e` is a non-constant full expression in a static initializer, for the given `reason`
35-
* and `reasonElement`.
36-
*/
37-
private predicate nonConstantFullExprInStaticInitializer(
38-
Expr e, Element reasonElement, string reason
39-
) {
40-
isFullExprOrAggregateInStaticInitializer(e) and
41-
if e instanceof AggregateLiteral
42-
then
43-
// If this is an aggregate literal, we apply this recursively
44-
nonConstantFullExprInStaticInitializer(e.getAChild(), reasonElement, reason)
45-
else (
46-
// Otherwise we check this component to determine if it is constant
47-
not (
48-
e.getFullyConverted().isConstant() or
49-
e.(Call).getTarget().isConstexpr() or
50-
e.(VariableAccess).getTarget().isConstexpr()
51-
) and
52-
reason = "uses a non-constant element in the initialization" and
53-
reasonElement = e
54-
)
55-
}
56-
57-
/**
58-
* A `ConstructorCall` that does not represent a constant initializer for an object according to
59-
* `[basic.start.init]`.
60-
*
61-
* In addition to identifying `ConstructorCall`s which are not constant initializers, this also
62-
* provides an explanatory "reason" for why this constructor is not considered to be a constant
63-
* initializer.
64-
*/
65-
predicate isNotConstantInitializer(ConstructorCall cc, Element reasonElement, string reason) {
66-
// Must call a constexpr constructor
67-
not cc.getTarget().isConstexpr() and
68-
reason =
69-
"calls the " + cc.getTarget().getName() + "(..) constructor which is not marked as constexpr" and
70-
reasonElement = cc
71-
or
72-
// And all arguments must either be constant, or themselves call constexpr constructors
73-
cc.getTarget().isConstexpr() and
74-
exists(Expr arg | arg = cc.getAnArgument() |
75-
isNotConstantInitializer(arg, reasonElement, reason)
76-
or
77-
not arg instanceof ConstructorCall and
78-
not arg.getFullyConverted().isConstant() and
79-
not arg.(Call).getTarget().isConstexpr() and
80-
not arg.(VariableAccess).getTarget().isConstexpr() and
81-
reason = "includes a non constant " + arg.getType() + " argument to a constexpr constructor" and
82-
reasonElement = arg
83-
)
84-
}
85-
86-
/**
87-
* Identifies if a `StaticStorageDurationVariable` is not constant initialized according to
88-
* `[basic.start.init]`.
89-
*/
90-
predicate isNotConstantInitialized(
91-
StaticStorageDurationVariable v, string reason, Element reasonElement
92-
) {
93-
if v.getInitializer().getExpr() instanceof ConstructorCall
94-
then
95-
// (2.2) if initialized by a constructor call, then that constructor call must be a constant
96-
// initializer for the variable to be constant initialized
97-
isNotConstantInitializer(v.getInitializer().getExpr(), reasonElement, reason)
98-
else
99-
// (2.3) If it is not initialized by a constructor call, then it must be the case that every full
100-
// expr in the initializer is a constant expression or that the object was "value initialized"
101-
// but without a constructor call. For value initialization, there are two non-constructor call
102-
// cases to consider:
103-
//
104-
// 1. The object was zero initialized - in which case, the extractor does not include a
105-
// constructor call - instead, it has a blank aggregate literal, or no initializer.
106-
// 2. The object is an array, which will be initialized by an aggregate literal.
107-
//
108-
// In both cases it is sufficient for us to find a non-constant full expression in the static
109-
// initializer
110-
nonConstantFullExprInStaticInitializer(v.getInitializer().getExpr(), reasonElement, reason)
111-
}
18+
import codingstandards.cpp.orderofevaluation.Initialization
11219

11320
from StaticStorageDurationVariable staticOrThreadLocalVar, string reason, Element reasonElement
11421
where
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
| test.cpp:57:6:57:14 | operator= | User defined copy or user defined move does not handle self-assignment correctly. |
2-
| test.cpp:66:6:66:14 | operator= | User defined copy or user defined move does not handle self-assignment correctly. |
1+
| test.cpp:56:6:56:14 | operator= | User defined copy or user defined move does not handle self-assignment correctly. |
2+
| test.cpp:65:6:65:14 | operator= | User defined copy or user defined move does not handle self-assignment correctly. |

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include <functional>
22
#include <string>
3-
#include <utility>
43

54
class A {
65
public:

cpp/common/src/codingstandards/cpp/Cpp14Literal.qll

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,33 @@ module Cpp14Literal {
1212
/** Convenience for implementing class `UnrecognizedNumericLiteral` */
1313
abstract private class RecognizedNumericLiteral extends StandardLibrary::Literal { }
1414

15+
/** An integer literal suffix (e.g. 'u', 'll', etc, or even an empty string). */
16+
class IntegerLiteralSuffix extends string {
17+
string uPart;
18+
string lPart;
19+
20+
IntegerLiteralSuffix() {
21+
uPart = ["", "u", "U"] and
22+
lPart = ["", "l", "L"] + ["", "l", "L"] and
23+
this = uPart + lPart
24+
}
25+
26+
predicate isSigned() { uPart = "" }
27+
28+
predicate isUnsigned() { uPart != "" }
29+
30+
int getLCount() { result = lPart.length() }
31+
}
32+
1533
/** An integer literal. */
1634
abstract class IntegerLiteral extends NumericLiteral {
1735
predicate isSigned() { not isUnsigned() }
1836

19-
predicate isUnsigned() { getValueText().regexpMatch(".*[uU][lL]?$") }
37+
predicate isUnsigned() { getSuffix().isUnsigned() }
38+
39+
IntegerLiteralSuffix getSuffix() {
40+
result = getValueText().regexpCapture("[^uUlL]*([uU]?[lL]*)\\s*$", 1)
41+
}
2042
}
2143

2244
/**

cpp/common/src/codingstandards/cpp/Expr.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,28 @@ predicate isCompileTimeEvaluatedExpression(Expr expression) {
243243
)
244244
}
245245

246+
/**
247+
* Find expressions that defer their value directly to an inner expression
248+
* value -- how temporary object can flow without being copied or having their
249+
* address taken.
250+
*
251+
* Full flow analysis with localFlowStep is often not necessary for certain
252+
* rules related to temporary objects, and may cast a wider net than needed for
253+
* those queries.
254+
*
255+
* When an array is on the rhs of a comma expr, or in the then/else branch of a
256+
* ternary expr, and the result us used as a pointer, then the ArrayToPointer
257+
* conversion is marked inside comma expr/ternary expr, on the operands. These
258+
* conversions are only non-compliant if they flow into an operation or store.
259+
*/
260+
predicate temporaryObjectFlowStep(Expr source, Expr sink) {
261+
source = sink.(CommaExpr).getRightOperand()
262+
or
263+
source = sink.(ConditionalExpr).getThen()
264+
or
265+
source = sink.(ConditionalExpr).getElse()
266+
}
267+
246268
predicate isDirectCompileTimeEvaluatedExpression(Expr expression) {
247269
expression instanceof Literal
248270
or

0 commit comments

Comments
 (0)