ASDenysPetrov updated this revision to Diff 392821.
ASDenysPetrov added a comment.

Improved dynamic type recognition. Provided `-fstrict-aliasing` compiler flag 
dependency.
Still has issues with some cases (see it at the bottom of the test file). WIP.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D114718/new/

https://reviews.llvm.org/D114718

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/StrictAliasingChecker.cpp
  clang/test/Analysis/Checkers/StrictAliasingChecker/strict-aliasing.cpp

Index: clang/test/Analysis/Checkers/StrictAliasingChecker/strict-aliasing.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/Checkers/StrictAliasingChecker/strict-aliasing.cpp
@@ -0,0 +1,524 @@
+// RUN: %clang_cc1 -std=c++20 -analyze -analyzer-config eagerly-assume=false -analyzer-checker=debug.ExprInspection,alpha.core.StrictAliasing -verify %s
+// NOTE: -relaxed-aliasing flag disables StrictAliasing checker.
+
+template <typename T>
+void clang_analyzer_dump(T x);
+void clang_analyzer_eval(int);
+
+namespace std {
+enum class byte : unsigned char {};
+enum class OtherByte : unsigned char {};
+}; // namespace std
+enum class EnumInt : int {};
+
+union UnionUchar {
+  unsigned char x;
+  char y;
+};
+union UnionInt {
+  int x;
+};
+class Class {};
+class ClassInt {
+public:
+  int x;
+};
+class Base {
+public:
+  int x;
+};
+struct AnotherBase {
+  int y;
+};
+class Derived : public AnotherBase, public Base {
+  int z;
+};
+class MostDerived : public Derived {
+  int w;
+};
+
+using AliasedStdByte = std::byte;
+using AliasedChar = char;
+using AliasedSChar = const signed char;
+using AliasedInt = int;
+using AliasedUInt = const unsigned int;
+using AliasedULong = unsigned long;
+using AliasedBase = Base;
+using AliasedAnotherBase = AnotherBase;
+
+namespace ns1 {
+
+void int_casts() {
+  using MyInt = int;
+  MyInt x = {};
+  // int to records
+  {
+    auto *ptr = (Class *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (ClassInt *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (UnionUchar *)&x;
+    ptr->x = 42; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (UnionInt *)&x;
+    ptr->x = 42; // expected-warning{{Undefined behavior}}
+  }
+  // int to records
+  {
+    auto *ptr = (std::byte *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (std::OtherByte *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior. Attempting to access the stored value of type}}
+  }
+  {
+    auto *ptr = (EnumInt *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  // int to scalars
+  {
+    auto *ptr = (const char *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (unsigned char *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (signed char *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (short *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned short *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed short *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (int *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (const volatile unsigned int *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (signed int *)&x;
+    *ptr = 24; // no-warning
+  }
+  {
+    auto *ptr = (long *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned long *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed long *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long long *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned long long *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed long long *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (float *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (double *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long double *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  // int to aliases
+  {
+    auto *ptr = (AliasedStdByte *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedChar *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedSChar *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedULong *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedInt *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedUInt *)&x;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedULong *)&x;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+}
+
+void derived_class_casts() {
+  Derived d;
+  // record to records
+  {
+    auto *ptr = (MostDerived *)&d;
+    auto y = ptr->x; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (Derived *)&d;
+    auto y = ptr->x; // no-warning
+  }
+  {
+    auto *ptr = (Base *)&d;
+    auto y = ptr->x; // no-warning
+  }
+  {
+    auto *ptr = (const AnotherBase *)&d;
+    auto y = ptr->y; // no-warning
+  }
+  {
+    auto *ptr = (ClassInt *)&d;
+    auto y = ptr->x; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (Class *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (const ClassInt *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (UnionUchar *)&d;
+    ptr->x = 42; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (UnionInt *)&d;
+    ptr->x = 42; // expected-warning{{Undefined behavior}}
+  }
+  // record to scalars
+  {
+    auto *ptr = (char *)&d;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (const unsigned char *)&d;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (signed char *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (short *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned short *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed short *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (int *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned int *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed int *)&d;
+    *ptr = 24; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned long *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed long *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long long *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned long long *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed long long *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (float *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (double *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long double *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  // record to aliases
+  {
+    auto *ptr = (AliasedStdByte *)&d;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedChar *)&d;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedSChar *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedULong *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedInt *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedUInt *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedULong *)&d;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedBase *)&d;
+    auto y = ptr->x; // no-warning
+  }
+  {
+    auto *ptr = (AliasedAnotherBase *)&d;
+    auto y = (*ptr).y; // no-warning
+  }
+}
+
+void base_class_casts() {
+  Base b;
+  // record to records
+  {
+    auto *ptr = (MostDerived *)&b;
+    auto y = ptr->x; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (Derived *)&b;
+    auto y = ptr->x; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (Base *)&b;
+    auto y = ptr->x; // no-warning
+  }
+  {
+    auto *ptr = (const AnotherBase *)&b;
+    auto y = ptr->y; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (ClassInt *)&b;
+    auto y = ptr->x; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (Class *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (const ClassInt *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (UnionUchar *)&b;
+    ptr->x = 42; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (UnionInt *)&b;
+    ptr->x = 42; // expected-warning{{Undefined behavior}}
+  }
+  // record to scalars
+  {
+    auto *ptr = (char *)&b;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (const unsigned char *)&b;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (signed char *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (short *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned short *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed short *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (int *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned int *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed int *)&b;
+    *ptr = 24; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned long *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed long *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long long *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (unsigned long long *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (signed long long *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (float *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (double *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (long double *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  // record to aliases
+  {
+    auto *ptr = (AliasedStdByte *)&b;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedChar *)&b;
+    auto y = *ptr; // no-warning
+  }
+  {
+    auto *ptr = (AliasedSChar *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedULong *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedInt *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedUInt *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedULong *)&b;
+    auto y = *ptr; // expected-warning{{Undefined behavior}}
+  }
+  {
+    auto *ptr = (AliasedBase *)&b;
+    auto y = ptr->x; // no-warning
+  }
+  {
+    auto *ptr = (AliasedAnotherBase *)&b;
+    auto y = (*ptr).y; // expected-warning{{Undefined behavior}}
+  }
+}
+
+// This produces nested CXXBaseObjectRegion.
+void nested_casts() {
+  MostDerived md;
+  {
+    auto *ptr1 = (Derived *)&md; // Base{md,Derived}
+    auto *ptr2 = (Base *)ptr1;   // Base{Base{md,Derived},Base}
+    auto y = ptr2->x;            // no-warning
+  }
+  {
+    auto *ptr1 = (Base *)&md;
+    auto *ptr2 = (Derived *)ptr1;
+    auto y = ptr2->x; // no-warning
+  }
+  {
+    auto *ptr1 = (Base *)&md;
+    auto *ptr2 = (AnotherBase *)ptr1;
+    auto *ptr3 = (MostDerived *)ptr2;
+    auto y = ptr3->x; // no-warning
+  }
+  {
+    auto *ptr1 = (Base *)&md;
+    auto *ptr2 = (MostDerived *)ptr1;
+    auto *ptr3 = (char *)ptr2;
+    auto y = *ptr3; // no-warning
+  }
+  {
+    auto *ptr1 = (UnionInt *)&md;
+    // TODO: Should not warn.
+    auto *ptr2 = (char *)ptr1; // expected-warning{{Undefined behavior}}
+    auto *ptr3 = (Base *)ptr2;
+    auto y = ptr3->x; // no-warning
+  }
+}
+
+} // namespace ns1
Index: clang/lib/StaticAnalyzer/Checkers/StrictAliasingChecker.cpp
===================================================================
--- /dev/null
+++ clang/lib/StaticAnalyzer/Checkers/StrictAliasingChecker.cpp
@@ -0,0 +1,204 @@
+//===- StrictAliasingChecker - ... ------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// StrictAliasingChecker implements checks on violation of the next paragraph of
+// the Standard which is known as `Strict Aliasing Rule`.
+// C++20 7.2.1 p11 [basic.lval]:
+//  If a program attempts to access the stored value of an object through a
+//  glvalue whose type is not similar to one of the following types the behavior
+//  is undefined:
+//  - the dynamic type of the object,
+//  - a type that is the signed or unsigned type corresponding to the dynamic
+//    type of the object, or
+//  - a char, unsigned char, or std::byte type.
+//
+// NOTE: The checker operates only when strict-aliasing is enabled with
+// corresponding compiler flag.
+//
+// NOTE: There are differences in strict aliasing rules between C, C++
+// Standards. Now we only impelement checks since C++20 Standard (there were
+// changes applied in C++20 http://wg21.link/cwg2051).
+//
+// TODO: Support C++98/11/14/17. Shall we?
+// TODO: Support C.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Attr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class AccessInferrer {
+  QualType From;
+  QualType To;
+  ASTContext &Ctx;
+
+public:
+  // Check whether the given types submit to the Strict Aliasing Rule.
+  //
+  // NOTE: User must provide canonical and unqualified QualType's for the
+  // correct result.
+  static bool canAccess(QualType From, QualType To, ASTContext &Ctx) {
+    // NOTE: Despite the function name `isCanonical()`, it also check whether
+    // the type is unqualified. (See implementation)
+    assert(From.isCanonical() && "The type shall be an unqualified canonical.");
+    assert(To.isCanonical() && "The type shall be an unqualified canonical.");
+    AccessInferrer AI(From, To, Ctx);
+    return AI.canAccessImpl();
+  }
+
+private:
+  AccessInferrer(QualType From, QualType To, ASTContext &Ctx)
+      : From(From), To(To), Ctx(Ctx) {}
+  bool canAccessImpl() {
+    return isSameDynamic() || isCharOrByte() || isOppositeSign();
+  }
+  // - the dynamic type of the object
+  bool isSameDynamic() {
+    if (From == To)
+      return true;
+
+    if (const CXXRecordDecl *FromDecl = From->getAsCXXRecordDecl())
+      if (const CXXRecordDecl *ToDecl = To->getAsCXXRecordDecl())
+        return FromDecl->isDerivedFrom(ToDecl);
+
+    return false;
+  }
+  // - a char, unsigned char, or std::byte type.
+  bool isCharOrByte() {
+    return To == Ctx.CharTy || To == Ctx.UnsignedCharTy || To->isStdByteType();
+  }
+  // - a type that is the signed or unsigned type corresponding to the dynamic
+  //   type of the object
+  bool isOppositeSign() {
+    QualType OppositeSignTy;
+    if (To->isUnsignedIntegerOrEnumerationType())
+      OppositeSignTy = Ctx.getCorrespondingSignedType(To);
+    else if (To->isSignedIntegerOrEnumerationType())
+      OppositeSignTy = Ctx.getCorrespondingUnsignedType(To);
+    return From == OppositeSignTy;
+  }
+};
+
+class StrictAliasingChecker : public Checker<check::Location> {
+  BugType BT{this, "Strict Aliasing Rule",
+             "Access Violation through unallowed type."};
+
+public:
+  void checkLocation(SVal Location, bool IsLoad, const Stmt *S,
+                     CheckerContext &C) const {
+    // Handle Expr only.
+    if (!isa<Expr>(S))
+      return;
+
+    const QualType ExprTy = cast<Expr>(S)->getType();
+
+    const QualType AliasedTy = getAliasedType(ExprTy);
+    // TODO: Handle this case in a proper way, if any.
+    if (AliasedTy.isNull())
+      return;
+
+    const QualType OrigTy = getOriginalType(C, Location, ExprTy);
+    // TODO: Handle this case in a proper way, if any.
+    if (OrigTy.isNull())
+      return;
+
+    if (!AccessInferrer::canAccess(OrigTy, AliasedTy, C.getASTContext()))
+      reportBug(C, OrigTy, AliasedTy);
+  }
+
+private:
+  // FIXME: Probably, we should have such function in QualType class.
+  // Existing `T->getCanonicalTypeUnqualified()` does not return unqualified
+  // type which, apparently, is expected.
+  QualType getCanonicalUnqualifiedType(QualType T) const {
+    // TODO: Check getUnqualifiedDesugaredType.
+    if (!T.isNull()) {
+      T = T->getCanonicalTypeUnqualified();
+      T.removeLocalFastQualifiers();
+    }
+    return T;
+  }
+
+  QualType getOriginalType(CheckerContext &C, SVal V, QualType T) const {
+    if (V.isUnknownOrUndef())
+      return QualType{};
+
+    assert(V.getAs<Loc>() && "Location shall be a Loc.");
+    V = C.getState()->getSVal(V.castAs<Loc>(), T);
+
+    auto MRV = V.getAs<loc::MemRegionVal>();
+    if (!MRV.hasValue())
+      return getCanonicalUnqualifiedType(V.getType(C.getASTContext()));
+
+    // Unwrap ElementRegion and CXXBaseObjectRegion nesting to get the base
+    // region.
+    const MemRegion *Base = MRV->getRegion()->StripCasts(true);
+
+    // Get type of the original declaration.
+    if (const VarRegion *VR = dyn_cast<VarRegion>(Base))
+      return getCanonicalUnqualifiedType(VR->getValueType());
+
+    // Get type from other types of regions.
+    // TODO: Support other regions in a proper way if would need.
+    return getCanonicalUnqualifiedType(V.getType(C.getASTContext()));
+  }
+
+  QualType getAliasedType(QualType T) const {
+    T = T->getPointeeType();
+    // If there is no pointee type(is null), then, it most likely is a cast from
+    // non-pointer (etc. integer) to pointer.
+    // TODO: Handle this case in a proper way, if any.
+    return getCanonicalUnqualifiedType(T);
+  }
+
+  const MemRegion *getElementRegionBase(const ElementRegion *ER) const {
+    const MemRegion *R = ER->getSuperRegion();
+    while ((ER = dyn_cast<ElementRegion>(R)))
+      R = ER->getSuperRegion();
+    return R;
+  }
+
+  void reportBug(CheckerContext &C, QualType From, QualType To) const {
+    SmallString<256> Buf;
+    llvm::raw_svector_ostream OS(Buf);
+    OS << "Undefined behavior. Attempting to access the stored value of type ";
+    OS << "'" << From.getAsString() << "'";
+    OS << " through unallowed type ";
+    OS << "'" << To.getAsString() << "'.";
+
+    ExplodedNode *Node = C.generateNonFatalErrorNode();
+    auto Report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), Node);
+    C.emitReport(std::move(Report));
+  }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Registration.
+//===----------------------------------------------------------------------===//
+
+void ento::registerStrictAliasingChecker(CheckerManager &CM) {
+  CM.registerChecker<StrictAliasingChecker>();
+}
+
+bool ento::shouldRegisterStrictAliasingChecker(const CheckerManager &CM) {
+  const LangOptions &LO = CM.getLangOpts();
+  const bool IsStrictAliasing = !CM.getCodeGenOpts().RelaxedAliasing;
+  // Support from C++20 for now.
+  // TODO: Support C++98/11/14/17. Shall we?
+  // TODO: Support C.
+  return IsStrictAliasing && (LO.CPlusPlus20 || LO.CPlusPlus2b);
+}
Index: clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -105,6 +105,7 @@
   StdLibraryFunctionsChecker.cpp
   STLAlgorithmModeling.cpp
   StreamChecker.cpp
+  StrictAliasingChecker.cpp
   StringChecker.cpp
   Taint.cpp
   TaintTesterChecker.cpp
Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -298,6 +298,12 @@
   Dependencies<[PthreadLockBase]>,
   Documentation<HasAlphaDocumentation>;
 
+def StrictAliasingChecker : Checker<"StrictAliasing">,
+  HelpText<"Check conformity with Strict Alising Rule. Check an access to the "
+           "stored value through a glvalue whose type is not allowed by "
+           "the Standard. ([basic.lval])">,
+  Documentation<HasAlphaDocumentation>;
+
 } // end "alpha.core"
 
 //===----------------------------------------------------------------------===//
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to