Index: clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -58,6 +58,11 @@ = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), ER->getValueType()); + // We assume that the location after the last element in the array is used as + // end() iterator. Reporting on these would return too many false positives. + if (Idx == NumElements) + return; + ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { @@ -70,7 +75,7 @@ // types explicitly reference such exploit categories (when applicable). if (!BT) BT.reset(new BuiltinBug( - this, "Return of pointer value outside of expected range", + this, "Buffer overflow", "Returned pointer value points outside the original object " "(potential buffer overflow)")); Index: clang/test/Analysis/misc-ps-region-store.m =================================================================== --- clang/test/Analysis/misc-ps-region-store.m +++ clang/test/Analysis/misc-ps-region-store.m @@ -463,7 +463,7 @@ static int test_cwe466_return_outofbounds_pointer_a[10]; int *test_cwe466_return_outofbounds_pointer() { - int *p = test_cwe466_return_outofbounds_pointer_a+10; + int *p = test_cwe466_return_outofbounds_pointer_a+11; return p; // expected-warning{{Returned pointer value points outside the original object}} } Index: clang/test/Analysis/return-ptr-range.cpp =================================================================== --- clang/test/Analysis/return-ptr-range.cpp +++ clang/test/Analysis/return-ptr-range.cpp @@ -25,3 +25,47 @@ } while (0); return local_ptr; // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow)}} } + +template +T* end(T (&arr)[N]) { + return arr + N; // no-warning, because we want to avoid false positives on returning the end() iterator of a container. +} + +void get_end_of_array() { + static int arr[10]; + end(arr); +} + +template +class Iterable { + int buffer[N]; + int *start, *finish; + +public: + Iterable() : start(buffer), finish(buffer + N) {} + + int* begin() { return start; } + int* end() { return finish; } +}; + +void use_iterable_object() { + Iterable<20> iter; + iter.end(); +} + +template +class BadIterable { + int buffer[N]; + int *start, *finish; + +public: + BadIterable() : start(buffer), finish(buffer + N) {} + + int* begin() { return start; } + int* end() { return finish + 1; } // expected-warning{{Returned pointer value points outside the original object (potential buffer overflow)}} +}; + +void use_bad_iterable_object() { + BadIterable<20> iter; + iter.end(); +}