[analyzer] OSObjectCStyleCast: Improve warning message.

Suggest OSRequiredCast as a closer alternative to C-style cast.
Explain how to decide.
This commit is contained in:
Artem Dergachev 2020-11-21 01:41:31 -08:00
parent 3696227c10
commit 8c5ca7c6e6
2 changed files with 13 additions and 10 deletions

View File

@ -24,32 +24,36 @@ using namespace ento;
using namespace ast_matchers;
namespace {
const char *WarnAtNode = "OSObjCast";
static constexpr const char *const WarnAtNode = "WarnAtNode";
static constexpr const char *const WarnRecordDecl = "WarnRecordDecl";
class OSObjectCStyleCastChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D,
AnalysisManager &AM,
void checkASTCodeBody(const Decl *D, AnalysisManager &AM,
BugReporter &BR) const;
};
}
static void emitDiagnostics(const BoundNodes &Nodes,
BugReporter &BR,
AnalysisDeclContext *ADC,
const OSObjectCStyleCastChecker *Checker) {
const auto *CE = Nodes.getNodeAs<CastExpr>(WarnAtNode);
assert(CE);
const CXXRecordDecl *RD = Nodes.getNodeAs<CXXRecordDecl>(WarnRecordDecl);
assert(CE && RD);
std::string Diagnostics;
llvm::raw_string_ostream OS(Diagnostics);
OS << "C-style cast of OSObject. Use OSDynamicCast instead.";
OS << "C-style cast of an OSObject is prone to type confusion attacks; "
<< "use 'OSRequiredCast' if the object is definitely of type '"
<< RD->getNameAsString() << "', or 'OSDynamicCast' followed by "
<< "a null check if unsure",
BR.EmitBasicReport(
ADC->getDecl(),
Checker,
/*Name=*/"OSObject C-Style Cast",
/*BugCategory=*/"Security",
categories::SecurityError,
OS.str(),
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC),
CE->getSourceRange());
@ -68,7 +72,7 @@ void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager
auto OSObjTypeM = hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase")));
auto OSObjSubclassM = hasTypePointingTo(
cxxRecordDecl(isDerivedFrom("OSObject")));
cxxRecordDecl(isDerivedFrom("OSObject")).bind(WarnRecordDecl));
auto CastM = cStyleCastExpr(
allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))),
@ -78,7 +82,6 @@ void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager
for (BoundNodes Match : Matches)
emitDiagnostics(Match, BR, ADC, this);
}
}
void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) {
Mgr.registerChecker<OSObjectCStyleCastChecker>();

View File

@ -13,7 +13,7 @@ struct B : public A {
};
unsigned warn_on_explicit_downcast(OSObject * obj) {
OSArray *a = (OSArray *) obj; // expected-warning{{C-style cast of OSObject. Use OSDynamicCast instead}}
OSArray *a = (OSArray *) obj; // expected-warning{{C-style cast of an OSObject is prone to type confusion attacks; use 'OSRequiredCast' if the object is definitely of type 'OSArray', or 'OSDynamicCast' followed by a null check if unsure}}
return a->getCount();
}