Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,11 @@ class ScopedErrorReportLock {
extern uptr stoptheworld_tracer_pid;
extern uptr stoptheworld_tracer_ppid;

// Returns true if we can read a memory range.
bool IsAccessibleMemoryRange(uptr beg, uptr size);
// Returns true if we can read a memory range starting at `src`, and copies
// content into `dest`.
bool TryMemCpy(void *dest, const void *src, uptr n);

// Error report formatting.
const char *StripPathPrefix(const char *filepath,
Expand Down
5 changes: 5 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}

Expand Down
83 changes: 68 additions & 15 deletions compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,26 +288,79 @@ bool SignalContext::IsStackOverflow() const {

#endif // SANITIZER_GO

static void SetNonBlock(int fd) {
int res = fcntl(fd, F_GETFL, 0);
CHECK(!internal_iserror(res, nullptr));

res |= O_NONBLOCK;
res = fcntl(fd, F_SETFL, res);
CHECK(!internal_iserror(res, nullptr));
}

bool IsAccessibleMemoryRange(uptr beg, uptr size) {
uptr page_size = GetPageSizeCached();
// Checking too large memory ranges is slow.
CHECK_LT(size, page_size * 10);
while (size) {
// `read` from `sock_pair[0]` into a dummy buffer to free up the pipe buffer
// for more `write` is slower than just recreating a pipe.
int sock_pair[2];
if (pipe(sock_pair))
return false;

auto cleanup = at_scope_exit([&]() {
internal_close(sock_pair[0]);
internal_close(sock_pair[1]);
});

SetNonBlock(sock_pair[1]);

int write_errno;
uptr w = internal_write(sock_pair[1], reinterpret_cast<char *>(beg), size);
if (internal_iserror(w, &write_errno)) {
CHECK_EQ(EFAULT, write_errno);
return false;
}
size -= w;
beg += w;
}

return true;
}

bool TryMemCpy(void *dest, const void *src, uptr n) {
int sock_pair[2];
if (pipe(sock_pair))
return false;
uptr bytes_written =
internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
int write_errno;
bool result;
if (internal_iserror(bytes_written, &write_errno)) {
CHECK_EQ(EFAULT, write_errno);
result = false;
} else {
result = (bytes_written == size);

auto cleanup = at_scope_exit([&]() {
internal_close(sock_pair[0]);
internal_close(sock_pair[1]);
});

SetNonBlock(sock_pair[0]);
SetNonBlock(sock_pair[1]);

char *d = static_cast<char *>(dest);
const char *s = static_cast<const char *>(src);

while (n) {
int e;
uptr w = internal_write(sock_pair[1], s, n);
if (internal_iserror(w, &e)) {
CHECK_EQ(EFAULT, e);
return false;
}
s += w;
n -= w;

while (w) {
uptr r = internal_read(sock_pair[0], d, w);
CHECK(!internal_iserror(r, &e));

d += r;
w -= r;
}
}
internal_close(sock_pair[0]);
internal_close(sock_pair[1]);
return result;

return true;
}

void PlatformPrepareForSandboxing(void *args) {
Expand Down
5 changes: 5 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
56 changes: 52 additions & 4 deletions compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <numeric>

# include "gmock/gmock.h"
# include "gtest/gtest.h"
# include "sanitizer_common/sanitizer_common.h"

namespace __sanitizer {

Expand Down Expand Up @@ -82,6 +85,51 @@ TEST(SanitizerCommon, IsAccessibleMemoryRange) {
munmap((void *)mem, 3 * page_size);
}

TEST(SanitizerCommon, IsAccessibleMemoryRangeLarge) {
const int size = GetPageSize() * 10000;

uptr mem = (uptr)mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
-1, 0);

EXPECT_TRUE(IsAccessibleMemoryRange(mem, size));

munmap((void *)mem, size);
}

TEST(SanitizerCommon, TryMemCpy) {
std::vector<char> src(10000000);
std::iota(src.begin(), src.end(), 123);
std::vector<char> dst;

using ::testing::ElementsAreArray;

dst.assign(1, 0);
ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));

dst.assign(100, 0);
ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));

dst.assign(534, 0);
ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));

dst.assign(GetPageSize(), 0);
ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));

dst.assign(src.size(), 0);
ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));

dst.assign(src.size() - 1, 0);
ASSERT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size()));
EXPECT_THAT(dst, ElementsAreArray(src.data(), dst.size()));

EXPECT_FALSE(TryMemCpy(dst.data(), nullptr, dst.size()));
}

} // namespace __sanitizer

#endif // SANITIZER_POSIX
Loading