Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -796,6 +796,10 @@ Dependencies<[SecuritySyntaxChecker]>, Documentation; +def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, + HelpText<"Check for an out-of-bound pointer being returned to callers">, + Documentation; + } // end "security" let ParentPackage = SecurityAlpha in { @@ -808,10 +812,6 @@ HelpText<"Warn about buffer overflows (newer checker)">, Documentation; -def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, - HelpText<"Check for an out-of-bound pointer being returned to callers">, - Documentation; - def MallocOverflowSecurityChecker : Checker<"MallocOverflow">, HelpText<"Check for overflows in the arguments to malloc()">, Documentation; 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) { 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 @@ -1,5 +1,5 @@ -// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s -// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyzer-checker=core,alpha.core.CastToStruct,alpha.security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s +// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core.CastToStruct,security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s +// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyzer-checker=core,alpha.core.CastToStruct,security.ReturnPtrRange,alpha.security.ArrayBound -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -Wno-objc-root-class %s typedef long unsigned int size_t; void *memcpy(void *, const void *, size_t); @@ -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 @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.security.ReturnPtrRange -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=security.ReturnPtrRange -verify %s int arr[10]; int *ptr; @@ -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(); +}