[clang] [analyzer] Add std::any checker (PR #76580)

Balazs Benics via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 29 12:19:53 PST 2023


================
@@ -0,0 +1,201 @@
+//===- StdAnyChecker.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
+//
+//===----------------------------------------------------------------------===//
+
+#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/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include "TaggedUnionModeling.h"
+
+using namespace clang;
+using namespace ento;
+using namespace tagged_union_modeling;
+
+REGISTER_MAP_WITH_PROGRAMSTATE(AnyHeldTypeMap, const MemRegion *, QualType)
+
+class StdAnyChecker : public Checker<eval::Call, check::RegionChanges> {
+  CallDescription AnyConstructor{{"std", "any", "any"}};
+  CallDescription AnyAsOp{{"std", "any", "operator="}};
+  CallDescription AnyReset{{"std", "any", "reset"}, 0, 0};
+  CallDescription AnyCast{{"std", "any_cast"}, 1, 1};
+
+  BugType BadAnyType{this, "BadAnyType", "BadAnyType"};
+  BugType NullAnyType{this, "NullAnyType", "NullAnyType"};
+
+public:
+  ProgramStateRef
+  checkRegionChanges(ProgramStateRef State,
+                     const InvalidatedSymbols *Invalidated,
+                     ArrayRef<const MemRegion *> ExplicitRegions,
+                     ArrayRef<const MemRegion *> Regions,
+                     const LocationContext *LCtx, const CallEvent *Call) const {
+    if (!Call)
+      return State;
+
+    return removeInformationStoredForDeadInstances<AnyHeldTypeMap>(*Call, State,
+                                                                   Regions);
+  }
+
+  bool evalCall(const CallEvent &Call, CheckerContext &C) const {
+    // Do not take implementation details into consideration
+    if (Call.isCalledFromSystemHeader())
+      return false;
+
+    if (AnyCast.matches(Call))
+      return handleAnyCastCall(Call, C);
+
+    if (AnyReset.matches(Call)) {
+      const auto *AsMemberCall = dyn_cast<CXXMemberCall>(&Call);
+      if (!AsMemberCall)
+        return false;
+
+      const auto *ThisMemRegion = AsMemberCall->getCXXThisVal().getAsRegion();
+      if (!ThisMemRegion)
+        return false;
+
+      setNullTypeAny(ThisMemRegion, C);
+      return true;
----------------
steakhal wrote:

This is probably a rare case when I'd prefer nesting ifs, or rather hoist this into a handler function and handle the "reset" call there. I'd prefer similar handlers for the rest of the APIs too.

https://github.com/llvm/llvm-project/pull/76580


More information about the cfe-commits mailing list