donat.nagy updated this revision to Diff 549881. Repository: rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION https://reviews.llvm.org/D157104/new/ https://reviews.llvm.org/D157104 Files: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp clang/test/Analysis/out-of-bounds.c Index: clang/test/Analysis/out-of-bounds.c =================================================================== --- clang/test/Analysis/out-of-bounds.c +++ clang/test/Analysis/out-of-bounds.c @@ -151,11 +151,23 @@ // Don't warn when indexing below the start of a symbolic region's whose // base extent we don't know. int *get_symbolic(void); -void test_index_below_symboloc(void) { +void test_underflow_symbolic(void) { int *buf = get_symbolic(); buf[-1] = 0; // no-warning; } +// But warn if we understand the internal memory layout of a symbolic region. +typedef struct { + int id; + char name[256]; +} user_t; + +user_t *get_symbolic_user(void); +char test_underflow_symbolic_2() { + user_t *user = get_symbolic_user(); + return user->name[-1]; // expected-warning{{Out of bound memory access}} +} + void test_incomplete_struct(void) { extern struct incomplete incomplete; int *p = (int *)&incomplete; Index: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -172,13 +172,18 @@ return; NonLoc ByteOffset = RawOffset->getByteOffset(); + const SubRegion *Reg = RawOffset->getRegion(); // CHECK LOWER BOUND - const MemSpaceRegion *SR = RawOffset->getRegion()->getMemorySpace(); - if (!llvm::isa<UnknownSpaceRegion>(SR)) { - // A pointer to UnknownSpaceRegion may point to the middle of - // an allocated region. - + const MemSpaceRegion *Space = Reg->getMemorySpace(); + if (!(isa<SymbolicRegion>(Reg) && isa<UnknownSpaceRegion>(Space))) { + // A symbolic region in unknown space represents an unknown pointer that + // may point into the middle of an array, so we don't look for underflows. + // Both conditions are significant because we want to check underflows in + // symbolic regions on the heap (which may be introduced by checkers like + // MallocChecker that call SValBuilder::getConjuredHeapSymbolVal()) and + // non-symbolic regions (e.g. a field subregion of a symbolic region) in + // unknown space. auto [state_precedesLowerBound, state_withinLowerBound] = compareValueToThreshold(state, ByteOffset, svalBuilder.makeZeroArrayIndex(), svalBuilder); @@ -195,7 +200,7 @@ // CHECK UPPER BOUND DefinedOrUnknownSVal Size = - getDynamicExtent(state, RawOffset->getRegion(), svalBuilder); + getDynamicExtent(state, Reg, svalBuilder); if (auto KnownSize = Size.getAs<NonLoc>()) { auto [state_withinUpperBound, state_exceedsUpperBound] = compareValueToThreshold(state, ByteOffset, *KnownSize, svalBuilder);
Index: clang/test/Analysis/out-of-bounds.c =================================================================== --- clang/test/Analysis/out-of-bounds.c +++ clang/test/Analysis/out-of-bounds.c @@ -151,11 +151,23 @@ // Don't warn when indexing below the start of a symbolic region's whose // base extent we don't know. int *get_symbolic(void); -void test_index_below_symboloc(void) { +void test_underflow_symbolic(void) { int *buf = get_symbolic(); buf[-1] = 0; // no-warning; } +// But warn if we understand the internal memory layout of a symbolic region. +typedef struct { + int id; + char name[256]; +} user_t; + +user_t *get_symbolic_user(void); +char test_underflow_symbolic_2() { + user_t *user = get_symbolic_user(); + return user->name[-1]; // expected-warning{{Out of bound memory access}} +} + void test_incomplete_struct(void) { extern struct incomplete incomplete; int *p = (int *)&incomplete; Index: clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -172,13 +172,18 @@ return; NonLoc ByteOffset = RawOffset->getByteOffset(); + const SubRegion *Reg = RawOffset->getRegion(); // CHECK LOWER BOUND - const MemSpaceRegion *SR = RawOffset->getRegion()->getMemorySpace(); - if (!llvm::isa<UnknownSpaceRegion>(SR)) { - // A pointer to UnknownSpaceRegion may point to the middle of - // an allocated region. - + const MemSpaceRegion *Space = Reg->getMemorySpace(); + if (!(isa<SymbolicRegion>(Reg) && isa<UnknownSpaceRegion>(Space))) { + // A symbolic region in unknown space represents an unknown pointer that + // may point into the middle of an array, so we don't look for underflows. + // Both conditions are significant because we want to check underflows in + // symbolic regions on the heap (which may be introduced by checkers like + // MallocChecker that call SValBuilder::getConjuredHeapSymbolVal()) and + // non-symbolic regions (e.g. a field subregion of a symbolic region) in + // unknown space. auto [state_precedesLowerBound, state_withinLowerBound] = compareValueToThreshold(state, ByteOffset, svalBuilder.makeZeroArrayIndex(), svalBuilder); @@ -195,7 +200,7 @@ // CHECK UPPER BOUND DefinedOrUnknownSVal Size = - getDynamicExtent(state, RawOffset->getRegion(), svalBuilder); + getDynamicExtent(state, Reg, svalBuilder); if (auto KnownSize = Size.getAs<NonLoc>()) { auto [state_withinUpperBound, state_exceedsUpperBound] = compareValueToThreshold(state, ByteOffset, *KnownSize, svalBuilder);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits