-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Introduce a new WebKit checker for a unchecked call arguments (#113708) #114522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
//=======- UncountedCallArgsChecker.cpp --------------------------*- C++ -*-==// | ||
//=======- RawPtrRefCallArgsChecker.cpp --------------------------*- C++ -*-==// | ||
// | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to have documentation for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so. I could imagine |
||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
|
@@ -27,16 +27,20 @@ using namespace ento; | |
|
||
namespace { | ||
|
||
class UncountedCallArgsChecker | ||
class RawPtrRefCallArgsChecker | ||
: public Checker<check::ASTDecl<TranslationUnitDecl>> { | ||
BugType Bug{this, | ||
"Uncounted call argument for a raw pointer/reference parameter", | ||
"WebKit coding guidelines"}; | ||
BugType Bug; | ||
mutable BugReporter *BR; | ||
|
||
TrivialFunctionAnalysis TFA; | ||
|
||
public: | ||
RawPtrRefCallArgsChecker(const char *description) | ||
: Bug(this, description, "WebKit coding guidelines") {} | ||
|
||
virtual std::optional<bool> isUnsafeType(QualType) const = 0; | ||
virtual std::optional<bool> isUnsafePtr(QualType) const = 0; | ||
virtual const char *ptrKind() const = 0; | ||
|
||
void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, | ||
BugReporter &BRArg) const { | ||
|
@@ -48,10 +52,10 @@ class UncountedCallArgsChecker | |
struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> { | ||
using Base = RecursiveASTVisitor<LocalVisitor>; | ||
|
||
const UncountedCallArgsChecker *Checker; | ||
const RawPtrRefCallArgsChecker *Checker; | ||
Decl *DeclWithIssue{nullptr}; | ||
|
||
explicit LocalVisitor(const UncountedCallArgsChecker *Checker) | ||
explicit LocalVisitor(const RawPtrRefCallArgsChecker *Checker) | ||
: Checker(Checker) { | ||
assert(Checker); | ||
} | ||
|
@@ -89,7 +93,8 @@ class UncountedCallArgsChecker | |
if (auto *F = CE->getDirectCallee()) { | ||
// Skip the first argument for overloaded member operators (e. g. lambda | ||
// or std::function call operator). | ||
unsigned ArgIdx = isa<CXXOperatorCallExpr>(CE) && isa_and_nonnull<CXXMethodDecl>(F); | ||
unsigned ArgIdx = | ||
isa<CXXOperatorCallExpr>(CE) && isa_and_nonnull<CXXMethodDecl>(F); | ||
|
||
if (auto *MemberCallExpr = dyn_cast<CXXMemberCallExpr>(CE)) { | ||
if (auto *MD = MemberCallExpr->getMethodDecl()) { | ||
|
@@ -102,8 +107,8 @@ class UncountedCallArgsChecker | |
} | ||
auto *E = MemberCallExpr->getImplicitObjectArgument(); | ||
QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType(); | ||
std::optional<bool> IsUncounted = isUncounted(ArgType); | ||
if (IsUncounted && *IsUncounted && !isPtrOriginSafe(E)) | ||
std::optional<bool> IsUnsafe = isUnsafeType(ArgType); | ||
if (IsUnsafe && *IsUnsafe && !isPtrOriginSafe(E)) | ||
reportBugOnThis(E, D); | ||
} | ||
|
||
|
@@ -119,7 +124,7 @@ class UncountedCallArgsChecker | |
|
||
QualType ArgType = (*P)->getType().getCanonicalType(); | ||
// FIXME: more complex types (arrays, references to raw pointers, etc) | ||
std::optional<bool> IsUncounted = isUncountedPtr(ArgType); | ||
std::optional<bool> IsUncounted = isUnsafePtr(ArgType); | ||
if (!IsUncounted || !(*IsUncounted)) | ||
continue; | ||
|
||
|
@@ -265,7 +270,7 @@ class UncountedCallArgsChecker | |
Os << " for parameter "; | ||
printQuotedQualifiedName(Os, Param); | ||
} | ||
Os << " is uncounted and unsafe."; | ||
Os << " is " << ptrKind() << " and unsafe."; | ||
|
||
const SourceLocation SrcLocToReport = | ||
isa<CXXDefaultArgExpr>(CallArg) ? Param->getDefaultArg()->getExprLoc() | ||
|
@@ -283,15 +288,53 @@ class UncountedCallArgsChecker | |
|
||
const SourceLocation SrcLocToReport = CallArg->getSourceRange().getBegin(); | ||
|
||
SmallString<100> Buf; | ||
llvm::raw_svector_ostream Os(Buf); | ||
Os << "Call argument for 'this' parameter is " << ptrKind(); | ||
Os << " and unsafe."; | ||
|
||
PathDiagnosticLocation BSLoc(SrcLocToReport, BR->getSourceManager()); | ||
auto Report = std::make_unique<BasicBugReport>( | ||
Bug, "Call argument for 'this' parameter is uncounted and unsafe.", | ||
BSLoc); | ||
auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc); | ||
Report->addRange(CallArg->getSourceRange()); | ||
Report->setDeclWithIssue(DeclWithIssue); | ||
BR->emitReport(std::move(Report)); | ||
} | ||
}; | ||
|
||
class UncountedCallArgsChecker final : public RawPtrRefCallArgsChecker { | ||
public: | ||
UncountedCallArgsChecker() | ||
: RawPtrRefCallArgsChecker("Uncounted call argument for a raw " | ||
"pointer/reference parameter") {} | ||
|
||
std::optional<bool> isUnsafeType(QualType QT) const final { | ||
return isUncounted(QT); | ||
} | ||
|
||
std::optional<bool> isUnsafePtr(QualType QT) const final { | ||
return isUncountedPtr(QT); | ||
} | ||
|
||
const char *ptrKind() const final { return "uncounted"; } | ||
}; | ||
|
||
class UncheckedCallArgsChecker final : public RawPtrRefCallArgsChecker { | ||
public: | ||
UncheckedCallArgsChecker() | ||
: RawPtrRefCallArgsChecker("Unchecked call argument for a raw " | ||
"pointer/reference parameter") {} | ||
|
||
std::optional<bool> isUnsafeType(QualType QT) const final { | ||
return isUnchecked(QT); | ||
} | ||
|
||
std::optional<bool> isUnsafePtr(QualType QT) const final { | ||
return isUncheckedPtr(QT); | ||
} | ||
|
||
const char *ptrKind() const final { return "unchecked"; } | ||
}; | ||
|
||
} // namespace | ||
|
||
void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) { | ||
|
@@ -301,3 +344,11 @@ void ento::registerUncountedCallArgsChecker(CheckerManager &Mgr) { | |
bool ento::shouldRegisterUncountedCallArgsChecker(const CheckerManager &) { | ||
return true; | ||
} | ||
|
||
void ento::registerUncheckedCallArgsChecker(CheckerManager &Mgr) { | ||
Mgr.registerChecker<UncheckedCallArgsChecker>(); | ||
} | ||
|
||
bool ento::shouldRegisterUncheckedCallArgsChecker(const CheckerManager &) { | ||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't seem to find a reference to this overload of
isUnchecked
. Do you see a use of it in future?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UncheckedCallArgsChecker::isUnsafeType
calls it.