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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits