"base/hex_dump.cc",
"base/logging.cc",
"base/mutex.cc",
+ "base/safe_copy.cc",
"base/scoped_arena_allocator.cc",
"base/scoped_flock.cc",
"base/stringpiece.cc",
"base/hex_dump_test.cc",
"base/histogram_test.cc",
"base/mutex_test.cc",
+ "base/safe_copy_test.cc",
"base/scoped_flock_test.cc",
"base/time_utils_test.cc",
"base/timing_logger_test.cc",
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "safe_copy.h"
+
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include <android-base/macros.h>
+
+namespace art {
+
+ssize_t SafeCopy(void *dst, const void *src, size_t len) {
+#if defined(__linux__)
+ struct iovec dst_iov = {
+ .iov_base = dst,
+ .iov_len = len,
+ };
+ struct iovec src_iov = {
+ .iov_base = const_cast<void*>(src),
+ .iov_len = len,
+ };
+
+ ssize_t rc = process_vm_readv(getpid(), &dst_iov, 1, &src_iov, 1, 0);
+ if (rc == -1) {
+ return 0;
+ }
+ return rc;
+#else
+ UNUSED(dst, src, len);
+ return -1;
+#endif
+}
+
+} // namespace art
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_BASE_SAFE_COPY_H_
+#define ART_RUNTIME_BASE_SAFE_COPY_H_
+
+#include <sys/types.h>
+
+namespace art {
+
+// Safely dereference a pointer.
+// Returns -1 if safe copy isn't implemented on the platform, 0 if src is unreadable.
+ssize_t SafeCopy(void *dst, const void *src, size_t len);
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_SAFE_COPY_H_
--- /dev/null
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "safe_copy.h"
+
+#include "common_runtime_test.h"
+
+#include <sys/mman.h>
+#include <sys/user.h>
+
+namespace art {
+
+#if defined(__linux__)
+
+TEST(SafeCopyTest, smoke) {
+ // Map two pages, and mark the second one as PROT_NONE.
+ void* map = mmap(nullptr, PAGE_SIZE * 2, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, map);
+ char* page1 = static_cast<char*>(map);
+ ASSERT_EQ(0, mprotect(page1 + PAGE_SIZE, PAGE_SIZE, PROT_NONE));
+
+ page1[0] = 'a';
+ page1[PAGE_SIZE - 1] = 'z';
+
+ char buf[PAGE_SIZE];
+
+ // Completely valid read.
+ memset(buf, 0xCC, sizeof(buf));
+ EXPECT_EQ(static_cast<ssize_t>(PAGE_SIZE), SafeCopy(buf, page1, PAGE_SIZE));
+ EXPECT_EQ(0, memcmp(buf, page1, PAGE_SIZE));
+
+ // Reading off of the end.
+ memset(buf, 0xCC, sizeof(buf));
+ EXPECT_EQ(static_cast<ssize_t>(PAGE_SIZE - 1), SafeCopy(buf, page1 + 1, PAGE_SIZE));
+ EXPECT_EQ(0, memcmp(buf, page1 + 1, PAGE_SIZE - 1));
+
+ // Completely invalid.
+ EXPECT_EQ(0, SafeCopy(buf, page1 + PAGE_SIZE, PAGE_SIZE));
+ ASSERT_EQ(0, munmap(map, PAGE_SIZE * 2));
+}
+
+#endif // defined(__linux__)
+
+} // namespace art