Skip to content

Commit 1eea92e

Browse files
author
Advenam Tacet
committed
Code review from EricWF
This commit addresses some comments from a code review: - add size check, - add coments with context to a test, - add comments explaining what happens in the test, - remove volatile, - split an if to constexpr if and normal if.
1 parent 7af271d commit 1eea92e

File tree

3 files changed

+33
-8
lines changed

3 files changed

+33
-8
lines changed

libcxx/include/string

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,8 +1891,9 @@ private:
18911891
#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
18921892
const void* __begin = data();
18931893
const void* __end = data() + capacity() + 1;
1894-
if (!__libcpp_is_constant_evaluated() && __asan_annotate_container_with_allocator<allocator_type>::value)
1895-
__sanitizer_annotate_contiguous_container(__begin, __end, __old_mid, __new_mid);
1894+
if _LIBCPP_CONSTEXPR_SINCE_CXX17 (__asan_annotate_container_with_allocator<allocator_type>::value)
1895+
if(!__libcpp_is_constant_evaluated())
1896+
__sanitizer_annotate_contiguous_container(__begin, __end, __old_mid, __new_mid);
18961897
#endif
18971898
}
18981899

libcxx/test/libcxx/containers/strings/basic.string/asan.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ int main(int, char**) {
4747
assert(is_string_asan_correct(c));
4848
assert(__sanitizer_verify_contiguous_container(c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) !=
4949
0);
50-
volatile T foo = c[c.size() + 1]; // should trigger ASAN. Use volatile to prevent being optimized away.
51-
assert(false); // if we got here, ASAN didn't trigger
50+
T foo = c[c.size() + 1]; // should trigger ASAN and call do_exit().
51+
assert(false); // if we got here, ASAN didn't trigger
5252
((void)foo);
5353
}
5454
}

libcxx/test/libcxx/containers/strings/basic.string/asan_turning_off.pass.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,26 @@
1616
// In those situations, one may want to deactivate annotations for a specific allocator.
1717
// It's possible with __asan_annotate_container_with_allocator template class.
1818
// This test confirms that those allocators work after turning off annotations.
19+
//
20+
// A context to this test is a situations when memory is repurposed and destructors are not called.
21+
// Related issue: https://github.com/llvm/llvm-project/issues/60384
22+
//
23+
// That issue appeared in the past and was addressed here: https://reviews.llvm.org/D145628
24+
//
25+
// There is also a question, if it's UB. And it's not clear.
26+
// Related discussion: https://reviews.llvm.org/D136765#4155262
27+
// Related notes: https://eel.is/c++draft/basic.life#6
28+
//
29+
// Even if it is UB, we want to make sure that it works that way, because people rely on this behavior.
30+
// In similar situations. a user explicitly turns off annotations for a specific allocator.
1931

2032
#include <assert.h>
2133
#include <stdlib.h>
2234
#include <string>
2335
#include <new>
2436

37+
// Allocator with pre-allocated (with malloc in constructor) buffers.
38+
// Memory may be freed without calling destructors.
2539
struct reuse_allocator {
2640
static size_t const N = 100;
2741
reuse_allocator() {
@@ -50,10 +64,15 @@ struct user_allocator {
5064
friend bool operator==(user_allocator, user_allocator) { return true; }
5165
friend bool operator!=(user_allocator x, user_allocator y) { return !(x == y); }
5266

53-
T* allocate(size_t) { return (T*)reuse_buffers.alloc(); }
67+
T* allocate(size_t n) {
68+
if (n * sizeof(T) > 8 * 1024)
69+
throw std::bad_array_new_length();
70+
return (T*)reuse_buffers.alloc();
71+
}
5472
void deallocate(T*, size_t) noexcept {}
5573
};
5674

75+
// Turn off annotations for user_allocator:
5776
template <class T>
5877
struct std::__asan_annotate_container_with_allocator<user_allocator<T>> {
5978
static bool const value = false;
@@ -63,15 +82,20 @@ int main() {
6382
using S = std::basic_string<char, std::char_traits<char>, user_allocator<char>>;
6483

6584
{
85+
// Create a string with a buffer from reuse allocator object:
6686
S* s = new (reuse_buffers.alloc()) S();
67-
for (int i = 0; i < 100; i++)
87+
// Use string, so it's poisoned, if container annotations for that allocator are not turned off:
88+
for (int i = 0; i < 40; i++)
6889
s->push_back('a');
6990
}
91+
// Reset the state of the allocator, don't call destructors, allow memory to be reused:
7092
reuse_buffers.reset();
7193
{
94+
// Create a next string with the same allocator, so the same buffer due to the reset:
7295
S s;
73-
for (int i = 0; i < 1000; i++)
74-
s.push_back('b');
96+
// Use memory inside the string again, if it's poisoned, an error will be raised:
97+
for (int i = 0; i < 60; i++)
98+
s.push_back('a');
7599
}
76100

77101
return 0;

0 commit comments

Comments
 (0)