33// Test __sanitizer_copy_contiguous_container_annotations.
44
55#include < algorithm>
6- #include < deque >
6+ #include < iostream >
77#include < memory>
88#include < numeric>
9+ #include < vector>
910
1011#include < assert.h>
1112#include < sanitizer/asan_interface.h>
@@ -24,212 +25,132 @@ template <class T> static constexpr T RoundUp(T x) {
2425 RoundDown (reinterpret_cast <uintptr_t >(x) + kGranularity - 1 ));
2526}
2627
27- static std::deque <int > GetPoisonedState (char *begin, char *end) {
28- std::deque <int > result;
28+ static std::vector <int > GetPoisonedState (char *begin, char *end) {
29+ std::vector <int > result;
2930 for (char *ptr = begin; ptr != end; ++ptr) {
3031 result.push_back (__asan_address_is_poisoned (ptr));
3132 }
3233 return result;
3334}
3435
3536static void RandomPoison (char *beg, char *end) {
36- if (beg != RoundDown (beg) && RoundDown (beg) != RoundDown (end) &&
37- rand () % 2 == 1 ) {
38- __asan_poison_memory_region (beg, RoundUp (beg) - beg);
39- __asan_unpoison_memory_region (beg, rand () % (RoundUp (beg) - beg + 1 ));
40- }
37+ assert (beg == RoundDown (beg));
38+ assert (end == RoundDown (end));
4139 for (beg = RoundUp (beg); beg + kGranularity <= end; beg += kGranularity ) {
4240 __asan_poison_memory_region (beg, kGranularity );
4341 __asan_unpoison_memory_region (beg, rand () % (kGranularity + 1 ));
4442 }
45- if (end > beg && __asan_address_is_poisoned (end)) {
46- __asan_poison_memory_region (beg, kGranularity );
47- __asan_unpoison_memory_region (beg, rand () % (end - beg + 1 ));
48- }
4943}
5044
51- static size_t CountUnpoisoned (std::deque<int > &poison_states, size_t n) {
52- size_t result = 0 ;
53- for (size_t i = 0 ; i < n && !poison_states.empty (); ++i) {
54- if (!poison_states.front ()) {
55- result = i + 1 ;
56- }
57- poison_states.pop_front ();
45+ static void Test (size_t capacity, size_t off_src, size_t off_dst,
46+ char *src_buffer_beg, char *src_buffer_end,
47+ char *dst_buffer_beg, char *dst_buffer_end) {
48+ size_t dst_buffer_size = dst_buffer_end - dst_buffer_beg;
49+ char *src_beg = src_buffer_beg + off_src;
50+ char *src_end = src_beg + capacity;
51+
52+ char *dst_beg = dst_buffer_beg + off_dst;
53+ char *dst_end = dst_beg + capacity;
54+
55+ std::vector<int > src_poison_states =
56+ GetPoisonedState (src_buffer_beg, src_buffer_end);
57+ std::vector<int > dst_poison_before =
58+ GetPoisonedState (dst_buffer_beg, dst_buffer_end);
59+ __sanitizer_copy_contiguous_container_annotations (src_beg, src_end, dst_beg,
60+ dst_end);
61+ std::vector<int > dst_poison_after =
62+ GetPoisonedState (dst_buffer_beg, dst_buffer_end);
63+
64+ // Create ideal copy of src over dst.
65+ std::vector<int > dst_poison_exp = dst_poison_before;
66+ for (size_t cur = 0 ; cur < capacity; ++cur)
67+ dst_poison_exp[off_dst + cur] = src_poison_states[off_src + cur];
68+
69+ // Unpoison prefixes of Asan granules.
70+ for (size_t cur = dst_buffer_size - 1 ; cur > 0 ; --cur) {
71+ if (cur % kGranularity != 0 && !dst_poison_exp[cur])
72+ dst_poison_exp[cur - 1 ] = 0 ;
5873 }
5974
60- return result;
75+ if (dst_poison_after != dst_poison_exp) {
76+ std::cerr << " [" << off_dst << " , " << off_dst + capacity << " )\n " ;
77+ for (size_t i = 0 ; i < dst_poison_after.size (); ++i) {
78+ std::cerr << i << " :\t " << dst_poison_before[i] << " \t "
79+ << dst_poison_after[i] << " \t " << dst_poison_exp[i] << " \n " ;
80+ }
81+ std::cerr << " ----------\n " ;
82+
83+ assert (dst_poison_after == dst_poison_exp);
84+ }
6185}
6286
63- void TestNonOverlappingContainers (size_t capacity, size_t off_src,
64- size_t off_dst, bool poison_src,
65- bool poison_dst) {
66- size_t src_buffer_size = capacity + off_src + kGranularity * 2 ;
67- size_t dst_buffer_size = capacity + off_dst + kGranularity * 2 ;
87+ static void TestNonOverlappingContainers (size_t capacity, size_t off_src,
88+ size_t off_dst) {
89+ // Test will copy [off_src, off_src + capacity) to [off_dst, off_dst + capacity).
90+ // Allocate buffers to have additional granule before and after tested ranges.
91+ off_src += kGranularity ;
92+ off_dst += kGranularity ;
93+ size_t src_buffer_size = RoundUp (off_src + capacity) + kGranularity ;
94+ size_t dst_buffer_size = RoundUp (off_dst + capacity) + kGranularity ;
6895
6996 std::unique_ptr<char []> src_buffer =
7097 std::make_unique<char []>(src_buffer_size);
7198 std::unique_ptr<char []> dst_buffer =
7299 std::make_unique<char []>(dst_buffer_size);
73100
74- char *src_buffer_end = src_buffer.get () + src_buffer_size;
75- char *dst_buffer_end = dst_buffer.get () + dst_buffer_size;
76- char *src_beg = src_buffer.get () + off_src;
77- char *dst_beg = dst_buffer.get () + off_dst;
78- char *src_end = src_beg + capacity;
79- char *dst_end = dst_beg + capacity;
101+ char *src_buffer_beg = src_buffer.get ();
102+ char *src_buffer_end = src_buffer_beg + src_buffer_size;
103+ assert (RoundDown (src_buffer_beg) == src_buffer_beg);
80104
81- for (int i = 0 ; i < 35 ; i++) {
82- if (poison_src)
83- __asan_poison_memory_region (src_buffer.get (), src_buffer_size);
84- if (poison_dst)
85- __asan_poison_memory_region (dst_buffer.get (), dst_buffer_size);
86-
87- RandomPoison (src_beg, src_end);
88- std::deque<int > poison_states = GetPoisonedState (src_beg, src_end);
89- __sanitizer_copy_contiguous_container_annotations (src_beg, src_end, dst_beg,
90- dst_end);
91-
92- // If src_buffer were poisoned, expected state of memory before src_beg
93- // is undetermined.
94- // If old buffer were not poisoned, that memory should still be unpoisoned.
95- char *cur;
96- if (!poison_src) {
97- for (cur = src_buffer.get (); cur < src_beg; ++cur) {
98- assert (!__asan_address_is_poisoned (cur));
99- }
100- }
101- for (size_t i = 0 ; i < poison_states.size (); ++i) {
102- assert (__asan_address_is_poisoned (&src_beg[i]) == poison_states[i]);
103- }
104- // Memory after src_end should be the same as at the beginning.
105- for (cur = src_end; cur < src_buffer_end; ++cur) {
106- assert (__asan_address_is_poisoned (cur) == poison_dst);
107- }
105+ char *dst_buffer_beg = dst_buffer.get ();
106+ char *dst_buffer_end = dst_buffer_beg + dst_buffer_size;
107+ assert (RoundDown (dst_buffer_beg) == dst_buffer_beg);
108108
109- // If dst_buffer were not poisoned, memory before dst_beg should never
110- // be poisoned. Otherwise, its state is undetermined.
111- if (!poison_dst) {
112- for (cur = dst_buffer.get (); cur < dst_beg; ++cur) {
113- assert (!__asan_address_is_poisoned (cur));
114- }
115- }
109+ for (int i = 0 ; i < 35 ; i++) {
110+ RandomPoison (src_buffer_beg, src_buffer_end);
111+ RandomPoison (dst_buffer_beg, dst_buffer_end);
116112
117- char *next;
118- for (cur = dst_beg; cur + kGranularity <= dst_end; cur = next) {
119- next = RoundUp (cur + 1 );
120- size_t unpoisoned = CountUnpoisoned (poison_states, next - cur);
121- if (unpoisoned > 0 ) {
122- assert (!__asan_address_is_poisoned (cur + unpoisoned - 1 ));
123- }
124- if (cur + unpoisoned < next) {
125- assert (__asan_address_is_poisoned (cur + unpoisoned));
126- }
127- }
128- // [cur; dst_end) is not checked yet.
129- // If dst_buffer were not poisoned, it cannot be poisoned.
130- // If dst_buffer were poisoned, it should be same as earlier.
131- if (cur < dst_end) {
132- size_t unpoisoned = CountUnpoisoned (poison_states, dst_end - cur);
133- if (unpoisoned > 0 ) {
134- assert (!__asan_address_is_poisoned (cur + unpoisoned - 1 ));
135- }
136- if (cur + unpoisoned < dst_end && poison_dst) {
137- assert (__asan_address_is_poisoned (cur + unpoisoned));
138- }
139- }
140- // Memory annotations after dst_end should be unchanged.
141- for (cur = dst_end; cur < dst_buffer_end; ++cur) {
142- assert (__asan_address_is_poisoned (cur) == poison_dst);
143- }
113+ Test (capacity, off_src, off_dst, src_buffer_beg, src_buffer_end,
114+ dst_buffer_beg, dst_buffer_end);
144115 }
145116
146- __asan_unpoison_memory_region (src_buffer. get () , src_buffer_size);
147- __asan_unpoison_memory_region (dst_buffer. get () , dst_buffer_size);
117+ __asan_unpoison_memory_region (src_buffer_beg , src_buffer_size);
118+ __asan_unpoison_memory_region (dst_buffer_beg , dst_buffer_size);
148119}
149120
150- void TestOverlappingContainers (size_t capacity, size_t off_src, size_t off_dst,
151- bool poison_whole, bool poison_dst) {
152- size_t buffer_size = capacity + off_src + off_dst + kGranularity * 3 ;
121+ static void TestOverlappingContainers (size_t capacity, size_t off_src,
122+ size_t off_dst) {
123+ // Test will copy [off_src, off_src + capacity) to [off_dst, off_dst + capacity).
124+ // Allocate buffers to have additional granule before and after tested ranges.
125+ off_src += kGranularity ;
126+ off_dst += kGranularity ;
127+ size_t buffer_size =
128+ RoundUp (std::max (off_src, off_dst) + capacity) + kGranularity ;
153129
154130 // Use unique_ptr with a custom deleter to manage the buffer
155131 std::unique_ptr<char []> buffer = std::make_unique<char []>(buffer_size);
156132
157- char *buffer_end = buffer.get () + buffer_size;
158- char *src_beg = buffer.get () + kGranularity + off_src;
159- char *dst_beg = buffer.get () + kGranularity + off_dst;
160- char *src_end = src_beg + capacity;
161- char *dst_end = dst_beg + capacity;
133+ char *buffer_beg = buffer.get ();
134+ char *buffer_end = buffer_beg + buffer_size;
135+ assert (RoundDown (buffer_beg) == buffer_beg);
162136
163137 for (int i = 0 ; i < 35 ; i++) {
164- if (poison_whole)
165- __asan_poison_memory_region (buffer.get (), buffer_size);
166- if (poison_dst)
167- __asan_poison_memory_region (dst_beg, dst_end - dst_beg);
168-
169- RandomPoison (src_beg, src_end);
170- auto poison_states = GetPoisonedState (src_beg, src_end);
171- __sanitizer_copy_contiguous_container_annotations (src_beg, src_end, dst_beg,
172- dst_end);
173- // This variable is used only when buffer ends in the middle of a granule.
174- bool can_modify_last_granule = __asan_address_is_poisoned (dst_end);
175-
176- // If whole buffer were poisoned, expected state of memory before first container
177- // is undetermined.
178- // If old buffer were not poisoned, that memory should still be unpoisoned.
179- char *cur;
180- if (!poison_whole) {
181- for (cur = buffer.get (); cur < src_beg && cur < dst_beg; ++cur) {
182- assert (!__asan_address_is_poisoned (cur));
183- }
184- }
138+ RandomPoison (buffer_beg, buffer_end);
185139
186- // Memory after end of both containers should be the same as at the beginning.
187- for (cur = (src_end > dst_end) ? src_end : dst_end; cur < buffer_end;
188- ++cur) {
189- assert (__asan_address_is_poisoned (cur) == poison_whole);
190- }
191-
192- char *next;
193- for (cur = dst_beg; cur + kGranularity <= dst_end; cur = next) {
194- next = RoundUp (cur + 1 );
195- size_t unpoisoned = CountUnpoisoned (poison_states, next - cur);
196- if (unpoisoned > 0 ) {
197- assert (!__asan_address_is_poisoned (cur + unpoisoned - 1 ));
198- }
199- if (cur + unpoisoned < next) {
200- assert (__asan_address_is_poisoned (cur + unpoisoned));
201- }
202- }
203- // [cur; dst_end) is not checked yet, if container ends in the middle of a granule.
204- // It can be poisoned, only if non-container bytes in that granule were poisoned.
205- // Otherwise, it should be unpoisoned.
206- if (cur < dst_end) {
207- size_t unpoisoned = CountUnpoisoned (poison_states, dst_end - cur);
208- if (unpoisoned > 0 ) {
209- assert (!__asan_address_is_poisoned (cur + unpoisoned - 1 ));
210- }
211- if (cur + unpoisoned < dst_end && can_modify_last_granule) {
212- assert (__asan_address_is_poisoned (cur + unpoisoned));
213- }
214- }
140+ Test (capacity, off_src, off_dst, buffer_beg, buffer_end, buffer_beg,
141+ buffer_end);
215142 }
216143
217- __asan_unpoison_memory_region (buffer. get () , buffer_size);
144+ __asan_unpoison_memory_region (buffer_beg , buffer_size);
218145}
219146
220147int main (int argc, char **argv) {
221148 int n = argc == 1 ? 64 : atoi (argv[1 ]);
222- for (size_t off_src = 0 ; off_src < kGranularity + 2 ; off_src++) {
223- for (size_t off_dst = 0 ; off_dst < kGranularity + 2 ; off_dst++) {
149+ for (size_t off_src = 0 ; off_src < kGranularity ; off_src++) {
150+ for (size_t off_dst = 0 ; off_dst < kGranularity ; off_dst++) {
224151 for (int capacity = 0 ; capacity <= n; capacity++) {
225- for (int poison_dst = 0 ; poison_dst < 2 ; ++poison_dst) {
226- for (int poison_dst = 0 ; poison_dst < 2 ; ++poison_dst) {
227- TestNonOverlappingContainers (capacity, off_src, off_dst, poison_dst,
228- poison_dst);
229- TestOverlappingContainers (capacity, off_src, off_dst, poison_dst,
230- poison_dst);
231- }
232- }
152+ TestNonOverlappingContainers (capacity, off_src, off_dst);
153+ TestOverlappingContainers (capacity, off_src, off_dst);
233154 }
234155 }
235156 }
0 commit comments