[clang] [analyzer] Add std::variant checker (PR #66481)

via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 15 07:00:40 PDT 2023


================
@@ -0,0 +1,128 @@
+//===- TaggedUnionModeling.h -------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKER_VARIANTLIKETYPEMODELING_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKER_VARIANTLIKETYPEMODELING_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/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/FoldingSet.h"
+#include <numeric>
+
+namespace clang {
+namespace ento {
+namespace variant_modeling {
+
+// The implementation of all these functions can be found in the
+// StdVariantChecker.cpp file under the same directory as this file.
+CallEventRef<> getCaller(const CallEvent &Call, CheckerContext &C);
+const TemplateArgument &getFirstTemplateArgument(const CallEvent &Call);
+bool isCopyConstructorCall(const CallEvent &Call);
+bool isCopyAssignmentCall(const CallEvent &Call);
+bool isMoveAssignmentCall(const CallEvent &Call);
+bool isMoveConstructorCall(const CallEvent &Call);
+bool isStdType(const Type *Type, const std::string &TypeName);
+bool isStdVariant(const Type *Type);
+bool calledFromSystemHeader(const CallEvent &Call, CheckerContext &C);
+
+// When invalidating regions we also have to follow that with our data
+// storages in the program state.
+template <class TypeMap>
+ProgramStateRef
+removeInformationStoredForDeadInstances(const CallEvent *Call,
+                                        ProgramStateRef State,
+                                        ArrayRef<const MemRegion *> Regions) {
+  // If we do not know anything about the call we shall not continue.
+  if (!Call) {
+    return State;
+  }
+
+  // If the call is coming from a system header it is implementation detail.
+  // We should not take it into consideration.
+  if (Call->isInSystemHeader()) {
+    return State;
+  }
+
+  // Remove the information we know about the invalidate region.
+  // It is not relevant anymore.
+  State = std::accumulate(
+      Regions.begin(), Regions.end(), State,
+      [](ProgramStateRef State, const MemRegion *CurrentMemRegion) {
+        if (State->contains<TypeMap>(CurrentMemRegion)) {
+          State = State->remove<TypeMap>(CurrentMemRegion);
+        }
+        return State;
+      });
+  return State;
+}
+
+template <class TypeMap>
+void handleConstructorAndAssignment(const CallEvent &Call, CheckerContext &C,
+                                    const SVal &ThisSVal) {
+  ProgramStateRef State = Call.getState();
+
+  auto ArgSVal = Call.getArgSVal(0);
+  const auto *ThisRegion = ThisSVal.getAsRegion();
+  const auto *ArgMemRegion = ArgSVal.getAsRegion();
+
+  // Make changes to the state according to type of constructor/assignment
+  State = [&]() {
+    bool IsCopy = isCopyConstructorCall(Call) || isCopyAssignmentCall(Call);
+    bool IsMove = isMoveConstructorCall(Call) || isMoveAssignmentCall(Call);
+
+    // First we handle copy and move operations
+    if (IsCopy || IsMove) {
+      // If the argument of a copy constructor or assignment is unknown then
+      // we will not know the argument of the copied to object.
+      bool OtherQTypeKnown = State->contains<TypeMap>(ArgMemRegion);
+
+      const QualType *OtherQType;
+      if (OtherQTypeKnown) {
+        OtherQType = State->get<TypeMap>(ArgMemRegion);
+      } else {
+        return State->contains<TypeMap>(ThisRegion)
+                   ? State->remove<TypeMap>(ThisRegion)
+                   : State;
+      }
+
+      // When move semantics is used we can only know that the moved from
+      // object must be in a destructible state. Other usage of the object
+      // than destruction is undefined.
+      if (IsMove) {
+        State = State->contains<TypeMap>(ArgMemRegion)
+                    ? State->remove<TypeMap>(ArgMemRegion)
+                    : State;
+      }
+      return State->set<TypeMap>(ThisRegion, *OtherQType);
+    }
+    // Then the other constructor/assignment where the argument is the new
+    // object held by the std::variant or std::any
----------------
DonatNagyE wrote:

Perhaps include the signature of the referenced constructors / assignment operators (here and above) for the sake of lazy readers like me :)

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


More information about the cfe-commits mailing list