31bool isRefcountedStringsHack(
const VarDecl *
V) {
33 auto safeClass = [](
const std::string &className) {
34 return className ==
"String" || className ==
"AtomString" ||
35 className ==
"UniquedString" || className ==
"Identifier";
39 if (
auto *CXXRD = T->getAsCXXRecordDecl()) {
43 if (T->isPointerType() || T->isReferenceType()) {
44 if (
auto *CXXRD = T->getPointeeCXXRecordDecl()) {
53 const VarDecl *Guardian{
nullptr};
55 explicit GuardianVisitor(
const VarDecl *Guardian) : Guardian(Guardian) {
59 bool VisitBinaryOperator(BinaryOperator *BO)
override {
61 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
62 if (VarRef->getDecl() == Guardian)
69 bool VisitCXXConstructExpr(CXXConstructExpr *CE)
override {
73 unsigned ArgIndex = 0;
75 ParmVarDecl *Parm =
nullptr;
76 if (ArgIndex < Ctor->getNumParams())
77 Parm = Ctor->getParamDecl(ArgIndex);
78 if (mutatesGuardian(Arg, Parm))
85 bool VisitCallExpr(CallExpr *CE)
override {
91 unsigned ArgIndex = 0;
94 ParmVarDecl *Parm =
nullptr;
95 if (ArgIndex >= ArgOffset) {
96 unsigned ParmIndex = ArgIndex - ArgOffset;
97 if (ParmIndex < Callee->getNumParams())
98 Parm =
Callee->getParamDecl(ParmIndex);
100 if (mutatesGuardian(Arg, Parm))
107 bool VisitCXXMemberCallExpr(CXXMemberCallExpr *MCE)
override {
110 if (ObjType.isConstQualified())
113 if (
auto *VarRef = dyn_cast<DeclRefExpr>(ThisArg)) {
121 bool mutatesGuardian(
const Expr *Arg,
const ParmVarDecl *ParmDecl) {
123 if (
auto *VarRef = dyn_cast<DeclRefExpr>(Arg)) {
124 if (VarRef->getDecl() == Guardian) {
126 if (!ArgType.isConstQualified())
134bool isGuardedScopeEmbeddedInGuardianScope(
const VarDecl *Guarded,
135 const VarDecl *MaybeGuardian) {
137 assert(MaybeGuardian);
142 const CompoundStmt *guardiansClosestCompStmtAncestor =
nullptr;
147 !guardianAncestors.
empty();
152 for (
auto &guardianAncestor : guardianAncestors) {
153 if (
auto *CStmtParentAncestor = guardianAncestor.get<
CompoundStmt>()) {
154 guardiansClosestCompStmtAncestor = CStmtParentAncestor;
158 if (guardiansClosestCompStmtAncestor)
162 if (!guardiansClosestCompStmtAncestor)
169 !guardedVarAncestors.
empty();
174 for (
auto &guardedVarAncestor : guardedVarAncestors) {
175 if (
auto *CStmtAncestor = guardedVarAncestor.get<
CompoundStmt>()) {
176 if (!FirstCompondStmt) {
177 FirstCompondStmt = CStmtAncestor;
180 if (CStmtAncestor == guardiansClosestCompStmtAncestor) {
181 GuardianVisitor guardianVisitor(MaybeGuardian);
182 auto *GuardedScope =
const_cast<CompoundStmt *
>(FirstCompondStmt);
183 return guardianVisitor.TraverseCompoundStmt(GuardedScope);
192class RawPtrRefLocalVarsChecker
193 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
195 EnsureFunctionAnalysis EFA;
198 mutable BugReporter *BR;
199 mutable std::optional<RetainTypeChecker> RTC;
202 RawPtrRefLocalVarsChecker(
const char *description)
203 : Bug(this, description,
"WebKit coding guidelines") {}
205 virtual std::optional<bool> isUnsafePtr(
const QualType T)
const = 0;
206 virtual bool isSafePtr(
const CXXRecordDecl *)
const = 0;
207 virtual bool isSafePtrType(
const QualType)
const = 0;
208 virtual bool isSafeExpr(
const Expr *)
const {
return false; }
209 virtual bool isSafeDecl(
const Decl *)
const {
return false; }
210 virtual const char *ptrKind()
const = 0;
212 void checkASTDecl(
const TranslationUnitDecl *TUD, AnalysisManager &MGR,
213 BugReporter &BRArg)
const {
220 const RawPtrRefLocalVarsChecker *Checker;
221 Decl *DeclWithIssue{
nullptr};
223 TrivialFunctionAnalysis TFA;
225 explicit LocalVisitor(
const RawPtrRefLocalVarsChecker *Checker)
228 ShouldVisitTemplateInstantiations =
true;
229 ShouldVisitImplicitCode =
false;
232 bool TraverseDecl(Decl *D)
override {
233 llvm::SaveAndRestore SavedDecl(DeclWithIssue);
239 bool VisitTypedefDecl(TypedefDecl *TD)
override {
241 Checker->RTC->visitTypedef(TD);
245 bool VisitVarDecl(VarDecl *
V)
override {
246 auto *
Init =
V->getInit();
247 if (
V->isLocalVarDecl())
248 Checker->visitVarDecl(
V,
Init, DeclWithIssue);
252 bool VisitBinaryOperator(BinaryOperator *BO)
override {
254 if (
auto *VarRef = dyn_cast<DeclRefExpr>(BO->
getLHS())) {
255 if (
auto *
V = dyn_cast<VarDecl>(VarRef->getDecl()))
256 Checker->visitVarDecl(
V, BO->
getRHS(), DeclWithIssue);
262 bool TraverseIfStmt(IfStmt *IS)
override {
272 return DynamicRecursiveASTVisitor::TraverseIfStmt(IS);
276 bool TraverseForStmt(ForStmt *FS)
override {
278 return DynamicRecursiveASTVisitor::TraverseForStmt(FS);
282 bool TraverseCXXForRangeStmt(CXXForRangeStmt *FRS)
override {
284 return DynamicRecursiveASTVisitor::TraverseCXXForRangeStmt(FRS);
288 bool TraverseWhileStmt(WhileStmt *WS)
override {
290 return DynamicRecursiveASTVisitor::TraverseWhileStmt(WS);
296 return DynamicRecursiveASTVisitor::TraverseCompoundStmt(CS);
300 bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl)
override {
303 return DynamicRecursiveASTVisitor::TraverseClassTemplateDecl(Decl);
307 LocalVisitor visitor(
this);
309 RTC->visitTranslationUnitDecl(TUD);
310 visitor.TraverseDecl(
const_cast<TranslationUnitDecl *
>(TUD));
313 void visitVarDecl(
const VarDecl *
V,
const Expr *
Value,
314 const Decl *DeclWithIssue)
const {
315 if (shouldSkipVarDecl(
V))
318 if (
auto *DD = dyn_cast<DecompositionDecl>(
V)) {
319 for (
auto *BD : DD->bindings()) {
320 auto *Binding = BD->getBinding();
323 std::optional<bool> IsUncountedPtr = isUnsafePtr(Binding->getType());
324 if (!IsUncountedPtr || !*IsUncountedPtr)
326 reportBug(
V,
nullptr, BD, DeclWithIssue);
330 std::optional<bool> IsUncountedPtr = isUnsafePtr(
V->getType());
331 if (IsUncountedPtr && *IsUncountedPtr) {
332 if (
Value && isPtrOriginSafe(
V,
Value, DeclWithIssue))
334 reportBug(
V,
Value,
nullptr, DeclWithIssue);
338 bool isPtrOriginSafe(
const VarDecl *
V,
const Expr *
Value,
339 const Decl *DeclWithIssue)
const {
343 [&](
const clang::QualType
Type) {
return isSafePtrType(
Type); },
344 [&](
const clang::Decl *D) {
return isSafeDecl(D); },
345 [&](
const clang::Expr *InitArgOrigin,
bool IsSafe) {
346 if (!InitArgOrigin || IsSafe)
361 if (EFA.isACallToEnsureFn(InitArgOrigin))
364 if (isSafeExpr(InitArgOrigin))
367 if (
auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
368 if (
auto *MaybeGuardian =
369 dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
370 const auto *MaybeGuardianArgType =
372 if (MaybeGuardianArgType) {
373 const CXXRecordDecl *
const MaybeGuardianArgCXXRecord =
374 MaybeGuardianArgType->getAsCXXRecordDecl();
375 if (MaybeGuardianArgCXXRecord) {
378 isRefcountedStringsHack(MaybeGuardian)) &&
379 isGuardedScopeEmbeddedInGuardianScope(
V, MaybeGuardian))
385 if (
auto *FD = dyn_cast<FunctionDecl>(DeclWithIssue)) {
386 if (GuardianVisitor{MaybeGuardian}.TraverseStmt(
390 if (
auto *MD = dyn_cast<ObjCMethodDecl>(DeclWithIssue)) {
391 if (GuardianVisitor{MaybeGuardian}.TraverseStmt(
403 bool shouldSkipVarDecl(
const VarDecl *
V)
const {
407 return BR->getSourceManager().isInSystemHeader(
V->getLocation());
410 void reportBug(
const VarDecl *
V,
const Expr *
Value,
const Decl *BindingDecl,
411 const Decl *DeclWithIssue)
const {
413 SmallString<100> Buf;
414 llvm::raw_svector_ostream Os(Buf);
417 Os <<
"Assignment to an " << ptrKind() <<
" parameter ";
421 PathDiagnosticLocation BSLoc(
Value->getExprLoc(), BR->getSourceManager());
422 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
424 BR->emitReport(std::move(
Report));
426 if (
V->hasLocalStorage())
427 Os <<
"Local variable ";
428 else if (
V->isStaticLocal())
429 Os <<
"Static local variable ";
430 else if (
V->hasGlobalStorage())
431 Os <<
"Global variable ";
438 Os <<
" is " << ptrKind() <<
" and unsafe.";
440 PathDiagnosticLocation BSLoc(
V->getLocation(), BR->getSourceManager());
441 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
442 Report->addRange(
V->getSourceRange());
443 Report->setDeclWithIssue(DeclWithIssue);
444 BR->emitReport(std::move(
Report));
449class UncountedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
451 UncountedLocalVarsChecker()
452 : RawPtrRefLocalVarsChecker(
"Uncounted raw pointer or reference not "
453 "provably backed by ref-counted variable") {}
454 std::optional<bool> isUnsafePtr(
const QualType T)
const final {
460 bool isSafePtrType(
const QualType
type)
const final {
463 const char *ptrKind() const final {
return "uncounted"; }
466class UncheckedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
468 UncheckedLocalVarsChecker()
469 : RawPtrRefLocalVarsChecker(
"Unchecked raw pointer or reference not "
470 "provably backed by checked variable") {}
471 std::optional<bool> isUnsafePtr(
const QualType T)
const final {
477 bool isSafePtrType(
const QualType
type)
const final {
480 bool isSafeExpr(
const Expr *E)
const final {
483 const char *ptrKind() const final {
return "unchecked"; }
486class UnretainedLocalVarsChecker final :
public RawPtrRefLocalVarsChecker {
488 UnretainedLocalVarsChecker()
489 : RawPtrRefLocalVarsChecker(
"Unretained raw pointer or reference not "
490 "provably backed by a RetainPtr") {
491 RTC = RetainTypeChecker();
493 std::optional<bool> isUnsafePtr(
const QualType T)
const final {
494 if (T.hasStrongOrWeakObjCLifetime())
496 return RTC->isUnretained(T);
501 bool isSafePtrType(
const QualType
type)
const final {
504 bool isSafeExpr(
const Expr *E)
const final {
508 bool isSafeDecl(
const Decl *D)
const final {
512 const char *ptrKind() const final {
return "unretained"; }
517void ento::registerUncountedLocalVarsChecker(
CheckerManager &Mgr) {
521bool ento::shouldRegisterUncountedLocalVarsChecker(
const CheckerManager &) {
525void ento::registerUncheckedLocalVarsChecker(
CheckerManager &Mgr) {
529bool ento::shouldRegisterUncheckedLocalVarsChecker(
const CheckerManager &) {
533void ento::registerUnretainedLocalVarsChecker(
CheckerManager &Mgr) {
537bool 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
SourceLocation getLocation() const
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 isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
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.
const SourceManager & getSourceManager()
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.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
bool isCocoaObjectRef(QualType T)
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.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
bool isExprToGetCheckedPtrCapableMember(const clang::Expr *E)
bool isPtrConversion(const FunctionDecl *F)
bool isRefOrCheckedPtrType(const clang::QualType T)
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
bool isRetainPtrOrOSPtrType(const clang::QualType T)
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).
bool isSmartPtrClass(const std::string &Name)
bool isRefCounted(const CXXRecordDecl *R)
@ Type
The name was classified as a type.
bool isRetainPtrOrOSPtr(const std::string &Name)
std::optional< bool > isUncountedPtr(const QualType T)
bool isSafePtr(clang::CXXRecordDecl *Decl)
std::string safeGetName(const T *ASTNode)
bool isNullPtr(const clang::Expr *E)
bool isCheckedPtr(const std::string &Name)
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
bool isConstOwnerPtrMemberExpr(const clang::Expr *E)
std::optional< bool > isUncheckedPtr(const QualType T)