|
| 1 | +/** |
| 2 | + * @id cpp/misra/member-functions-refqualified |
| 3 | + * @name RULE-6-8-4: Member functions returning references to their object should be refqualified appropriately |
| 4 | + * @description Member functions that return references to temporary objects (or subobjects) can |
| 5 | + * lead to dangling pointers. |
| 6 | + * @kind problem |
| 7 | + * @precision very-high |
| 8 | + * @problem.severity error |
| 9 | + * @tags external/misra/id/rule-6-8-4 |
| 10 | + * correctness |
| 11 | + * scope/single-translation-unit |
| 12 | + * external/misra/enforcement/decidable |
| 13 | + * external/misra/obligation/advisory |
| 14 | + */ |
| 15 | + |
| 16 | +import cpp |
| 17 | +import codingstandards.cpp.misra |
| 18 | +import codingstandards.cpp.types.Compatible |
| 19 | +import codingstandards.cpp.Operator |
| 20 | + |
| 21 | +abstract class MembersReturningObjectOrSubobject extends MemberFunction { |
| 22 | + string toString() { result = "Members returning object or subobject" } |
| 23 | +} |
| 24 | + |
| 25 | +class MembersReturningObject extends MembersReturningObjectOrSubobject { |
| 26 | + MembersReturningObject() { |
| 27 | + exists(ReturnStmt r, ThisExpr t | |
| 28 | + r.getEnclosingFunction() = this and |
| 29 | + ( |
| 30 | + r.getAChild*() = t |
| 31 | + or |
| 32 | + exists(PointerDereferenceExpr p | |
| 33 | + p.getAChild*() = t and |
| 34 | + r.getAChild*() = p |
| 35 | + ) |
| 36 | + ) and |
| 37 | + t.getActualType().stripType() = this.getDeclaringType() |
| 38 | + ) |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +class MembersReturningSubObject extends MembersReturningObjectOrSubobject { |
| 43 | + MembersReturningSubObject() { |
| 44 | + exists(ReturnStmt r, FieldSubObjectDeclaration field | |
| 45 | + r.getEnclosingFunction() = this and |
| 46 | + ( |
| 47 | + r.getAChild*() = field.(Field).getAnAccess() |
| 48 | + or |
| 49 | + exists(PointerDereferenceExpr p | |
| 50 | + p.getAChild*() = field.(Field).getAnAccess() and |
| 51 | + r.getAChild*() = p |
| 52 | + ) |
| 53 | + ) and |
| 54 | + field.(Field).getDeclaringType() = this.getDeclaringType() |
| 55 | + ) |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +predicate relevantTypes(Type a, Type b) { |
| 60 | + exists(MembersReturningObject f, MemberFunction overload | |
| 61 | + f.getAnOverload() = overload and |
| 62 | + exists(int i | |
| 63 | + f.getParameter(i).getType() = a and |
| 64 | + overload.getParameter(i).getType() = b |
| 65 | + ) |
| 66 | + ) |
| 67 | +} |
| 68 | + |
| 69 | +class AppropriatelyQualified extends MembersReturningObjectOrSubobject { |
| 70 | + AppropriatelyQualified() { |
| 71 | + //non-const-lvalue-ref-qualified |
| 72 | + this.isLValueRefQualified() and |
| 73 | + not this.hasSpecifier("const") |
| 74 | + or |
| 75 | + //const-lvalue-ref-qualified |
| 76 | + this.isLValueRefQualified() and |
| 77 | + this.hasSpecifier("const") and |
| 78 | + //and overload exists that is rvalue-ref-qualified |
| 79 | + exists(MemberFunction overload | |
| 80 | + this.getAnOverload() = overload and |
| 81 | + overload.isRValueRefQualified() and |
| 82 | + //and has same param list |
| 83 | + forall(int i | exists([this, overload].getParameter(i)) | |
| 84 | + TypeEquivalence<TypesCompatibleConfig, relevantTypes/2>::equalTypes(this.getParameter(i) |
| 85 | + .getType(), overload.getParameter(i).getType()) |
| 86 | + ) |
| 87 | + ) |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +/** |
| 92 | + * Fields that are not reference type can be subobjects |
| 93 | + */ |
| 94 | +class FieldSubObjectDeclaration extends Declaration { |
| 95 | + FieldSubObjectDeclaration() { |
| 96 | + not this.getADeclarationEntry().getType() instanceof ReferenceType and |
| 97 | + this instanceof Field |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +class DefaultedAssignmentOperator extends AssignmentOperator { |
| 102 | + DefaultedAssignmentOperator() { this.isDefaulted() } |
| 103 | +} |
| 104 | + |
| 105 | +from MembersReturningObjectOrSubobject f |
| 106 | +where |
| 107 | + not isExcluded(f, Declarations5Package::memberFunctionsRefqualifiedQuery()) and |
| 108 | + not f instanceof AppropriatelyQualified and |
| 109 | + not f instanceof DefaultedAssignmentOperator |
| 110 | +select f, "Member function is not properly ref qualified." |
0 commit comments