Author: george.karpenkov Date: Fri Feb 8 13:09:00 2019 New Revision: 353566
URL: http://llvm.org/viewvc/llvm-project?rev=353566&view=rev Log: [analyzer] Opt-in C Style Cast Checker for OSObject pointers Differential Revision: https://reviews.llvm.org/D57261 Added: cfe/trunk/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp cfe/trunk/test/Analysis/osobjectcstylecastchecker_test.cpp Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Modified: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td?rev=353566&r1=353565&r2=353566&view=diff ============================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td (original) +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td Fri Feb 8 13:09:00 2019 @@ -812,6 +812,14 @@ def GCDAntipattern : Checker<"GCDAntipat Documentation<NotDocumented>; } // end "optin.performance" +let ParentPackage = OSXOptIn in { + +def OSObjectCStyleCast : Checker<"OSObjectCStyleCast">, + HelpText<"Checker for C-style casts of OSObjects">, + Documentation<NotDocumented>; + +} // end "optin.osx" + let ParentPackage = CocoaAlpha in { def IvarInvalidationModeling : Checker<"IvarInvalidationModeling">, Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=353566&r1=353565&r2=353566&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Fri Feb 8 13:09:00 2019 @@ -71,6 +71,7 @@ add_clang_library(clangStaticAnalyzerChe ObjCSelfInitChecker.cpp ObjCSuperDeallocChecker.cpp ObjCUnusedIVarsChecker.cpp + OSObjectCStyleCast.cpp PaddingChecker.cpp PointerArithChecker.cpp PointerSubChecker.cpp Added: cfe/trunk/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp?rev=353566&view=auto ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp (added) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp Fri Feb 8 13:09:00 2019 @@ -0,0 +1,90 @@ +//===- OSObjectCStyleCast.cpp ------------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines OSObjectCStyleCast checker, which checks for C-style casts +// of OSObjects. Such casts almost always indicate a code smell, +// as an explicit static or dynamic cast should be used instead. +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "llvm/Support/Debug.h" + +using namespace clang; +using namespace ento; +using namespace ast_matchers; + +namespace { + +const char *WarnAtNode = "OSObjCast"; + +class OSObjectCStyleCastChecker : public Checker<check::ASTCodeBody> { +public: + 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); + + std::string Diagnostics; + llvm::raw_string_ostream OS(Diagnostics); + OS << "C-style cast of OSObject. Use OSDynamicCast instead."; + + BR.EmitBasicReport( + ADC->getDecl(), + Checker, + /*Name=*/"OSObject C-Style Cast", + /*Category=*/"Security", + OS.str(), + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), ADC), + CE->getSourceRange()); +} + +static auto hasTypePointingTo(DeclarationMatcher DeclM) + -> decltype(hasType(pointerType())) { + return hasType(pointerType(pointee(hasDeclaration(DeclM)))); +} + +void OSObjectCStyleCastChecker::checkASTCodeBody(const Decl *D, AnalysisManager &AM, + BugReporter &BR) const { + + AnalysisDeclContext *ADC = AM.getAnalysisDeclContext(D); + + auto DynamicCastM = callExpr(callee(functionDecl(hasName("safeMetaCast")))); + + auto OSObjTypeM = hasTypePointingTo(cxxRecordDecl(isDerivedFrom("OSMetaClassBase"))); + auto OSObjSubclassM = hasTypePointingTo( + cxxRecordDecl(isDerivedFrom("OSObject"))); + + auto CastM = cStyleCastExpr( + allOf(hasSourceExpression(allOf(OSObjTypeM, unless(DynamicCastM))), + OSObjSubclassM)).bind(WarnAtNode); + + auto Matches = match(stmt(forEachDescendant(CastM)), *D->getBody(), AM.getASTContext()); + for (BoundNodes Match : Matches) + emitDiagnostics(Match, BR, ADC, this); +} +} + +void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) { + Mgr.registerChecker<OSObjectCStyleCastChecker>(); +} + +bool ento::shouldRegisterOSObjectCStyleCast(const LangOptions &LO) { + return true; +} Added: cfe/trunk/test/Analysis/osobjectcstylecastchecker_test.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/osobjectcstylecastchecker_test.cpp?rev=353566&view=auto ============================================================================== --- cfe/trunk/test/Analysis/osobjectcstylecastchecker_test.cpp (added) +++ cfe/trunk/test/Analysis/osobjectcstylecastchecker_test.cpp Fri Feb 8 13:09:00 2019 @@ -0,0 +1,39 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=optin.osx.OSObjectCStyleCast %s -verify +#include "os_object_base.h" + +struct OSArray : public OSObject { + unsigned getCount(); +}; + +struct A { + int x; +}; +struct B : public A { + unsigned getCount(); +}; + +unsigned warn_on_explicit_downcast(OSObject * obj) { + OSArray *a = (OSArray *) obj; // expected-warning{{C-style cast of OSObject. Use OSDynamicCast instead}} + return a->getCount(); +} + +void no_warn_on_upcast(OSArray *arr) { + OSObject *obj = (OSObject *) arr; + obj->retain(); + obj->release(); +} + +unsigned no_warn_on_dynamic_cast(OSObject *obj) { + OSArray *a = OSDynamicCast(OSArray, obj); + return a->getCount(); +} + +unsigned long no_warn_on_primitive_conversion(OSArray *arr) { + return (unsigned long) arr; +} + +unsigned no_warn_on_other_type_cast(A *a) { + B *b = (B *) a; + return b->getCount(); +} + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits