ASDenysPetrov updated this revision to Diff 383812.
ASDenysPetrov added a comment.
Updated according to comments.
TODO: make the feature `-fno-strict-aliasing` dependent.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D110927/new/
https://reviews.llvm.org/D110927
Files:
clang/lib/StaticAnalyzer/Core/RegionStore.cpp
clang/test/Analysis/initialization.cpp
Index: clang/test/Analysis/initialization.cpp
===================================================================
--- clang/test/Analysis/initialization.cpp
+++ clang/test/Analysis/initialization.cpp
@@ -4,6 +4,10 @@
void clang_analyzer_dump(T x);
void clang_analyzer_eval(int);
+namespace std {
+enum class byte : unsigned char {};
+};
+
struct S {
int a = 3;
};
@@ -256,3 +260,55 @@
clang_analyzer_eval(glob_arr9[1][2] == 7); // expected-warning{{TRUE}}
clang_analyzer_eval(glob_arr9[1][3] == 0); // expected-warning{{TRUE}}
}
+
+void glob_cast_same1() {
+ auto *ptr = (int *)glob_arr2;
+ auto x1 = ptr[0]; // no-warning
+ auto x2 = ptr[1]; // no-warning
+}
+
+void glob_cast_char1() {
+ const auto *ptr = (char *)glob_arr2; // 1-dim array to char*
+ auto x1 = ptr[0]; // no-warning
+ auto x2 = ptr[1]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_cast_char2() {
+ const auto *ptr = (char *)glob_arr5; // 2-dim array to char*
+ auto x1 = ptr[0]; // no-warning
+ // FIXME: Should warn {{garbage or undefined}}.
+ auto x2 = ptr[1]; // no-warning
+}
+
+void glob_cast_uchar1() {
+ auto *ptr = (unsigned char *)glob_arr2;
+ auto x1 = ptr[0]; // no-warning
+ auto x2 = ptr[1]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_cast_byte1() {
+ auto *ptr = (const std::byte *)glob_arr2;
+ auto x1 = ptr[0]; // no-warning
+ auto x2 = ptr[1]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_cast_opposite_sign1() {
+ auto *ptr = (unsigned int *)glob_arr2;
+ auto x1 = ptr[0]; // no-warning
+ auto x2 = ptr[1]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_cast_invalid1() {
+ auto *ptr = (signed char *)glob_arr2;
+ auto x = ptr[0]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_cast_invalid2() {
+ using T = short *;
+ auto x = ((T)glob_arr2)[0]; // expected-warning{{garbage or undefined}}
+}
+
+void glob_cast_invalid3() {
+ auto *ptr = (char32_t *)glob_arr2;
+ auto x = ptr[0]; // expected-warning{{garbage or undefined}}
+}
Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -446,6 +446,8 @@
QualType ElemT);
SVal getSValFromStringLiteral(const StringLiteral *SL, uint64_t Offset,
QualType ElemT);
+ bool canAccessStoredValue(QualType OrigT, QualType ThroughT,
+ uint64_t Index) const;
public: // Part of public interface to class.
@@ -1651,6 +1653,20 @@
return Extents;
}
+/// This is a helper function for `getConstantValFromConstArrayInitializer`.
+///
+/// Return a root type of the n-dimensional array.
+///
+/// E.g. for `const int[1][2][3];` returns `int`.
+QualType getConstantArrayRootElement(const ConstantArrayType *CAT) {
+ assert(CAT && "ConstantArrayType should not be null");
+ while (const auto *DummyCAT =
+ dyn_cast<ConstantArrayType>(CAT->getElementType())) {
+ CAT = DummyCAT;
+ }
+ return CAT->getElementType();
+}
+
/// This is a helper function for `getConstantValFromConstArrayInitializer`.
///
/// Return an array of offsets from nested ElementRegions. The array is never
@@ -1736,6 +1752,60 @@
return None;
}
+/// Returns true if the stored value can be accessed through the pointer to
+/// another type.
+///
+/// C++20 7.2.1.11 [basic.lval] (excerpt):
+/// A program can access the stored value of an object through:
+/// - the same type of the object;
+/// - a signed or unsigned type corresponding to the type of the
+/// object;
+/// - a char, unsigned char, std::byte. (NOTE:
+/// Otherwise, the behavior is undefined.
+///
+/// Example:
+/// const int arr[42] = {};
+/// auto* pchar = (char*)arr;
+/// auto* punsigned = (unsigned int*)arr;
+/// auto* pshort = (short*)arr;
+/// auto x1 = pchar[0]; // valid
+/// auto x2 = pchar[1]; // UB
+/// auto x3 = punsigned[0]; // valid
+/// auto x4 = pshort[0]; // UB
+bool RegionStoreManager::canAccessStoredValue(QualType OrigT, QualType ThroughT,
+ uint64_t Index) const {
+ // Remove cv-qualifiers.
+ OrigT = OrigT->getCanonicalTypeUnqualified();
+ ThroughT = ThroughT->getCanonicalTypeUnqualified();
+
+ // - is same
+ if (OrigT == ThroughT)
+ return true;
+
+ // NOTE: C++20 6.8.2(3.4) [basic.compound]:
+ // An object of type T that is not an array element is considered to
+ // belong to an array with ONE element of type T.
+ // Hence, the first element can be retrieved only. At least until a
+ // paper P1839R0 be considered by the committee.
+ if ((Index != 0))
+ return false;
+
+ // - is char, uchar, std::byte
+ if ((ThroughT == Ctx.CharTy) || (ThroughT == Ctx.UnsignedCharTy) ||
+ ThroughT->isStdByteType())
+ return true;
+
+ QualType TypeWithOppositeSign = OrigT->isUnsignedIntegerOrEnumerationType()
+ ? Ctx.getCorrespondingSignedType(OrigT)
+ : Ctx.getCorrespondingUnsignedType(OrigT);
+
+ // - is opposite sign
+ if (ThroughT == TypeWithOppositeSign)
+ return true;
+
+ return false;
+}
+
Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
RegionBindingsConstRef B, const ElementRegion *R) {
assert(R && "ElementRegion should not be null");
@@ -1799,18 +1869,24 @@
ConcreteOffsets))
return *V;
+ // Check whether a program can access the stored value of another
+ // type.
+ QualType ElemT = R->getElementType();
+ QualType ArrT = getConstantArrayRootElement(CAT);
+ if (!canAccessStoredValue(ArrT, ElemT, ConcreteOffsets.back()))
+ return UndefinedVal();
+
// Handle InitListExpr.
// Example:
// const char arr[4][2] = { { 1, 2 }, { 3 }, 4, 5 };
if (const auto *ILE = dyn_cast<InitListExpr>(Init))
- return getSValFromInitListExpr(ILE, ConcreteOffsets, R->getElementType());
+ return getSValFromInitListExpr(ILE, ConcreteOffsets, ElemT);
// Handle StringLiteral.
// Example:
// const char arr[] = "abc";
if (const auto *SL = dyn_cast<StringLiteral>(Init))
- return getSValFromStringLiteral(SL, ConcreteOffsets.front(),
- R->getElementType());
+ return getSValFromStringLiteral(SL, ConcreteOffsets.front(), ElemT);
// FIXME: Handle CompoundLiteralExpr.
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits