diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp')
-rw-r--r-- | contrib/libs/clang16/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/contrib/libs/clang16/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/contrib/libs/clang16/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp new file mode 100644 index 0000000000..04e7f8dec8 --- /dev/null +++ b/contrib/libs/clang16/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -0,0 +1,181 @@ +// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- 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 defines MacOSXAPIChecker, which is an assortment of checks on calls +// to various, widely used Apple APIs. +// +// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated +// to here, using the new Checker interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Attr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace ento; + +namespace { +class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > { + mutable std::unique_ptr<BugType> BT_dispatchOnce; + + static const ObjCIvarRegion *getParentIvarRegion(const MemRegion *R); + +public: + void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + + void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, + StringRef FName) const; + + typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &, + const CallExpr *, + StringRef FName) const; +}; +} //end anonymous namespace + +//===----------------------------------------------------------------------===// +// dispatch_once and dispatch_once_f +//===----------------------------------------------------------------------===// + +const ObjCIvarRegion * +MacOSXAPIChecker::getParentIvarRegion(const MemRegion *R) { + const SubRegion *SR = dyn_cast<SubRegion>(R); + while (SR) { + if (const ObjCIvarRegion *IR = dyn_cast<ObjCIvarRegion>(SR)) + return IR; + SR = dyn_cast<SubRegion>(SR->getSuperRegion()); + } + return nullptr; +} + +void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, + StringRef FName) const { + if (CE->getNumArgs() < 1) + return; + + // Check if the first argument is improperly allocated. If so, issue a + // warning because that's likely to be bad news. + const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion(); + if (!R) + return; + + // Global variables are fine. + const MemRegion *RB = R->getBaseRegion(); + const MemSpaceRegion *RS = RB->getMemorySpace(); + if (isa<GlobalsSpaceRegion>(RS)) + return; + + // Handle _dispatch_once. In some versions of the OS X SDK we have the case + // that dispatch_once is a macro that wraps a call to _dispatch_once. + // _dispatch_once is then a function which then calls the real dispatch_once. + // Users do not care; they just want the warning at the top-level call. + if (CE->getBeginLoc().isMacroID()) { + StringRef TrimmedFName = FName.ltrim('_'); + if (TrimmedFName != FName) + FName = TrimmedFName; + } + + SmallString<256> S; + llvm::raw_svector_ostream os(S); + bool SuggestStatic = false; + os << "Call to '" << FName << "' uses"; + if (const VarRegion *VR = dyn_cast<VarRegion>(RB)) { + const VarDecl *VD = VR->getDecl(); + // FIXME: These should have correct memory space and thus should be filtered + // out earlier. This branch only fires when we're looking from a block, + // which we analyze as a top-level declaration, onto a static local + // in a function that contains the block. + if (VD->isStaticLocal()) + return; + // We filtered out globals earlier, so it must be a local variable + // or a block variable which is under UnknownSpaceRegion. + if (VR != R) + os << " memory within"; + if (VD->hasAttr<BlocksAttr>()) + os << " the block variable '"; + else + os << " the local variable '"; + os << VR->getDecl()->getName() << '\''; + SuggestStatic = true; + } else if (const ObjCIvarRegion *IVR = getParentIvarRegion(R)) { + if (IVR != R) + os << " memory within"; + os << " the instance variable '" << IVR->getDecl()->getName() << '\''; + } else if (isa<HeapSpaceRegion>(RS)) { + os << " heap-allocated memory"; + } else if (isa<UnknownSpaceRegion>(RS)) { + // Presence of an IVar superregion has priority over this branch, because + // ObjC objects are on the heap even if the core doesn't realize this. + // Presence of a block variable base region has priority over this branch, + // because block variables are known to be either on stack or on heap + // (might actually move between the two, hence UnknownSpace). + return; + } else { + os << " stack allocated memory"; + } + os << " for the predicate value. Using such transient memory for " + "the predicate is potentially dangerous."; + if (SuggestStatic) + os << " Perhaps you intended to declare the variable as 'static'?"; + + ExplodedNode *N = C.generateErrorNode(); + if (!N) + return; + + if (!BT_dispatchOnce) + BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'", + "API Misuse (Apple)")); + + auto report = + std::make_unique<PathSensitiveBugReport>(*BT_dispatchOnce, os.str(), N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.emitReport(std::move(report)); +} + +//===----------------------------------------------------------------------===// +// Central dispatch function. +//===----------------------------------------------------------------------===// + +void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, + CheckerContext &C) const { + StringRef Name = C.getCalleeName(CE); + if (Name.empty()) + return; + + SubChecker SC = + llvm::StringSwitch<SubChecker>(Name) + .Cases("dispatch_once", + "_dispatch_once", + "dispatch_once_f", + &MacOSXAPIChecker::CheckDispatchOnce) + .Default(nullptr); + + if (SC) + (this->*SC)(C, CE, Name); +} + +//===----------------------------------------------------------------------===// +// Registration. +//===----------------------------------------------------------------------===// + +void ento::registerMacOSXAPIChecker(CheckerManager &mgr) { + mgr.registerChecker<MacOSXAPIChecker>(); +} + +bool ento::shouldRegisterMacOSXAPIChecker(const CheckerManager &mgr) { + return true; +} |