|
| 1 | +//===----------------------------------------------------------------------===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +// XFAIL: FROZEN-CXX03-HEADERS-FIXME |
| 10 | +// REQUIRES: asan |
| 11 | + |
| 12 | +// Check that libc++ honors when __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ is set |
| 13 | +// and disables the container overflow checks. |
| 14 | + |
| 15 | +// ADDITIONAL_COMPILE_FLAGS: -D__SANITIZER_DISABLE_CONTAINER_OVERFLOW__ |
| 16 | + |
| 17 | +#include <deque> |
| 18 | +#include <string> |
| 19 | +#include <vector> |
| 20 | + |
| 21 | +// This check is somewhat weak because it would pass if we renamed the libc++-internal |
| 22 | +// macro and forgot to update this test. But it doesn't hurt to check it in addition to |
| 23 | +// the tests below. |
| 24 | +#if _LIBCPP_ENABLE_ASAN_CONTAINER_CHECKS |
| 25 | +# error "Container overflow checks should be disabled in libc++" |
| 26 | +#endif |
| 27 | + |
| 28 | +void vector() { |
| 29 | + std::vector<int> v; |
| 30 | + v.reserve(100); |
| 31 | + int* data = v.data(); |
| 32 | + |
| 33 | + // This is illegal with respect to std::vector, but legal from the core language perspective since |
| 34 | + // we do own that allocated memory and `int` is an implicit lifetime type. If container overflow |
| 35 | + // checks are enabled, this would fail. |
| 36 | + data[4] = 42; |
| 37 | +} |
| 38 | + |
| 39 | +// For std::string, we must use a custom char_traits class to reliably test this behavior. Since |
| 40 | +// std::string is externally instantiated in the built library, __SANITIZER_DISABLE_CONTAINER_OVERFLOW__ |
| 41 | +// will not be honored for any function that happens to be in the built library. Using a custom |
| 42 | +// char_traits class ensures that this doesn't get in the way. |
| 43 | +struct my_char_traits : std::char_traits<char> {}; |
| 44 | + |
| 45 | +void string() { |
| 46 | + std::basic_string<char, my_char_traits> s; |
| 47 | + s.reserve(100); |
| 48 | + char* data = s.data(); |
| 49 | + data[4] = 'x'; |
| 50 | +} |
| 51 | + |
| 52 | +void deque() { |
| 53 | + std::deque<int> d; |
| 54 | + d.push_back(1); |
| 55 | + d.push_back(2); |
| 56 | + d.push_back(3); |
| 57 | + int* last_element = &d[2]; |
| 58 | + d.pop_back(); |
| 59 | + |
| 60 | + // This reference is technically invalidated according to the library. However since |
| 61 | + // we know std::deque is implemented using segments of a fairly large size and we know |
| 62 | + // the non-erased elements are not invalidated by pop_front() (per the Standard), we can |
| 63 | + // rely on the fact that the last element still exists in memory that is owned by the |
| 64 | + // std::deque. |
| 65 | + // |
| 66 | + // If container overflow checks were enabled, this would obviously fail. |
| 67 | + *last_element = 42; |
| 68 | +} |
| 69 | + |
| 70 | +int main(int, char**) { |
| 71 | + vector(); |
| 72 | + string(); |
| 73 | + deque(); |
| 74 | + return 0; |
| 75 | +} |
0 commit comments