Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2b1c06b
M5-2-2: Make into shared query
lcartey Aug 15, 2025
7e9fe0b
Add Conversions2 package
lcartey Aug 15, 2025
c81f246
Rule 8.2.1: Implement as a shared query
lcartey Aug 15, 2025
75837e2
PointerToAVirtualBaseClass: Handle reference types and type defs
lcartey Aug 15, 2025
1792e88
A5-2-2: Refactor query to extract shared components
lcartey Aug 15, 2025
9b9a68c
Fix AlertReporting for nested macros
lcartey Aug 17, 2025
9aa5e21
RULE-8-2-2 - NoCStyleOrFunctionalCasts
lcartey Aug 17, 2025
9118b81
RULE-8-2-6 - IntToPointerCastProhibited
lcartey Aug 17, 2025
13e184e
Add intptr_t and uintptr_t stubs
lcartey Aug 17, 2025
72d24a1
RULE-8-2-7 - NoPointerToIntegralCast
lcartey Aug 17, 2025
8804fec
RULE-8-2-8 - PointerToIntegralCast
lcartey Aug 17, 2025
29f1bbd
RULE-9-2-1 - NoStandaloneTypeCastExpression
lcartey Aug 18, 2025
d645670
Update mutex to include scoped_lock stubs
lcartey Aug 18, 2025
5efc380
Rule 8.2.6: Query improvements
lcartey Aug 18, 2025
b0d18ce
Rule 8.2.7: Simplify CodeQL
lcartey Aug 18, 2025
51ef7bd
Rule 8.2.8: Improve CodeQL query
lcartey Aug 18, 2025
550f38c
Rule 9.2.1: Add proviso for if statement initializers
lcartey Aug 18, 2025
3ab9104
Add change note for AlertReporting behaviour
lcartey Aug 18, 2025
1d0736e
PointerToAVirtualBaseClass: Support casts from parents of virtual
lcartey Aug 21, 2025
6bce7f8
Rule 8.2.8: Handle results in templates per rule
lcartey Aug 21, 2025
6e9ee92
Conversions2: Add rule tags
lcartey Aug 26, 2025
3477dcf
Query formatting
lcartey Aug 26, 2025
9969544
Merge branch 'main' into lcartey/cpp-conversions2
lcartey Aug 27, 2025
0124f5e
Fix performance issue from join on start column.
MichaelRFairhurst Aug 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions change_notes/2025-08-15-m5-2-2-virtual-base.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- `M5-2-2` - `PointerToAVirtualBaseClassCastToAPointer.ql`:
- Report casts where the from or to types are typedefs to virtual base classes or derived classes.
- Report casts to a reference type which is a derived type.
- Report casts where the base class is the parent of a virtual base class.
- The alert message has been updated to refer to the virtual base class derivation.
3 changes: 3 additions & 0 deletions change_notes/2025-08-18-fix-alert-reporting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- `RULE-1-2`, `RULE-23-3`, `RULE-23-5`, `RULE-23-6`:
- Results that occur in nested macro invocations are now reported in the macro that defines the contravening code, rather than the macro which is first expanded.
- Results the occur in arguments to macro invocations are now reported in at the macro invocation site, instead of the macro definition site.
13 changes: 3 additions & 10 deletions cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import cpp
import codingstandards.cpp.autosar
import codingstandards.cpp.Macro
import codingstandards.cpp.CStyleCasts

/**
* Gets the macro (if any) that generated the given `CStyleCast`.
Expand Down Expand Up @@ -61,18 +62,10 @@ Macro getGeneratedFrom(CStyleCast c) {
* argument type is compatible with a single-argument constructor.
*/

from CStyleCast c, string extraMessage, Locatable l, string supplementary
from ExplicitUserDefinedCStyleCast c, string extraMessage, Locatable l, string supplementary
where
not isExcluded(c, BannedSyntaxPackage::traditionalCStyleCastsUsedQuery()) and
not c.isImplicit() and
not c.getType() instanceof UnknownType and
// For casts in templates that occur on types related to a template parameter, the copy of th
// cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all
// the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case
// of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on
// uninstantiated templates, and instead rely on reporting results within instantiations.
not c.isFromUninstantiatedTemplate(_) and
// Exclude casts created from macro invocations of macros defined by third parties
// Not generated from a library macro
not getGeneratedFrom(c) instanceof LibraryMacro and
// If the cast was generated from a user-provided macro, then report the macro that generated the
// cast, as the macro itself may have generated the cast
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@

import cpp
import codingstandards.cpp.autosar
import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer

from Cast cast, VirtualBaseClass castFrom, Class castTo
where
not isExcluded(cast, PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery()) and
not cast instanceof DynamicCast and
castFrom = cast.getExpr().getType().(PointerType).getBaseType() and
cast.getType().(PointerType).getBaseType() = castTo and
castTo = castFrom.getADerivedClass+()
select cast,
"A pointer to virtual base class $@ is not cast to a pointer of derived class $@ using a dynamic_cast.",
castFrom, castFrom.getName(), castTo, castTo.getName()
class PointerToAVirtualBaseClassCastToAPointerQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery
{
PointerToAVirtualBaseClassCastToAPointerQuery() {
this = PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery()
}
}
2 changes: 1 addition & 1 deletion cpp/autosar/test/rules/A5-2-2/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <string>
#include <utility>
int foo() { return 1; }

// A copy of 8.2,2 test.cpp, but with different cases compliant/non-compliant
void test_c_style_cast() {
double f = 3.14;
std::uint32_t n1 = (std::uint32_t)f; // NON_COMPLIANT - C-style cast
Expand Down

This file was deleted.

18 changes: 0 additions & 18 deletions cpp/autosar/test/rules/M5-2-2/test.cpp

This file was deleted.

17 changes: 15 additions & 2 deletions cpp/common/src/codingstandards/cpp/AlertReporting.qll
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,28 @@ module MacroUnwrapper<ResultType ResultElement> {
* Gets a macro invocation that applies to the result element.
*/
private MacroInvocation getAMacroInvocation(ResultElement re) {
result.getAnExpandedElement() = re
result.getAnAffectedElement() = re
}

private MacroInvocation getASubsumedMacroInvocation(ResultElement re) {
result = getAMacroInvocation(re) and
// Only report cases where the element is not located at the macro expansion site
// This means we'll report results in macro arguments in the macro argument
// location, not within the macro itself.
//
// Do not join start column values.
pragma[only_bind_out](result.getLocation().getStartColumn()) =
pragma[only_bind_out](re.getLocation().getStartColumn())
}

/**
* Gets the primary macro invocation that generated the result element.
*
* Does not hold for cases where the result element is located at a macro argument site.
*/
MacroInvocation getPrimaryMacroInvocation(ResultElement re) {
exists(MacroInvocation mi |
mi = getAMacroInvocation(re) and
mi = getASubsumedMacroInvocation(re) and
// No other more specific macro that expands to element
not exists(MacroInvocation otherMi |
otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi
Expand Down
18 changes: 18 additions & 0 deletions cpp/common/src/codingstandards/cpp/CStyleCasts.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import cpp
import codingstandards.cpp.Macro

/**
* A C-style cast that is explicitly user written and has a known target type.
*/
class ExplicitUserDefinedCStyleCast extends CStyleCast {
ExplicitUserDefinedCStyleCast() {
not this.isImplicit() and
not this.getType() instanceof UnknownType and
// For casts in templates that occur on types related to a template parameter, the copy of th
// cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all
// the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case
// of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on
// uninstantiated templates, and instead rely on reporting results within instantiations.
not this.isFromUninstantiatedTemplate(_)
}
}
112 changes: 112 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype Conversions2Query =
TVirtualBaseClassCastToDerivedQuery() or
TNoCStyleOrFunctionalCastsQuery() or
TIntToPointerCastProhibitedQuery() or
TNoPointerToIntegralCastQuery() or
TPointerToIntegralCastQuery() or
TNoStandaloneTypeCastExpressionQuery()

predicate isConversions2QueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `virtualBaseClassCastToDerived` query
Conversions2Package::virtualBaseClassCastToDerivedQuery() and
queryId =
// `@id` for the `virtualBaseClassCastToDerived` query
"cpp/misra/virtual-base-class-cast-to-derived" and
ruleId = "RULE-8-2-1" and
category = "required"
or
query =
// `Query` instance for the `noCStyleOrFunctionalCasts` query
Conversions2Package::noCStyleOrFunctionalCastsQuery() and
queryId =
// `@id` for the `noCStyleOrFunctionalCasts` query
"cpp/misra/no-c-style-or-functional-casts" and
ruleId = "RULE-8-2-2" and
category = "required"
or
query =
// `Query` instance for the `intToPointerCastProhibited` query
Conversions2Package::intToPointerCastProhibitedQuery() and
queryId =
// `@id` for the `intToPointerCastProhibited` query
"cpp/misra/int-to-pointer-cast-prohibited" and
ruleId = "RULE-8-2-6" and
category = "required"
or
query =
// `Query` instance for the `noPointerToIntegralCast` query
Conversions2Package::noPointerToIntegralCastQuery() and
queryId =
// `@id` for the `noPointerToIntegralCast` query
"cpp/misra/no-pointer-to-integral-cast" and
ruleId = "RULE-8-2-7" and
category = "advisory"
or
query =
// `Query` instance for the `pointerToIntegralCast` query
Conversions2Package::pointerToIntegralCastQuery() and
queryId =
// `@id` for the `pointerToIntegralCast` query
"cpp/misra/pointer-to-integral-cast" and
ruleId = "RULE-8-2-8" and
category = "required"
or
query =
// `Query` instance for the `noStandaloneTypeCastExpression` query
Conversions2Package::noStandaloneTypeCastExpressionQuery() and
queryId =
// `@id` for the `noStandaloneTypeCastExpression` query
"cpp/misra/no-standalone-type-cast-expression" and
ruleId = "RULE-9-2-1" and
category = "required"
}

module Conversions2Package {
Query virtualBaseClassCastToDerivedQuery() {
//autogenerate `Query` type
result =
// `Query` type for `virtualBaseClassCastToDerived` query
TQueryCPP(TConversions2PackageQuery(TVirtualBaseClassCastToDerivedQuery()))
}

Query noCStyleOrFunctionalCastsQuery() {
//autogenerate `Query` type
result =
// `Query` type for `noCStyleOrFunctionalCasts` query
TQueryCPP(TConversions2PackageQuery(TNoCStyleOrFunctionalCastsQuery()))
}

Query intToPointerCastProhibitedQuery() {
//autogenerate `Query` type
result =
// `Query` type for `intToPointerCastProhibited` query
TQueryCPP(TConversions2PackageQuery(TIntToPointerCastProhibitedQuery()))
}

Query noPointerToIntegralCastQuery() {
//autogenerate `Query` type
result =
// `Query` type for `noPointerToIntegralCast` query
TQueryCPP(TConversions2PackageQuery(TNoPointerToIntegralCastQuery()))
}

Query pointerToIntegralCastQuery() {
//autogenerate `Query` type
result =
// `Query` type for `pointerToIntegralCast` query
TQueryCPP(TConversions2PackageQuery(TPointerToIntegralCastQuery()))
}

Query noStandaloneTypeCastExpressionQuery() {
//autogenerate `Query` type
result =
// `Query` type for `noStandaloneTypeCastExpression` query
TQueryCPP(TConversions2PackageQuery(TNoStandaloneTypeCastExpressionQuery()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Concurrency
import Conditionals
import Const
import Conversions
import Conversions2
import DeadCode
import Declarations
import ExceptionSafety
Expand Down Expand Up @@ -71,6 +72,7 @@ newtype TCPPQuery =
TConditionalsPackageQuery(ConditionalsQuery q) or
TConstPackageQuery(ConstQuery q) or
TConversionsPackageQuery(ConversionsQuery q) or
TConversions2PackageQuery(Conversions2Query q) or
TDeadCodePackageQuery(DeadCodeQuery q) or
TDeclarationsPackageQuery(DeclarationsQuery q) or
TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or
Expand Down Expand Up @@ -128,6 +130,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
isConditionalsQueryMetadata(query, queryId, ruleId, category) or
isConstQueryMetadata(query, queryId, ruleId, category) or
isConversionsQueryMetadata(query, queryId, ruleId, category) or
isConversions2QueryMetadata(query, queryId, ruleId, category) or
isDeadCodeQueryMetadata(query, queryId, ruleId, category) or
isDeclarationsQueryMetadata(query, queryId, ruleId, category) or
isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Provides a library with a `problems` predicate for the following issue:
* A pointer to a virtual base class shall only be cast to a pointer to a derived class
* by means of dynamic_cast, otherwise the cast has undefined behavior.
*/

import cpp
import codingstandards.cpp.Customizations
import codingstandards.cpp.Exclusions

abstract class PointerToAVirtualBaseClassCastToAPointerSharedQuery extends Query { }

Query getQuery() { result instanceof PointerToAVirtualBaseClassCastToAPointerSharedQuery }

query predicate problems(
Cast cast, string message, VirtualClassDerivation derivation, string derivationDescription
) {
exists(Class castFrom, VirtualBaseClass virtualBaseClass, Class castTo, string type |
not isExcluded(cast, getQuery()) and
not cast instanceof DynamicCast and
castTo = virtualBaseClass.getADerivedClass+() and
virtualBaseClass = castFrom.getADerivedClass*() and
derivation = virtualBaseClass.getAVirtualDerivation() and
derivation.getDerivedClass().getADerivedClass*() = castTo and
derivationDescription = "derived through virtual base class " + virtualBaseClass.getName() and
message =
"dynamic_cast not used for cast from " + type + " to base class " + castFrom.getName() +
" to derived class " + castTo.getName() + " which is $@."
|
// Pointer cast
castFrom = cast.getExpr().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
cast.getType().stripTopLevelSpecifiers().(PointerType).getBaseType() = castTo and
type = "pointer"
or
// Reference type cast
castFrom = cast.getExpr().getType().stripTopLevelSpecifiers() and
// Not actually represented as a reference type in our model - instead as the
// type itself
cast.getType().stripTopLevelSpecifiers() = castTo and
type = "reference"
)
}
3 changes: 3 additions & 0 deletions cpp/common/test/includes/standard-library/cstdint
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ using ::uint_fast32_t;
using ::uint_fast64_t;
using ::uint_fast8_t;
using ::uintmax_t;

using ::intptr_t;
using ::uintptr_t;
} // namespace std
#endif // _GHLIBCPP_CSTDINT
10 changes: 9 additions & 1 deletion cpp/common/test/includes/standard-library/mutex.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#ifndef _GHLIBCPP_MUTEX
#define _GHLIBCPP_MUTEX
#include "chrono.h"
#include <chrono>

namespace std {

Expand Down Expand Up @@ -77,6 +77,14 @@ template <typename Mutex> class lock_guard {
mutex_type &_m;
};

template <class... MutexTypes> class scoped_lock {
public:
explicit scoped_lock(MutexTypes &...m);
scoped_lock(const scoped_lock &) = delete;
scoped_lock &operator=(const scoped_lock &) = delete;
~scoped_lock();
};

} // namespace std

#endif // _GHLIBCPP_MUTEX
3 changes: 3 additions & 0 deletions cpp/common/test/includes/standard-library/stdint.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;

typedef long intptr_t;
typedef unsigned long uintptr_t;

#endif // _GHLIBCPP_STDINT
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
| test.cpp:41:12:41:37 | reinterpret_cast<C2 *>... | dynamic_cast not used for cast from pointer to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 |
| test.cpp:47:12:47:38 | reinterpret_cast<C2>... | dynamic_cast not used for cast from reference to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 |
| test.cpp:53:17:53:48 | reinterpret_cast<Derived>... | dynamic_cast not used for cast from reference to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 |
| test.cpp:86:12:86:37 | reinterpret_cast<C2 *>... | dynamic_cast not used for cast from pointer to base class C0 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer

class TestFileQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery, TestQuery { }
Loading
Loading