Skip to content

Commit 7106de9

Browse files
authored
[sanitizer] Add MemCpyAccessible (#112794)
A layer over `TryMemCpy` to copy only available pages.
1 parent 46df20a commit 7106de9

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size);
275275
// the source range cannot be read, in which case the contents of `dest` are
276276
// undefined.
277277
bool TryMemCpy(void *dest, const void *src, uptr n);
278+
// Copies accessible memory, and zero fill inaccessible.
279+
void MemCpyAccessible(void *dest, const void *src, uptr n);
278280

279281
// Error report formatting.
280282
const char *StripPathPrefix(const char *filepath,

compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,32 @@ static void StopStackDepotBackgroundThread() {
219219
static void StopStackDepotBackgroundThread() {}
220220
#endif
221221

222+
void MemCpyAccessible(void *dest, const void *src, uptr n) {
223+
if (TryMemCpy(dest, src, n))
224+
return;
225+
226+
const uptr page_size = GetPageSize();
227+
uptr b = reinterpret_cast<uptr>(src);
228+
uptr b_up = RoundUpTo(b, page_size);
229+
230+
uptr e = reinterpret_cast<uptr>(src) + n;
231+
uptr e_down = RoundDownTo(e, page_size);
232+
233+
auto copy_or_zero = [dest, src](uptr beg, uptr end) {
234+
const uptr udest = reinterpret_cast<uptr>(dest);
235+
const uptr usrc = reinterpret_cast<uptr>(src);
236+
void *d = reinterpret_cast<void *>(udest + (beg - usrc));
237+
const uptr size = end - beg;
238+
if (!TryMemCpy(d, reinterpret_cast<void *>(beg), size))
239+
internal_memset(d, 0, size);
240+
};
241+
242+
copy_or_zero(b, b_up);
243+
for (uptr p = b_up; p < e_down; p += page_size)
244+
copy_or_zero(p, p + page_size);
245+
copy_or_zero(e_down, e);
246+
}
247+
222248
} // namespace __sanitizer
223249

224250
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,

compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,43 @@ TEST(SanitizerCommon, TryMemCpyNull) {
127127
EXPECT_FALSE(TryMemCpy(dst.data(), nullptr, dst.size()));
128128
}
129129

130+
TEST(SanitizerCommon, MemCpyAccessible) {
131+
const int page_num = 1000;
132+
const int page_size = GetPageSize();
133+
InternalMmapVector<char> src(page_num * page_size);
134+
std::iota(src.begin(), src.end(), 123);
135+
std::vector<char> dst;
136+
std::vector<char> exp = {src.begin(), src.end()};
137+
138+
// Protect some pages.
139+
for (int i = 7; i < page_num; i *= 2) {
140+
mprotect(src.data() + i * page_size, page_size, PROT_NONE);
141+
std::fill(exp.data() + i * page_size, exp.data() + (i + 1) * page_size, 0);
142+
}
143+
144+
dst.assign(src.size(), 0);
145+
EXPECT_FALSE(TryMemCpy(dst.data(), src.data(), dst.size()));
146+
147+
// Full page aligned range with mprotect pages.
148+
dst.assign(src.size(), 0);
149+
MemCpyAccessible(dst.data(), src.data(), dst.size());
150+
EXPECT_TRUE(std::equal(dst.begin(), dst.end(), exp.begin()));
151+
152+
// Misaligned range with mprotect pages.
153+
size_t offb = 3;
154+
size_t offe = 7;
155+
dst.assign(src.size() - offb - offe, 0);
156+
MemCpyAccessible(dst.data(), src.data() + offb, dst.size());
157+
EXPECT_TRUE(std::equal(dst.begin(), dst.end(), exp.begin() + offb));
158+
159+
// Misaligned range with ends in mprotect pages.
160+
offb = 3 + 7 * page_size;
161+
offe = 7 + 14 * page_size;
162+
dst.assign(src.size() - offb - offe, 0);
163+
MemCpyAccessible(dst.data(), src.data() + offb, dst.size());
164+
EXPECT_TRUE(std::equal(dst.begin(), dst.end(), exp.begin() + offb));
165+
}
166+
130167
} // namespace __sanitizer
131168

132169
#endif // SANITIZER_POSIX

0 commit comments

Comments
 (0)