32bool isRefcountedStringsHack(
const VarDecl *
V) {
34 auto safeClass = [](
const std::string &className) {
35 return className ==
"String" || className ==
"AtomString" ||
36 className ==
"UniquedString" || className ==
"Identifier";
40 if (
auto *CXXRD =
T->getAsCXXRecordDecl()) {
44 if (
T->isPointerType() ||
T->isReferenceType()) {
45 if (
auto *CXXRD =
T->getPointeeCXXRecordDecl()) {
54 const VarDecl *Guardian{
nullptr};
56 explicit GuardianVisitor(
const VarDecl *Guardian) : Guardian(Guardian) {
60 bool VisitBinaryOperator(BinaryOperator *BO)
override {
62 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
63 if (VarRef->getDecl() == Guardian)
70 bool VisitCXXConstructExpr(CXXConstructExpr *CE)
override {
74 unsigned ArgIndex = 0;
76 ParmVarDecl *Parm =
nullptr;
77 if (ArgIndex < Ctor->getNumParams())
78 Parm = Ctor->getParamDecl(ArgIndex);
79 if (mutatesGuardian(Arg, Parm))
86 bool VisitCallExpr(CallExpr *CE)
override {
92 if (
auto *
Method = dyn_cast<CXXMethodDecl>(Callee)) {
96 unsigned ArgIndex = 0;
99 ParmVarDecl *Parm =
nullptr;
100 if (ArgIndex >= ArgOffset) {
101 unsigned ParmIndex = ArgIndex - ArgOffset;
102 if (ParmIndex < Callee->getNumParams())
103 Parm =
Callee->getParamDecl(ParmIndex);
105 if (mutatesGuardian(Arg, Parm))
112 bool VisitCXXMemberCallExpr(CXXMemberCallExpr *MCE)
override {
115 if (ObjType.isConstQualified())
118 if (
auto *VarRef = dyn_cast<DeclRefExpr>(ThisArg)) {
126 bool mutatesGuardian(
const Expr *Arg,
const ParmVarDecl *ParmDecl) {
128 if (
auto *VarRef = dyn_cast<DeclRefExpr>(Arg)) {
129 if (VarRef->getDecl() == Guardian) {
131 if (!ArgType.isConstQualified())
139bool isGuardedScopeEmbeddedInGuardianScope(
const VarDecl *Guarded,
140 const VarDecl *MaybeGuardian) {
142 assert(MaybeGuardian);
147 const CompoundStmt *guardiansClosestCompStmtAncestor =
nullptr;
152 !guardianAncestors.
empty();
157 for (
auto &guardianAncestor : guardianAncestors) {
158 if (
auto *CStmtParentAncestor = guardianAncestor.get<
CompoundStmt>()) {
159 guardiansClosestCompStmtAncestor = CStmtParentAncestor;
163 if (guardiansClosestCompStmtAncestor)
167 if (!guardiansClosestCompStmtAncestor)
174 !guardedVarAncestors.
empty();
179 for (
auto &guardedVarAncestor : guardedVarAncestors) {
180 if (
auto *CStmtAncestor = guardedVarAncestor.get<
CompoundStmt>()) {
181 if (!FirstCompondStmt) {
182 FirstCompondStmt = CStmtAncestor;
185 if (CStmtAncestor == guardiansClosestCompStmtAncestor) {
186 GuardianVisitor guardianVisitor(MaybeGuardian);
187 auto *GuardedScope =
const_cast<CompoundStmt *
>(FirstCompondStmt);
188 return guardianVisitor.TraverseCompoundStmt(GuardedScope);
197class RawPtrRefLocalVarsChecker
198 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
200 EnsureFunctionAnalysis EFA;
203 mutable BugReporter *BR;
204 const std::unique_ptr<PtrRefSafetyModel> Model;
207 RawPtrRefLocalVarsChecker(
const char *description,
208 std::unique_ptr<PtrRefSafetyModel> Model)
209 : Bug(this, description,
"WebKit coding guidelines"),
210 Model(std::move(Model)) {}
212 std::optional<bool> isUnsafePtr(QualType
T)
const {
216 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
217 BugReporter &BRArg)
const {
224 const RawPtrRefLocalVarsChecker *Checker;
225 Decl *DeclWithIssue{
nullptr};
227 TrivialFunctionAnalysis TFA;
229 explicit LocalVisitor(
const RawPtrRefLocalVarsChecker *Checker)
232 ShouldVisitTemplateInstantiations =
true;
233 ShouldVisitImplicitCode =
false;
236 bool TraverseDecl(Decl *D)
override {
237 llvm::SaveAndRestore SavedDecl(DeclWithIssue);
243 bool VisitTypedefDecl(TypedefDecl *TD)
override {
244 if (
auto *RTC = Checker->Model->retainTypeChecker())
245 RTC->visitTypedef(TD);
249 bool VisitVarDecl(VarDecl *
V)
override {
250 auto *
Init =
V->getInit();
251 if (
V->isLocalVarDecl())
252 Checker->visitVarDecl(
V,
Init, DeclWithIssue);
256 bool VisitBinaryOperator(BinaryOperator *BO)
override {
258 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
259 if (
auto *
V = dyn_cast<VarDecl>(VarRef->getDecl()))
260 Checker->visitVarDecl(
V, BO->
getRHS(), DeclWithIssue);
266 bool TraverseIfStmt(IfStmt *IS)
override {
276 return DynamicRecursiveASTVisitor::TraverseIfStmt(IS);
280 bool TraverseForStmt(ForStmt *FS)
override {
282 return DynamicRecursiveASTVisitor::TraverseForStmt(FS);
286 bool TraverseCXXForRangeStmt(CXXForRangeStmt *FRS)
override {
288 return DynamicRecursiveASTVisitor::TraverseCXXForRangeStmt(FRS);
292 bool TraverseWhileStmt(WhileStmt *WS)
override {
294 return DynamicRecursiveASTVisitor::TraverseWhileStmt(WS);
300 return DynamicRecursiveASTVisitor::TraverseCompoundStmt(CS);
304 bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl)
override {
307 return DynamicRecursiveASTVisitor::TraverseClassTemplateDecl(Decl);
311 LocalVisitor visitor(
this);
312 if (
auto *RTC = Model->retainTypeChecker())
313 RTC->visitTranslationUnitDecl(TUD);
314 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
317 void visitVarDecl(
const VarDecl *
V,
const Expr *
Value,
318 const Decl *DeclWithIssue)
const {
319 if (shouldSkipVarDecl(
V))
322 if (
auto *DD = dyn_cast<DecompositionDecl>(
V)) {
323 for (
auto *BD : DD->bindings()) {
324 auto *Binding = BD->getBinding();
327 std::optional<bool> IsUncountedPtr = isUnsafePtr(Binding->getType());
328 if (!IsUncountedPtr || !*IsUncountedPtr)
330 reportBug(
V,
nullptr, BD, DeclWithIssue);
334 std::optional<bool> IsUncountedPtr = isUnsafePtr(
V->getType());
335 if (IsUncountedPtr && *IsUncountedPtr) {
336 if (
Value && isPtrOriginSafe(
V,
Value, DeclWithIssue))
338 reportBug(
V,
Value,
nullptr, DeclWithIssue);
342 bool isPtrOriginSafe(
const VarDecl *
V,
const Expr *
Value,
343 const Decl *DeclWithIssue)
const {
346 [&](
const clang::CXXRecordDecl *
Record) {
347 return Model->isSafePtr(
Record);
349 [&](
const clang::QualType
Type) {
return Model->isSafePtrType(
Type); },
350 [&](
const clang::Decl *D) {
351 return Model->isSafeDecl(D, BR->getSourceManager());
353 [&](
const clang::Expr *InitArgOrigin,
bool IsSafe) {
354 if (!InitArgOrigin || IsSafe)
369 if (EFA.isACallToEnsureFn(InitArgOrigin))
372 if (Model->isSafeExpr(InitArgOrigin))
375 if (
auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
376 if (
auto *MaybeGuardian =
377 dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
378 const auto *MaybeGuardianArgType =
380 if (MaybeGuardianArgType) {
381 const CXXRecordDecl *
const MaybeGuardianArgCXXRecord =
382 MaybeGuardianArgType->getAsCXXRecordDecl();
383 if (MaybeGuardianArgCXXRecord) {
385 (Model->isSafePtr(MaybeGuardianArgCXXRecord) ||
386 isRefcountedStringsHack(MaybeGuardian)) &&
387 isGuardedScopeEmbeddedInGuardianScope(
V, MaybeGuardian))
393 if (
auto *FD = dyn_cast<FunctionDecl>(DeclWithIssue)) {
394 if (GuardianVisitor{MaybeGuardian}.TraverseStmt(
398 if (
auto *MD = dyn_cast<ObjCMethodDecl>(DeclWithIssue)) {
399 if (GuardianVisitor{MaybeGuardian}.TraverseStmt(
411 bool shouldSkipVarDecl(
const VarDecl *
V)
const {
415 return BR->getSourceManager().isInSystemHeader(
V->getLocation());
418 void reportBug(
const VarDecl *
V,
const Expr *
Value,
const Decl *BindingDecl,
419 const Decl *DeclWithIssue)
const {
421 SmallString<100> Buf;
422 llvm::raw_svector_ostream Os(Buf);
428 printPointerTypeAndType(Os,
V->getType());
430 SourceLocation ExprLoc = (
Value) ?
Value->getExprLoc() :
V->getLocation();
431 PathDiagnosticLocation BSLoc(ExprLoc, BR->getSourceManager());
432 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
435 Report->setDeclWithIssue(DeclWithIssue);
436 BR->emitReport(std::move(
Report));
438 if (
V->hasLocalStorage())
439 Os <<
"Local variable ";
440 else if (
V->isStaticLocal())
441 Os <<
"Static local variable ";
442 else if (
V->hasGlobalStorage())
443 Os <<
"Global variable ";
451 printPointerTypeAndType(Os,
V->getType());
453 PathDiagnosticLocation BSLoc(
V->getLocation(), BR->getSourceManager());
454 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
455 Report->addRange(
V->getSourceRange());
456 Report->setDeclWithIssue(DeclWithIssue);
457 BR->emitReport(std::move(
Report));
461 void printPointerTypeAndType(llvm::raw_svector_ostream &Os,
464 auto *RTC = Model->retainTypeChecker();
466 Os << Model->typeName() <<
" ";
467 if (
auto *Decl = RTC->getCanonicalDecl(QT)) {
470 auto Typedef = VarType->getAs<TypedefType>();
475 auto *DesugaredType = VarType->getUnqualifiedDesugaredType();
477 Os <<
"raw " << (IsPtr ?
"pointer" :
"reference") <<
" to ";
478 Os << Model->typeName() <<
" ";
484class UncountedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
486 UncountedLocalVarsChecker()
487 : RawPtrRefLocalVarsChecker(
"Uncounted raw pointer or reference not "
488 "provably backed by ref-counted variable",
492class UncheckedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
494 UncheckedLocalVarsChecker()
495 : RawPtrRefLocalVarsChecker(
"Unchecked raw pointer or reference not "
496 "provably backed by checked variable",
500class UnretainedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
502 UnretainedLocalVarsChecker()
503 : RawPtrRefLocalVarsChecker(
"Unretained raw pointer or reference not "
504 "provably backed by a RetainPtr",
510void ento::registerUncountedLocalVarsChecker(
CheckerManager &Mgr) {
514bool ento::shouldRegisterUncountedLocalVarsChecker(
const CheckerManager &) {
518void ento::registerUncheckedLocalVarsChecker(
CheckerManager &Mgr) {
522bool ento::shouldRegisterUncheckedLocalVarsChecker(
const CheckerManager &) {
526void ento::registerUnretainedLocalVarsChecker(
CheckerManager &Mgr) {
530bool ento::shouldRegisterUnretainedLocalVarsChecker(
const CheckerManager &) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::MachO::Record Record
Defines the clang::SourceLocation class and associated facilities.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
DynTypedNodeList getParents(const NodeT &Node)
Forwards to get node parents from the ParentMapContext.
static bool isAssignmentOp(Opcode Opc)
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
QualType getObjectType() const
Retrieve the type of the object argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
CompoundStmt - This represents a group of statements like { stmt stmt }.
ASTContext & getASTContext() const LLVM_READONLY
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
virtual bool TraverseDecl(MaybeConst< Decl > *D)
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
VarDecl * getConditionVariable()
Retrieve the variable declared in this "if" statement, if any.
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
bool isTrivial(const Decl *D, const Stmt **OffendingStmt=nullptr) const
Represents a variable declaration or definition.
bool isLocalVarDecl() const
Returns true for local variable declarations other than parameters.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
bool isPtrConversion(const FunctionDecl *F)
std::unique_ptr< PtrRefSafetyModel > makeCheckedPtrSafetyModel()
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
std::optional< bool > isUnsafePtrForStorage(const PtrRefSafetyModel &Model, QualType T, bool IgnoreARC=false)
Applies the memory-management exemptions that hold for a variable, member, or lambda capture (but not...
bool tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj, std::function< bool(const clang::CXXRecordDecl *)> isSafePtr, std::function< bool(const clang::QualType)> isSafePtrType, std::function< bool(const clang::Decl *)> isSafeGlobalDecl, std::function< bool(const clang::Expr *, bool)> callback)
This function de-facto defines a set of transformations that we consider safe (in heuristical sense).
const FunctionProtoType * T
bool isSmartPtrClass(const std::string &Name)
@ Type
The name was classified as a type.
std::optional< bool > isGetterOfSafePtr(const CXXMethodDecl *M)
void printTypeName(llvm::raw_ostream &Os, const QualType QT)
std::string safeGetName(const T *ASTNode)
bool isNullPtr(const clang::Expr *E)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
std::unique_ptr< PtrRefSafetyModel > makeRefPtrSafetyModel()
std::unique_ptr< PtrRefSafetyModel > makeRetainPtrSafetyModel()
bool isConstOwnerPtrMemberExpr(const clang::Expr *E)