[clang] [clang][analyzer] Introduce modeling for threading related checkers (PR #109636)
Balazs Benics via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 10 01:04:05 PDT 2024
Endre =?utf-8?q?Fülöp?= <endre.fulop at sigmatechnology.com>,
Endre =?utf-8?q?Fülöp?= <endre.fulop at sigmatechnology.com>,
Endre =?utf-8?q?Fülöp?= <endre.fulop at sigmatechnology.com>,
Endre =?utf-8?q?Fülöp?= <endre.fulop at sigmatechnology.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/109636 at github.com>
================
@@ -0,0 +1,244 @@
+//===--- MutexModelingAPI.h - API for modeling mutexes --------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines inter-checker API for tracking and manipulating the
+// modeled state of locked mutexes in the GDM.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MUTEXMODELINGAPI_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MUTEXMODELINGAPI_H
+
+#include "MutexModelingDomain.h"
+#include "MutexModelingGDM.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace clang {
+
+namespace ento {
+class BugType;
+namespace mutex_modeling {
+
+// Set of registered bug types for mutex modeling
+inline llvm::SmallSet<const BugType *, 0> RegisteredBugTypes{};
+
+// Register a bug type for mutex modeling
+inline void RegisterBugTypeForMutexModeling(const BugType *BT) {
+ RegisteredBugTypes.insert(BT);
+}
+
+// Check if a bug type is registered for mutex modeling
+inline bool IsBugTypeRegisteredForMutexModeling(const BugType *BT) {
+ return RegisteredBugTypes.contains(BT);
+}
+
+// Vector of registered event descriptors
+inline llvm::SmallVector<EventDescriptor, 0> RegisteredEvents{};
+
+// Register an event descriptor
+inline auto RegisterEvent(EventDescriptor Event) {
+ RegisteredEvents.push_back(Event);
+}
+
+// Helper functions to create common types of mutex extractors
+inline auto
+MakeFirstArgExtractor(ArrayRef<StringRef> NameParts, int NumArgsRequired = 1,
+ CallDescription::Mode MatchAs = CDM::CLibrary) {
+ return FirstArgMutexExtractor{
+ CallDescription{MatchAs, NameParts, NumArgsRequired}};
+}
+
+inline auto
+MakeMemberExtractor(ArrayRef<StringRef> NameParts, int NumArgsRequired = 0,
+ CallDescription::Mode MatchAs = CDM::CXXMethod) {
+ return MemberMutexExtractor{
+ CallDescription{MatchAs, NameParts, NumArgsRequired}};
+}
+
+inline auto MakeRAIILockExtractor(StringRef GuardObjectName) {
+ return RAIILockExtractor{GuardObjectName};
+}
+
+inline auto MakeRAIIReleaseExtractor(StringRef GuardObjectName) {
+ return RAIIReleaseExtractor{GuardObjectName};
+}
+
+// Check if any critical sections are currently active
+inline bool AreAnyCritsectionsActive(CheckerContext &C) {
+ return !C.getState()->get<CritSections>().isEmpty();
+}
+
+// Create a note tag for a mutex critical section
+inline const NoteTag *CreateMutexCritSectionNote(CritSectionMarker M,
+ CheckerContext &C) {
+ return C.getNoteTag([M](const PathSensitiveBugReport &BR,
+ llvm::raw_ostream &OS) {
+ if (!IsBugTypeRegisteredForMutexModeling(&BR.getBugType()))
+ return;
+ const auto CritSectionBegins =
+ BR.getErrorNode()->getState()->get<CritSections>();
+ llvm::SmallVector<CritSectionMarker, 4> LocksForMutex;
+ llvm::copy_if(CritSectionBegins, std::back_inserter(LocksForMutex),
+ [M](const auto &Marker) {
+ return Marker.MutexRegion == M.MutexRegion;
+ });
+ if (LocksForMutex.empty())
+ return;
+
+ // As the ImmutableList builds the locks by prepending them, we
+ // reverse the list to get the correct order.
+ std::reverse(LocksForMutex.begin(), LocksForMutex.end());
+
+ // Find the index of the lock expression in the list of all locks for a
+ // given mutex (in acquisition order).
+ const CritSectionMarker *const Position =
+ llvm::find_if(std::as_const(LocksForMutex), [M](const auto &Marker) {
+ return Marker.BeginExpr == M.BeginExpr;
+ });
+ if (Position == LocksForMutex.end())
+ return;
+
+ // If there is only one lock event, we don't need to specify how many times
+ // the critical section was entered.
+ if (LocksForMutex.size() == 1) {
+ OS << "Entering critical section here";
+ return;
+ }
+
+ const auto IndexOfLock =
+ std::distance(std::as_const(LocksForMutex).begin(), Position);
+
+ const auto OrdinalOfLock = IndexOfLock + 1;
+ OS << "Entering critical section for the " << OrdinalOfLock
+ << llvm::getOrdinalSuffix(OrdinalOfLock) << " time here";
+ });
+}
+
+// Print the current state of mutex events, lock states, and destroyed return
+// values
+inline void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep) {
----------------
steakhal wrote:
I'd suggest not having function bodies in API headers. A minimal header helps to understand better what is the intended use without the need to glass over implementation details.
It also helps in parsing times, as the less code is in headers, the better.
This applies to all headers.
https://github.com/llvm/llvm-project/pull/109636
More information about the cfe-commits
mailing list