diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations5.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations5.qll new file mode 100644 index 000000000..ff4806a5b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations5.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations5Query = + TMemberFunctionsRefqualifiedQuery() or + TTypeAliasesDeclarationQuery() + +predicate isDeclarations5QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `memberFunctionsRefqualified` query + Declarations5Package::memberFunctionsRefqualifiedQuery() and + queryId = + // `@id` for the `memberFunctionsRefqualified` query + "cpp/misra/member-functions-refqualified" and + ruleId = "RULE-6-8-4" and + category = "advisory" + or + query = + // `Query` instance for the `typeAliasesDeclaration` query + Declarations5Package::typeAliasesDeclarationQuery() and + queryId = + // `@id` for the `typeAliasesDeclaration` query + "cpp/misra/type-aliases-declaration" and + ruleId = "RULE-6-9-1" and + category = "required" +} + +module Declarations5Package { + Query memberFunctionsRefqualifiedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `memberFunctionsRefqualified` query + TQueryCPP(TDeclarations5PackageQuery(TMemberFunctionsRefqualifiedQuery())) + } + + Query typeAliasesDeclarationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `typeAliasesDeclaration` query + TQueryCPP(TDeclarations5PackageQuery(TTypeAliasesDeclarationQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 3b8175042..4ac25ca67 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -34,6 +34,7 @@ import DeadCode9 import Declarations import Declarations1 import Declarations2 +import Declarations5 import ExceptionSafety import Exceptions1 import Exceptions2 @@ -131,6 +132,7 @@ newtype TCPPQuery = TDeclarationsPackageQuery(DeclarationsQuery q) or TDeclarations1PackageQuery(Declarations1Query q) or TDeclarations2PackageQuery(Declarations2Query q) or + TDeclarations5PackageQuery(Declarations5Query q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or @@ -228,6 +230,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeclarationsQueryMetadata(query, queryId, ruleId, category) or isDeclarations1QueryMetadata(query, queryId, ruleId, category) or isDeclarations2QueryMetadata(query, queryId, ruleId, category) or + isDeclarations5QueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or isExceptions1QueryMetadata(query, queryId, ruleId, category) or isExceptions2QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/misra/src/rules/RULE-6-8-4/MemberFunctionsRefqualified.ql b/cpp/misra/src/rules/RULE-6-8-4/MemberFunctionsRefqualified.ql new file mode 100644 index 000000000..360d17f0e --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-8-4/MemberFunctionsRefqualified.ql @@ -0,0 +1,117 @@ +/** + * @id cpp/misra/member-functions-refqualified + * @name RULE-6-8-4: Member functions returning references to their object should be refqualified appropriately + * @description Member functions that return references to temporary objects (or subobjects) can + * lead to dangling pointers. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-8-4 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.types.Compatible +import codingstandards.cpp.Operator + +class MembersReturningPointerOrRef extends MemberFunction { + MembersReturningPointerOrRef() { + this.getUnspecifiedType() instanceof PointerType or + this.getUnspecifiedType() instanceof ReferenceType + } +} + +abstract class MembersReturningObjectOrSubobject extends MembersReturningPointerOrRef { + string toString() { result = "Members returning object or subobject" } +} + +class MembersReturningObject extends MembersReturningObjectOrSubobject { + MembersReturningObject() { + exists(ReturnStmt r, ThisExpr t | + r.getEnclosingFunction() = this and + ( + r.getAChild*() = t + or + exists(PointerDereferenceExpr p | + p.getAChild*() = t and + r.getAChild*() = p + ) + ) and + t.getActualType().stripType() = this.getDeclaringType() + ) + } +} + +class MembersReturningSubObject extends MembersReturningObjectOrSubobject { + MembersReturningSubObject() { + exists(ReturnStmt r, FieldSubObjectDeclaration field | + r.getEnclosingFunction() = this and + ( + r.getAChild*() = field.(Field).getAnAccess() + or + exists(PointerDereferenceExpr p | + p.getAChild*() = field.(Field).getAnAccess() and + r.getAChild*() = p + ) + ) and + field.(Field).getDeclaringType() = this.getDeclaringType() + ) + } +} + +predicate relevantTypes(Type a, Type b) { + exists(MembersReturningObject f, MemberFunction overload | + f.getAnOverload() = overload and + exists(int i | + f.getParameter(i).getType() = a and + overload.getParameter(i).getType() = b + ) + ) +} + +class AppropriatelyQualified extends MembersReturningObjectOrSubobject { + AppropriatelyQualified() { + //non-const-lvalue-ref-qualified + this.isLValueRefQualified() and + not this.hasSpecifier("const") + or + //const-lvalue-ref-qualified + this.isLValueRefQualified() and + this.hasSpecifier("const") and + //and overload exists that is rvalue-ref-qualified + exists(MemberFunction overload | + this.getAnOverload() = overload and + overload.isRValueRefQualified() and + //and has same param list + forall(int i | exists([this, overload].getParameter(i)) | + TypeEquivalence::equalTypes(this.getParameter(i) + .getType(), overload.getParameter(i).getType()) + ) + ) + } +} + +/** + * Fields that are not reference type can be subobjects + */ +class FieldSubObjectDeclaration extends Declaration { + FieldSubObjectDeclaration() { + not this.getADeclarationEntry().getType() instanceof ReferenceType and + this instanceof Field + } +} + +class DefaultedAssignmentOperator extends AssignmentOperator { + DefaultedAssignmentOperator() { this.isDefaulted() } +} + +from MembersReturningObjectOrSubobject f +where + not isExcluded(f, Declarations5Package::memberFunctionsRefqualifiedQuery()) and + not f instanceof AppropriatelyQualified and + not f instanceof DefaultedAssignmentOperator +select f, "Member function is not properly ref qualified." diff --git a/cpp/misra/src/rules/RULE-6-9-1/TypeAliasesDeclaration.ql b/cpp/misra/src/rules/RULE-6-9-1/TypeAliasesDeclaration.ql new file mode 100644 index 000000000..d8898377d --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-9-1/TypeAliasesDeclaration.ql @@ -0,0 +1,33 @@ +/** + * @id cpp/misra/type-aliases-declaration + * @name RULE-6-9-1: The same type aliases shall be used in all declarations of the same entity + * @description Using different type aliases on redeclarations can make code hard to understand and + * maintain. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-6-9-1 + * maintainability + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from DeclarationEntry decl1, DeclarationEntry decl2, TypedefType t +where + not isExcluded(decl1, Declarations5Package::typeAliasesDeclarationQuery()) and + not isExcluded(decl2, Declarations5Package::typeAliasesDeclarationQuery()) and + not decl1 = decl2 and + decl1.getDeclaration() = decl2.getDeclaration() and + t.getATypeNameUse() = decl1 and + not t.getATypeNameUse() = decl2 and + //exception cases - we dont want to disallow struct typedef name use + not t.getBaseType() instanceof Struct and + not t.getBaseType() instanceof Enum +select decl1, + "Declaration entry has a different type alias than $@ where the type alias used is '$@'.", decl2, + decl2.getName(), t, t.getName() diff --git a/cpp/misra/test/rules/RULE-6-8-4/MemberFunctionsRefqualified.expected b/cpp/misra/test/rules/RULE-6-8-4/MemberFunctionsRefqualified.expected new file mode 100644 index 000000000..d81930a4d --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-8-4/MemberFunctionsRefqualified.expected @@ -0,0 +1,6 @@ +| test.cpp:12:14:12:20 | Members returning object or subobject | Member function is not properly ref qualified. | +| test.cpp:24:12:24:23 | Members returning object or subobject | Member function is not properly ref qualified. | +| test.cpp:28:6:28:18 | Members returning object or subobject | Member function is not properly ref qualified. | +| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. | +| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. | +| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. | diff --git a/cpp/misra/test/rules/RULE-6-8-4/MemberFunctionsRefqualified.qlref b/cpp/misra/test/rules/RULE-6-8-4/MemberFunctionsRefqualified.qlref new file mode 100644 index 000000000..c214d5ca1 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-8-4/MemberFunctionsRefqualified.qlref @@ -0,0 +1 @@ +rules/RULE-6-8-4/MemberFunctionsRefqualified.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-8-4/test.cpp b/cpp/misra/test/rules/RULE-6-8-4/test.cpp new file mode 100644 index 000000000..dacfdde4a --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-8-4/test.cpp @@ -0,0 +1,54 @@ +struct A { + int a; + int &b; + + int &geta() & { return a; } // COMPLIANT + + int const &geta2() const & { // COMPLIANT -- due to overload below + return a; + } + int geta2() && { return a; } + + int const &getabad() const & { // NON_COMPLIANT -- no overload provided + return a; + } + + int getb() && { return b; } // COMPLIANT -- b is not a subobject + + A const *getstruct() const & { // COMPLIANT -- due to overload below + return this; + } + + A getstruct() const && = delete; + + A const *getstructbad() const & { // NON_COMPLIANT -- no overload provided + return this; + } + + A &getstructbad2() { return *this; } // NON_COMPLIANT +}; + +class C { + C *f() { // COMPLIANT -- this is not explicitly designated therefore this is + // not + // relevant for this rule + C *thisclass = this; + return thisclass; + } +}; + +struct Templ { + template + Templ const *f(T) const & { // NON_COMPLIANT -- for an instantiation below + return this; + } + + void f(int) const && = delete; +}; + +void f(int p, float p1) { + Templ t; + t.f(p); + t.f(p1); // instantiation that causes issue due to parameter list type meaning + // there is no overload +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-9-1/TypeAliasesDeclaration.expected b/cpp/misra/test/rules/RULE-6-9-1/TypeAliasesDeclaration.expected new file mode 100644 index 000000000..db0ef7b72 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-9-1/TypeAliasesDeclaration.expected @@ -0,0 +1,2 @@ +| test.cpp:4:5:4:5 | definition of i | Declaration entry has a different type alias than $@ where the type alias used is '$@'. | test.cpp:5:12:5:12 | declaration of i | i | test.cpp:1:13:1:15 | INT | INT | +| test.cpp:11:20:11:20 | declaration of i | Declaration entry has a different type alias than $@ where the type alias used is '$@'. | test.cpp:10:12:10:12 | declaration of i | i | test.cpp:2:7:2:11 | Index | Index | diff --git a/cpp/misra/test/rules/RULE-6-9-1/TypeAliasesDeclaration.qlref b/cpp/misra/test/rules/RULE-6-9-1/TypeAliasesDeclaration.qlref new file mode 100644 index 000000000..a3cf4823c --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-9-1/TypeAliasesDeclaration.qlref @@ -0,0 +1 @@ +rules/RULE-6-9-1/TypeAliasesDeclaration.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-9-1/test.cpp b/cpp/misra/test/rules/RULE-6-9-1/test.cpp new file mode 100644 index 000000000..dfc18becf --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-9-1/test.cpp @@ -0,0 +1,15 @@ +typedef int INT; +using Index = int; + +INT i; +extern int i; // NON_COMPLIANT + +INT j; +extern INT j; // COMPLIANT + +void g(int i); +void g(Index const i); // NON_COMPLIANT + +void h(Index i); +void h(Index const i); // COMPLIANT +void h(int *i); // COMPLIANT \ No newline at end of file diff --git a/rule_packages/cpp/Declarations5.json b/rule_packages/cpp/Declarations5.json new file mode 100644 index 000000000..4f4c08e7d --- /dev/null +++ b/rule_packages/cpp/Declarations5.json @@ -0,0 +1,47 @@ +{ + "MISRA-C++-2023": { + "RULE-6-8-4": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Member functions that return references to temporary objects (or subobjects) can lead to dangling pointers.", + "kind": "problem", + "name": "Member functions returning references to their object should be refqualified appropriately", + "precision": "very-high", + "severity": "error", + "short_name": "MemberFunctionsRefqualified", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "Member functions returning references to their object should be refqualified appropriately" + }, + "RULE-6-9-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using different type aliases on redeclarations can make code hard to understand and maintain.", + "kind": "problem", + "name": "The same type aliases shall be used in all declarations of the same entity", + "precision": "very-high", + "severity": "warning", + "short_name": "TypeAliasesDeclaration", + "tags": [ + "maintainability", + "readability", + "scope/single-translation-unit" + ] + } + ], + "title": "The same type aliases shall be used in all declarations of the same entity" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index bbbb47f38..beb82215d 100644 --- a/rules.csv +++ b/rules.csv @@ -867,8 +867,8 @@ cpp,MISRA-C++-2023,RULE-6-7-2,Yes,Required,Decidable,Single Translation Unit,Glo cpp,MISRA-C++-2023,RULE-6-8-1,Yes,Required,Undecidable,System,An object shall not be accessed outside of its lifetime,A3-8-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A function must not return a reference or a pointer to a local variable with automatic storage duration,M7-5-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,Lifetime,Medium, -cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations3,Medium, -cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations3,Medium, +cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations5,Medium, +cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations5,Medium, cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy,