[compiler-rt] 46df20a - [sanitizer] Add TryMemCpy (#112668)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 17 16:59:52 PDT 2024
Author: Vitaly Buka
Date: 2024-10-17T16:59:49-07:00
New Revision: 46df20ab63ee8c14c5d4eef07e2a7cccd466c064
URL: https://github.com/llvm/llvm-project/commit/46df20ab63ee8c14c5d4eef07e2a7cccd466c064
DIFF: https://github.com/llvm/llvm-project/commit/46df20ab63ee8c14c5d4eef07e2a7cccd466c064.diff
LOG: [sanitizer] Add TryMemCpy (#112668)
For posix implementation is similar to
`IsAccessibleMemoryRange`, using `pipe`.
We need this because we can't rely on non-atomic
`IsAccessibleMemoryRange` + `memcpy`, as the
protection or mapping may change and we may
crash.
Added:
Modified:
compiler-rt/lib/sanitizer_common/sanitizer_common.h
compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 082d2158e579bd..3a28420ed02d78 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -268,7 +268,13 @@ class ScopedErrorReportLock {
extern uptr stoptheworld_tracer_pid;
extern uptr stoptheworld_tracer_ppid;
+// Returns true if the entire range can be read.
bool IsAccessibleMemoryRange(uptr beg, uptr size);
+// Attempts to copy `n` bytes from memory range starting at `src` to `dest`.
+// Returns true if the entire range can be read. Returns `false` if any part of
+// the source range cannot be read, in which case the contents of `dest` are
+// undefined.
+bool TryMemCpy(void *dest, const void *src, uptr n);
// Error report formatting.
const char *StripPathPrefix(const char *filepath,
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
index 75dcf546729f6e..c2ace46c946587 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
@@ -444,6 +444,11 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
return status == ZX_OK;
}
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+ // TODO: implement.
+ return false;
+}
+
// FIXME implement on this platform.
void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
index 3ab83977a4ee23..7ee2319456d23e 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -326,6 +326,50 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
return true;
}
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+ if (!n)
+ return true;
+ int fds[2];
+ CHECK_EQ(0, pipe(fds));
+
+ auto cleanup = at_scope_exit([&]() {
+ internal_close(fds[0]);
+ internal_close(fds[1]);
+ });
+
+ SetNonBlock(fds[0]);
+ SetNonBlock(fds[1]);
+
+ char *d = static_cast<char *>(dest);
+ const char *s = static_cast<const char *>(src);
+
+ while (n) {
+ int e;
+ uptr w = internal_write(fds[1], s, n);
+ if (internal_iserror(w, &e)) {
+ if (e == EINTR)
+ continue;
+ CHECK_EQ(EFAULT, e);
+ return false;
+ }
+ s += w;
+ n -= w;
+
+ while (w) {
+ uptr r = internal_read(fds[0], d, w);
+ if (internal_iserror(r, &e)) {
+ CHECK_EQ(EINTR, e);
+ continue;
+ }
+
+ d += r;
+ w -= r;
+ }
+ }
+
+ return true;
+}
+
void PlatformPrepareForSandboxing(void *args) {
// Some kinds of sandboxes may forbid filesystem access, so we won't be able
// to read the file mappings from /proc/self/maps. Luckily, neither the
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
index 6fb947aa6d6c26..ea513d5f263fe2 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
@@ -968,6 +968,11 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
return true;
}
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+ // TODO: implement.
+ return false;
+}
+
bool SignalContext::IsStackOverflow() const {
return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW;
}
diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
index 04890f2f5e2af2..658ca60175b3bd 100644
--- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
+++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
@@ -13,11 +13,14 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_POSIX
-#include "sanitizer_common/sanitizer_common.h"
-#include "gtest/gtest.h"
+# include <pthread.h>
+# include <sys/mman.h>
-#include <pthread.h>
-#include <sys/mman.h>
+# include <algorithm>
+# include <numeric>
+
+# include "gtest/gtest.h"
+# include "sanitizer_common/sanitizer_common.h"
namespace __sanitizer {
@@ -86,6 +89,44 @@ TEST(SanitizerCommon, IsAccessibleMemoryRangeLarge) {
buffer.size()));
}
+TEST(SanitizerCommon, TryMemCpy) {
+ std::vector<char> src(10000000);
+ std::iota(src.begin(), src.end(), 123);
+ std::vector<char> dst;
+
+ // Don't use ::testing::ElementsAreArray or similar, as the huge output on an
+ // error is not helpful.
+
+ dst.assign(1, 0);
+ EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+ EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin()));
+
+ dst.assign(100, 0);
+ EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+ EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin()));
+
+ dst.assign(534, 0);
+ EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+ EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin()));
+
+ dst.assign(GetPageSize(), 0);
+ EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+ EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin()));
+
+ dst.assign(src.size(), 0);
+ EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+ EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin()));
+
+ dst.assign(src.size() - 1, 0);
+ EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
+ EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin()));
+}
+
+TEST(SanitizerCommon, TryMemCpyNull) {
+ std::vector<char> dst(100);
+ EXPECT_FALSE(TryMemCpy(dst.data(), nullptr, dst.size()));
+}
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX
More information about the llvm-commits
mailing list