// RUN: %clang_analyze_cc1 -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)}} } 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(); }