1 //=======- ASTUtils.cpp ------------------------------------------*- C++ -*-==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ASTUtils.h" 10 #include "PtrTypesSemantics.h" 11 #include "clang/AST/CXXInheritance.h" 12 #include "clang/AST/Decl.h" 13 #include "clang/AST/DeclCXX.h" 14 #include "clang/AST/ExprCXX.h" 15 #include "clang/AST/ExprObjC.h" 16 #include "clang/AST/StmtVisitor.h" 17 #include <optional> 18 19 namespace clang { 20 21 bool isSafePtr(clang::CXXRecordDecl *Decl) { 22 return isRefCounted(Decl) || isCheckedPtr(Decl); 23 } 24 25 bool tryToFindPtrOrigin( 26 const Expr *E, bool StopAtFirstRefCountedObj, 27 std::function<bool(const clang::Expr *, bool)> callback) { 28 while (E) { 29 if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(E)) { 30 E = tempExpr->getSubExpr(); 31 continue; 32 } 33 if (auto *tempExpr = dyn_cast<CXXBindTemporaryExpr>(E)) { 34 E = tempExpr->getSubExpr(); 35 continue; 36 } 37 if (auto *tempExpr = dyn_cast<CXXConstructExpr>(E)) { 38 if (auto *C = tempExpr->getConstructor()) { 39 if (auto *Class = C->getParent(); Class && isSafePtr(Class)) 40 return callback(E, true); 41 break; 42 } 43 } 44 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) { 45 if (auto *RF = POE->getResultExpr()) { 46 E = RF; 47 continue; 48 } 49 } 50 if (auto *tempExpr = dyn_cast<ParenExpr>(E)) { 51 E = tempExpr->getSubExpr(); 52 continue; 53 } 54 if (auto *Expr = dyn_cast<ConditionalOperator>(E)) { 55 return tryToFindPtrOrigin(Expr->getTrueExpr(), StopAtFirstRefCountedObj, 56 callback) && 57 tryToFindPtrOrigin(Expr->getFalseExpr(), StopAtFirstRefCountedObj, 58 callback); 59 } 60 if (auto *cast = dyn_cast<CastExpr>(E)) { 61 if (StopAtFirstRefCountedObj) { 62 if (auto *ConversionFunc = 63 dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) { 64 if (isCtorOfSafePtr(ConversionFunc)) 65 return callback(E, true); 66 } 67 } 68 // FIXME: This can give false "origin" that would lead to false negatives 69 // in checkers. See https://reviews.llvm.org/D37023 for reference. 70 E = cast->getSubExpr(); 71 continue; 72 } 73 if (auto *call = dyn_cast<CallExpr>(E)) { 74 if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) { 75 if (auto *decl = memberCall->getMethodDecl()) { 76 std::optional<bool> IsGetterOfRefCt = isGetterOfSafePtr(decl); 77 if (IsGetterOfRefCt && *IsGetterOfRefCt) { 78 E = memberCall->getImplicitObjectArgument(); 79 if (StopAtFirstRefCountedObj) { 80 return callback(E, true); 81 } 82 continue; 83 } 84 } 85 } 86 87 if (auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(E)) { 88 if (operatorCall->getNumArgs() == 1) { 89 E = operatorCall->getArg(0); 90 continue; 91 } 92 } 93 94 if (auto *callee = call->getDirectCallee()) { 95 if (isCtorOfRefCounted(callee) || isCtorOfCheckedPtr(callee)) { 96 if (StopAtFirstRefCountedObj) 97 return callback(E, true); 98 99 E = call->getArg(0); 100 continue; 101 } 102 103 if (isSafePtrType(callee->getReturnType())) 104 return callback(E, true); 105 106 if (isSingleton(callee)) 107 return callback(E, true); 108 109 if (callee->isInStdNamespace() && safeGetName(callee) == "forward") { 110 E = call->getArg(0); 111 continue; 112 } 113 114 if (isPtrConversion(callee)) { 115 E = call->getArg(0); 116 continue; 117 } 118 } 119 } 120 if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) { 121 if (auto *Method = ObjCMsgExpr->getMethodDecl()) { 122 if (isSafePtrType(Method->getReturnType())) 123 return callback(E, true); 124 } 125 } 126 if (auto *unaryOp = dyn_cast<UnaryOperator>(E)) { 127 // FIXME: Currently accepts ANY unary operator. Is it OK? 128 E = unaryOp->getSubExpr(); 129 continue; 130 } 131 132 break; 133 } 134 // Some other expression. 135 return callback(E, false); 136 } 137 138 bool isASafeCallArg(const Expr *E) { 139 assert(E); 140 if (auto *Ref = dyn_cast<DeclRefExpr>(E)) { 141 if (auto *D = dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) { 142 if (isa<ParmVarDecl>(D) || D->isLocalVarDecl()) 143 return true; 144 } 145 } 146 if (isConstOwnerPtrMemberExpr(E)) 147 return true; 148 149 // TODO: checker for method calls on non-refcounted objects 150 return isa<CXXThisExpr>(E); 151 } 152 153 bool isConstOwnerPtrMemberExpr(const clang::Expr *E) { 154 if (auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) { 155 if (auto *Callee = MCE->getDirectCallee()) { 156 auto Name = safeGetName(Callee); 157 if (Name == "get" || Name == "ptr") { 158 auto *ThisArg = MCE->getImplicitObjectArgument(); 159 E = ThisArg; 160 } 161 } 162 } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) { 163 if (OCE->getOperator() == OO_Star && OCE->getNumArgs() == 1) 164 E = OCE->getArg(0); 165 } 166 auto *ME = dyn_cast<MemberExpr>(E); 167 if (!ME) 168 return false; 169 auto *D = ME->getMemberDecl(); 170 if (!D) 171 return false; 172 auto T = D->getType(); 173 return isOwnerPtrType(T) && T.isConstQualified(); 174 } 175 176 class EnsureFunctionVisitor 177 : public ConstStmtVisitor<EnsureFunctionVisitor, bool> { 178 public: 179 bool VisitStmt(const Stmt *S) { 180 for (const Stmt *Child : S->children()) { 181 if (Child && !Visit(Child)) 182 return false; 183 } 184 return true; 185 } 186 187 bool VisitReturnStmt(const ReturnStmt *RS) { 188 if (auto *RV = RS->getRetValue()) { 189 RV = RV->IgnoreParenCasts(); 190 if (isa<CXXNullPtrLiteralExpr>(RV)) 191 return true; 192 return isConstOwnerPtrMemberExpr(RV); 193 } 194 return false; 195 } 196 }; 197 198 bool EnsureFunctionAnalysis::isACallToEnsureFn(const clang::Expr *E) const { 199 auto *MCE = dyn_cast<CXXMemberCallExpr>(E); 200 if (!MCE) 201 return false; 202 auto *Callee = MCE->getDirectCallee(); 203 if (!Callee) 204 return false; 205 auto *Body = Callee->getBody(); 206 if (!Body) 207 return false; 208 auto [CacheIt, IsNew] = Cache.insert(std::make_pair(Callee, false)); 209 if (IsNew) 210 CacheIt->second = EnsureFunctionVisitor().Visit(Body); 211 return CacheIt->second; 212 } 213 214 } // namespace clang 215