ASDenysPetrov created this revision. ASDenysPetrov added reviewers: steakhal, NoQ, martong. ASDenysPetrov added a project: clang. Herald added subscribers: manas, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun. ASDenysPetrov requested review of this revision. Herald added a subscriber: cfe-commits.
Specifically, this fixes the case when we get an access to array element through the pointer to element. This covers several //FIXME's//. in D111654 <https://reviews.llvm.org/D111654>. Example: const int arr[4][2]; const int *ptr = arr[1]; // Fixes this. The issue is that `arr[1]` is `int*` (`&Element{Element{glob_arr5,1 S64b,int[2]},0 S64b,int}`), and `ptr` is `const int*`. We don't take qualifiers into account. Consequently, we doesn't match the types as the same ones. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D113480 Files: clang/lib/StaticAnalyzer/Core/Store.cpp clang/test/Analysis/initialization.cpp Index: clang/test/Analysis/initialization.cpp =================================================================== --- clang/test/Analysis/initialization.cpp +++ clang/test/Analysis/initialization.cpp @@ -68,8 +68,7 @@ void glob_invalid_index4() { const int *ptr = glob_arr4[1]; int idx = -42; - // FIXME: Should warn {{garbage or undefined}}. - auto x = ptr[idx]; // no-warning + auto x = ptr[idx]; // expected-warning{{garbage or undefined}} } int const glob_arr5[4][2] = {{1}, 3, 4, 5}; @@ -86,16 +85,11 @@ void glob_ptr_index2() { int const *ptr = glob_arr5[1]; - // FIXME: Should be TRUE. - clang_analyzer_eval(ptr[0] == 3); // expected-warning{{UNKNOWN}} - // FIXME: Should be TRUE. - clang_analyzer_eval(ptr[1] == 4); // expected-warning{{UNKNOWN}} - // FIXME: Should be UNDEFINED. - clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNKNOWN}} - // FIXME: Should be UNDEFINED. - clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNKNOWN}} - // FIXME: Should be UNDEFINED. - clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(ptr[0] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[1] == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNDEFINED}} + clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNDEFINED}} + clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNDEFINED}} } void glob_invalid_index5() { @@ -106,8 +100,7 @@ void glob_invalid_index6() { int const *ptr = &glob_arr5[1][0]; int idx = 42; - // FIXME: Should warn {{garbage or undefined}}. - auto x = ptr[idx]; // no-warning + auto x = ptr[idx]; // expected-warning{{garbage or undefined}} } extern const int glob_arr_no_init[10]; Index: clang/lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/Store.cpp +++ clang/lib/StaticAnalyzer/Core/Store.cpp @@ -101,13 +101,19 @@ if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy) return R; - // Handle casts from compatible types. - if (R->isBoundable()) + const auto IsSameRegionType = [&Ctx, CanonPointeeTy](const MemRegion *R) { if (const auto *TR = dyn_cast<TypedValueRegion>(R)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); - if (CanonPointeeTy == ObjTy) - return R; + if (CanonPointeeTy.getLocalUnqualifiedType() == + ObjTy.getLocalUnqualifiedType()) + return true; } + return false; + }; + + // Handle casts from compatible types. + if (R->isBoundable() && IsSameRegionType(R)) + return R; // Process region cast according to the kind of the region being cast. switch (R->getKind()) { @@ -174,16 +180,11 @@ CharUnits off = rawOff.getOffset(); if (off.isZero()) { - // Edge case: we are at 0 bytes off the beginning of baseR. We + // Edge case: we are at 0 bytes off the beginning of baseR. We // check to see if type we are casting to is the same as the base - // region. If so, just return the base region. - if (const auto *TR = dyn_cast<TypedValueRegion>(baseR)) { - QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); - QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); - if (CanonPointeeTy == ObjTy) - return baseR; - } - + // region. If so, just return the base region. + if (IsSameRegionType(baseR)) + return baseR; // Otherwise, create a new ElementRegion at offset 0. return MakeElementRegion(cast<SubRegion>(baseR), PointeeTy); }
Index: clang/test/Analysis/initialization.cpp =================================================================== --- clang/test/Analysis/initialization.cpp +++ clang/test/Analysis/initialization.cpp @@ -68,8 +68,7 @@ void glob_invalid_index4() { const int *ptr = glob_arr4[1]; int idx = -42; - // FIXME: Should warn {{garbage or undefined}}. - auto x = ptr[idx]; // no-warning + auto x = ptr[idx]; // expected-warning{{garbage or undefined}} } int const glob_arr5[4][2] = {{1}, 3, 4, 5}; @@ -86,16 +85,11 @@ void glob_ptr_index2() { int const *ptr = glob_arr5[1]; - // FIXME: Should be TRUE. - clang_analyzer_eval(ptr[0] == 3); // expected-warning{{UNKNOWN}} - // FIXME: Should be TRUE. - clang_analyzer_eval(ptr[1] == 4); // expected-warning{{UNKNOWN}} - // FIXME: Should be UNDEFINED. - clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNKNOWN}} - // FIXME: Should be UNDEFINED. - clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNKNOWN}} - // FIXME: Should be UNDEFINED. - clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(ptr[0] == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[1] == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(ptr[2] == 5); // expected-warning{{UNDEFINED}} + clang_analyzer_eval(ptr[3] == 0); // expected-warning{{UNDEFINED}} + clang_analyzer_eval(ptr[4] == 0); // expected-warning{{UNDEFINED}} } void glob_invalid_index5() { @@ -106,8 +100,7 @@ void glob_invalid_index6() { int const *ptr = &glob_arr5[1][0]; int idx = 42; - // FIXME: Should warn {{garbage or undefined}}. - auto x = ptr[idx]; // no-warning + auto x = ptr[idx]; // expected-warning{{garbage or undefined}} } extern const int glob_arr_no_init[10]; Index: clang/lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/Store.cpp +++ clang/lib/StaticAnalyzer/Core/Store.cpp @@ -101,13 +101,19 @@ if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy) return R; - // Handle casts from compatible types. - if (R->isBoundable()) + const auto IsSameRegionType = [&Ctx, CanonPointeeTy](const MemRegion *R) { if (const auto *TR = dyn_cast<TypedValueRegion>(R)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); - if (CanonPointeeTy == ObjTy) - return R; + if (CanonPointeeTy.getLocalUnqualifiedType() == + ObjTy.getLocalUnqualifiedType()) + return true; } + return false; + }; + + // Handle casts from compatible types. + if (R->isBoundable() && IsSameRegionType(R)) + return R; // Process region cast according to the kind of the region being cast. switch (R->getKind()) { @@ -174,16 +180,11 @@ CharUnits off = rawOff.getOffset(); if (off.isZero()) { - // Edge case: we are at 0 bytes off the beginning of baseR. We + // Edge case: we are at 0 bytes off the beginning of baseR. We // check to see if type we are casting to is the same as the base - // region. If so, just return the base region. - if (const auto *TR = dyn_cast<TypedValueRegion>(baseR)) { - QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); - QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); - if (CanonPointeeTy == ObjTy) - return baseR; - } - + // region. If so, just return the base region. + if (IsSameRegionType(baseR)) + return baseR; // Otherwise, create a new ElementRegion at offset 0. return MakeElementRegion(cast<SubRegion>(baseR), PointeeTy); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits