steakhal updated this revision to Diff 283936. steakhal added a comment. - Moved the FIXME closer to the subject. - Added tests for covering incomplete enums as well. - Added `REQUIRES: z3`. This will mark the test case `unsupported` on every buildbots. See my notes about this behavior at D83677 <https://reviews.llvm.org/D83677>. - Refined test file.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D85528/new/ https://reviews.llvm.org/D85528 Files: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h clang/test/Analysis/z3-refute-enum-crash.cpp
Index: clang/test/Analysis/z3-refute-enum-crash.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/z3-refute-enum-crash.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection \ +// RUN: -analyzer-config crosscheck-with-z3=true -verify %s +// REQUIRES: z3 +// +// Requires z3 only for refutation. Works with both constraint managers. + +void clang_analyzer_warnIfReached(); + +using sugar_t = unsigned char; + +// Complete enum types +enum class ScopedSugaredComplete : sugar_t {}; +enum class ScopedPrimitiveComplete : unsigned char {}; +enum UnscopedSugaredComplete : sugar_t {}; +enum UnscopedPrimitiveComplete : unsigned char {}; + +// Incomplete enum types +enum class ScopedSugaredIncomplete : sugar_t; +enum class ScopedPrimitiveIncomplete : unsigned char; +enum UnscopedSugaredIncomplete : sugar_t; +enum UnscopedPrimitiveIncomplete : unsigned char; + +template <typename T> +T conjure(); + +void test_complete_enum_types() { + auto var1 = conjure<ScopedSugaredComplete>(); + auto var2 = conjure<ScopedPrimitiveComplete>(); + auto var3 = conjure<UnscopedSugaredComplete>(); + auto var4 = conjure<UnscopedPrimitiveComplete>(); + + int sym1 = static_cast<unsigned char>(var1) & 0x0F; + if (sym1) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash + + int sym2 = static_cast<unsigned char>(var2) & 0x0F; + if (sym2) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash + + int sym3 = static_cast<unsigned char>(var3) & 0x0F; + if (sym3) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash + + int sym4 = static_cast<unsigned char>(var4) & 0x0F; + if (sym4) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash +} + +void test_incomplete_enum_types() { + auto var1 = conjure<ScopedSugaredIncomplete>(); + auto var2 = conjure<ScopedPrimitiveIncomplete>(); + auto var3 = conjure<UnscopedSugaredIncomplete>(); + auto var4 = conjure<UnscopedPrimitiveIncomplete>(); + + int sym1 = static_cast<unsigned char>(var1) & 0x0F; + if (sym1) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash + + int sym2 = static_cast<unsigned char>(var2) & 0x0F; + if (sym2) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash + + int sym3 = static_cast<unsigned char>(var3) & 0x0F; + if (sym3) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash + + int sym4 = static_cast<unsigned char>(var4) & 0x0F; + if (sym4) + clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash +} Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -95,11 +95,22 @@ } bool haveSameType(QualType Ty1, QualType Ty2) { + const auto IsIntegralOrUnscopedCompleteEnumerationType = [](QualType Ty) { + const Type *CanonicalType = Ty.getCanonicalType().getTypePtr(); + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + return Ty->isIntegralOrEnumerationType(); + }; + + const bool BothHaveSameCanonicalTypes = + Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2); + const bool BothHaveIntegralLikeTypes = + IsIntegralOrUnscopedCompleteEnumerationType(Ty1) && + IsIntegralOrUnscopedCompleteEnumerationType(Ty2); + // FIXME: Remove the second disjunct when we support symbolic // truncation/extension. - return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) || - (Ty1->isIntegralOrEnumerationType() && - Ty2->isIntegralOrEnumerationType())); + return BothHaveSameCanonicalTypes || BothHaveIntegralLikeTypes; } SVal evalCast(SVal val, QualType castTy, QualType originalType);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits