Index: lib/StaticAnalyzer/Core/Environment.cpp =================================================================== --- lib/StaticAnalyzer/Core/Environment.cpp +++ lib/StaticAnalyzer/Core/Environment.cpp @@ -171,8 +171,15 @@ EBMapRef = EBMapRef.add(BlkExpr, X); // If the block expr's value is a memory region, then mark that region. - if (Optional R = X.getAs()) - SymReaper.markLive(R->getRegion()); + if (Optional R = X.getAs()) { + const MemRegion *MR = R->getRegion(); + SymReaper.markLive(MR); + + // Mark the element index as live. + if (const ElementRegion *ER = dyn_cast(MR)) + if (SymbolRef Sym = ER->getIndex().getAsSymbol()) + SymReaper.markLive(Sym); + } // Mark all symbols in the block expr's value live. RSScaner.scan(X); Index: lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- lib/StaticAnalyzer/Core/RegionStore.cpp +++ lib/StaticAnalyzer/Core/RegionStore.cpp @@ -2260,6 +2260,16 @@ if (const MemRegion *R = V.getAsRegion()) { AddToWorkList(R); + // Element index of an element region is live. + if (const ElementRegion *ER = dyn_cast(R)) { + SVal Idx = ER->getIndex(); + for (SymExpr::symbol_iterator SI = Idx.symbol_begin(), + SE = Idx.symbol_end(); + SI != SE; ++SI) { + SymReaper.markLive(*SI); + } + } + // All regions captured by a block are also live. if (const BlockDataRegion *BR = dyn_cast(R)) { BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(), Index: test/Analysis/return-ptr-range.cpp =================================================================== --- test/Analysis/return-ptr-range.cpp +++ test/Analysis/return-ptr-range.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.ReturnPtrRange -verify %s + +int arr[10]; +int *ptr; + +int conjure_index(); + +int *test_element_index_lifetime() { + do { + int x = conjure_index(); + ptr = arr + x; + if (x != 20) + return arr; // no-warning + } while (0); + return ptr; // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow)}} +} + +int *test_element_index_lifetime_with_local_ptr() { + int *local_ptr; + do { + int x = conjure_index(); + local_ptr = arr + x; + if (x != 20) + return arr; // no-warning + } while (0); + return local_ptr; // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow)}} +}