Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(399)

Unified Diff: third_party/crashpad/crashpad/util/linux/process_memory_test.cc

Issue 2804713002: Update Crashpad to b4095401639ebe2ad33169e5c1d994065cbff1b8 (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crashpad/crashpad/util/linux/process_memory_test.cc
diff --git a/third_party/crashpad/crashpad/util/linux/process_memory_test.cc b/third_party/crashpad/crashpad/util/linux/process_memory_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e00134a75e0e924dfb18bdd0d83773b99681d821
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/linux/process_memory_test.cc
@@ -0,0 +1,403 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// 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 "util/linux/process_memory.h"
+
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include "gtest/gtest.h"
+#include "test/errors.h"
+#include "test/multiprocess.h"
+#include "util/file/file_io.h"
+#include "util/posix/scoped_mmap.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+class TargetProcessTest : public Multiprocess {
+ public:
+ TargetProcessTest() : Multiprocess() {}
+ ~TargetProcessTest() {}
+
+ void RunAgainstSelf() { DoTest(getpid()); }
+
+ void RunAgainstForked() { Run(); }
+
+ private:
+ void MultiprocessParent() override { DoTest(ChildPID()); }
+
+ void MultiprocessChild() override { CheckedReadFileAtEOF(ReadPipeHandle()); }
+
+ virtual void DoTest(pid_t pid) = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(TargetProcessTest);
+};
+
+class ReadTest : public TargetProcessTest {
+ public:
+ ReadTest()
+ : TargetProcessTest(),
+ page_size_(getpagesize()),
+ region_size_(4 * page_size_),
+ region_(new char[region_size_]) {
+ for (size_t index = 0; index < region_size_; ++index) {
+ region_[index] = index % 256;
+ }
+ }
+
+ private:
+ void DoTest(pid_t pid) override {
+ ProcessMemory memory;
+ ASSERT_TRUE(memory.Initialize(pid));
+
+ LinuxVMAddress address = reinterpret_cast<LinuxVMAddress>(region_.get());
+ std::unique_ptr<char[]> result(new char[region_size_]);
+
+ // Ensure that the entire region can be read.
+ ASSERT_TRUE(memory.Read(address, region_size_, result.get()));
+ EXPECT_EQ(memcmp(region_.get(), result.get(), region_size_), 0);
+
+ // Ensure that a read of length 0 succeeds and doesn’t touch the result.
+ memset(result.get(), '\0', region_size_);
+ ASSERT_TRUE(memory.Read(address, 0, result.get()));
+ for (size_t i = 0; i < region_size_; ++i) {
+ EXPECT_EQ(result[i], 0);
+ }
+
+ // Ensure that a read starting at an unaligned address works.
+ ASSERT_TRUE(memory.Read(address + 1, region_size_ - 1, result.get()));
+ EXPECT_EQ(memcmp(region_.get() + 1, result.get(), region_size_ - 1), 0);
+
+ // Ensure that a read ending at an unaligned address works.
+ ASSERT_TRUE(memory.Read(address, region_size_ - 1, result.get()));
+ EXPECT_EQ(memcmp(region_.get(), result.get(), region_size_ - 1), 0);
+
+ // Ensure that a read starting and ending at unaligned addresses works.
+ ASSERT_TRUE(memory.Read(address + 1, region_size_ - 2, result.get()));
+ EXPECT_EQ(memcmp(region_.get() + 1, result.get(), region_size_ - 2), 0);
+
+ // Ensure that a read of exactly one page works.
+ ASSERT_TRUE(memory.Read(address + page_size_, page_size_, result.get()));
+ EXPECT_EQ(memcmp(region_.get() + page_size_, result.get(), page_size_), 0);
+
+ // Ensure that reading exactly a single byte works.
+ result[1] = 'J';
+ ASSERT_TRUE(memory.Read(address + 2, 1, result.get()));
+ EXPECT_EQ(result[0], region_[2]);
+ EXPECT_EQ(result[1], 'J');
+ }
+
+ const size_t page_size_;
+ const size_t region_size_;
+ std::unique_ptr<char[]> region_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadTest);
+};
+
+TEST(ProcessMemory, ReadSelf) {
+ ReadTest test;
+ test.RunAgainstSelf();
+}
+
+TEST(ProcessMemory, ReadForked) {
+ ReadTest test;
+ test.RunAgainstForked();
+}
+
+bool ReadCString(const ProcessMemory& memory,
+ const char* pointer,
+ std::string* result) {
+ return memory.ReadCString(reinterpret_cast<LinuxVMAddress>(pointer), result);
+}
+
+bool ReadCStringSizeLimited(const ProcessMemory& memory,
+ const char* pointer,
+ size_t size,
+ std::string* result) {
+ return memory.ReadCStringSizeLimited(
+ reinterpret_cast<LinuxVMAddress>(pointer), size, result);
+}
+
+const char kConstCharEmpty[] = "";
+const char kConstCharShort[] = "A short const char[]";
+
+class ReadCStringTest : public TargetProcessTest {
+ public:
+ ReadCStringTest(bool limit_size)
+ : TargetProcessTest(),
+ member_char_empty_(""),
+ member_char_short_("A short member char[]"),
+ limit_size_(limit_size) {
+ const size_t kStringLongSize = 4 * getpagesize();
+ for (size_t index = 0; index < kStringLongSize; ++index) {
+ string_long_.push_back((index % 255) + 1);
+ }
+ EXPECT_EQ(string_long_.size(), kStringLongSize);
+ }
+
+ private:
+ void DoTest(pid_t pid) override {
+ ProcessMemory memory;
+ ASSERT_TRUE(memory.Initialize(pid));
+
+ std::string result;
+
+ if (limit_size_) {
+ ASSERT_TRUE(ReadCStringSizeLimited(
+ memory, kConstCharEmpty, arraysize(kConstCharEmpty), &result));
+ EXPECT_EQ(result, kConstCharEmpty);
+
+ ASSERT_TRUE(ReadCStringSizeLimited(
+ memory, kConstCharShort, arraysize(kConstCharShort), &result));
+ EXPECT_EQ(result, kConstCharShort);
+ EXPECT_FALSE(ReadCStringSizeLimited(
+ memory, kConstCharShort, arraysize(kConstCharShort) - 1, &result));
+
+ ASSERT_TRUE(ReadCStringSizeLimited(
+ memory, member_char_empty_, strlen(member_char_empty_) + 1, &result));
+ EXPECT_EQ(result, member_char_empty_);
+
+ ASSERT_TRUE(ReadCStringSizeLimited(
+ memory, member_char_short_, strlen(member_char_short_) + 1, &result));
+ EXPECT_EQ(result, member_char_short_);
+ EXPECT_FALSE(ReadCStringSizeLimited(
+ memory, member_char_short_, strlen(member_char_short_), &result));
+
+ ASSERT_TRUE(ReadCStringSizeLimited(
+ memory, string_long_.c_str(), string_long_.size() + 1, &result));
+ EXPECT_EQ(result, string_long_);
+ EXPECT_FALSE(ReadCStringSizeLimited(
+ memory, string_long_.c_str(), string_long_.size(), &result));
+ } else {
+ ASSERT_TRUE(ReadCString(memory, kConstCharEmpty, &result));
+ EXPECT_EQ(result, kConstCharEmpty);
+
+ ASSERT_TRUE(ReadCString(memory, kConstCharShort, &result));
+ EXPECT_EQ(result, kConstCharShort);
+
+ ASSERT_TRUE(ReadCString(memory, member_char_empty_, &result));
+ EXPECT_EQ(result, member_char_empty_);
+
+ ASSERT_TRUE(ReadCString(memory, member_char_short_, &result));
+ EXPECT_EQ(result, member_char_short_);
+
+ ASSERT_TRUE(ReadCString(memory, string_long_.c_str(), &result));
+ EXPECT_EQ(result, string_long_);
+ }
+ }
+
+ std::string string_long_;
+ const char* member_char_empty_;
+ const char* member_char_short_;
+ const bool limit_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadCStringTest);
+};
+
+TEST(ProcessMemory, ReadCStringSelf) {
+ ReadCStringTest test(/* limit_size= */ false);
+ test.RunAgainstSelf();
+}
+
+TEST(ProcessMemory, ReadCStringForked) {
+ ReadCStringTest test(/* limit_size= */ false);
+ test.RunAgainstForked();
+}
+
+TEST(ProcessMemory, ReadCStringSizeLimitedSelf) {
+ ReadCStringTest test(/* limit_size= */ true);
+ test.RunAgainstSelf();
+}
+
+TEST(ProcessMemory, ReadCStringSizeLimitedForked) {
+ ReadCStringTest test(/* limit_size= */ true);
+ test.RunAgainstForked();
+}
+
+class ReadUnmappedTest : public TargetProcessTest {
+ public:
+ ReadUnmappedTest()
+ : TargetProcessTest(),
+ page_size_(getpagesize()),
+ region_size_(2 * page_size_),
+ result_(new char[region_size_]) {
+ if (!pages_.ResetMmap(nullptr,
+ region_size_,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1,
+ 0)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ char* region = pages_.addr_as<char*>();
+ for (size_t index = 0; index < region_size_; ++index) {
+ region[index] = index % 256;
+ }
+
+ EXPECT_TRUE(pages_.ResetAddrLen(region, page_size_));
+ }
+
+ private:
+ void DoTest(pid_t pid) override {
+ ProcessMemory memory;
+ ASSERT_TRUE(memory.Initialize(pid));
+
+ LinuxVMAddress page_addr1 = pages_.addr_as<LinuxVMAddress>();
+ LinuxVMAddress page_addr2 = page_addr1 + page_size_;
+
+ EXPECT_TRUE(memory.Read(page_addr1, page_size_, result_.get()));
+ EXPECT_TRUE(memory.Read(page_addr2 - 1, 1, result_.get()));
+
+ EXPECT_FALSE(memory.Read(page_addr1, region_size_, result_.get()));
+ EXPECT_FALSE(memory.Read(page_addr2, page_size_, result_.get()));
+ EXPECT_FALSE(memory.Read(page_addr2 - 1, 2, result_.get()));
+ }
+
+ ScopedMmap pages_;
+ const size_t page_size_;
+ const size_t region_size_;
+ std::unique_ptr<char[]> result_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadUnmappedTest);
+};
+
+TEST(ProcessMemory, ReadUnmappedSelf) {
+ ReadUnmappedTest test;
+ ASSERT_FALSE(testing::Test::HasFailure());
+ test.RunAgainstSelf();
+}
+
+TEST(ProcessMemory, ReadUnmappedForked) {
+ ReadUnmappedTest test;
+ ASSERT_FALSE(testing::Test::HasFailure());
+ test.RunAgainstForked();
+}
+
+class ReadCStringUnmappedTest : public TargetProcessTest {
+ public:
+ ReadCStringUnmappedTest(bool limit_size)
+ : TargetProcessTest(),
+ page_size_(getpagesize()),
+ region_size_(2 * page_size_),
+ limit_size_(limit_size) {
+ if (!pages_.ResetMmap(nullptr,
+ region_size_,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1,
+ 0)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ char* region = pages_.addr_as<char*>();
+ for (size_t index = 0; index < region_size_; ++index) {
+ region[index] = 1 + index % 255;
+ }
+
+ // A string at the start of the mapped region
+ string1_ = region;
+ string1_[expected_length_] = '\0';
+
+ // A string near the end of the mapped region
+ string2_ = region + page_size_ - expected_length_ * 2;
+ string2_[expected_length_] = '\0';
+
+ // A string that crosses from the mapped into the unmapped region
+ string3_ = region + page_size_ - expected_length_ + 1;
+ string3_[expected_length_] = '\0';
+
+ // A string entirely in the unmapped region
+ string4_ = region + page_size_ + 10;
+ string4_[expected_length_] = '\0';
+
+ result_.reserve(expected_length_ + 1);
+
+ EXPECT_TRUE(pages_.ResetAddrLen(region, page_size_));
+ }
+
+ private:
+ void DoTest(pid_t pid) {
+ ProcessMemory memory;
+ ASSERT_TRUE(memory.Initialize(pid));
+
+ if (limit_size_) {
+ ASSERT_TRUE(ReadCStringSizeLimited(
+ memory, string1_, expected_length_ + 1, &result_));
+ EXPECT_EQ(result_, string1_);
+ ASSERT_TRUE(ReadCStringSizeLimited(
+ memory, string2_, expected_length_ + 1, &result_));
+ EXPECT_EQ(result_, string2_);
+ EXPECT_FALSE(ReadCStringSizeLimited(
+ memory, string3_, expected_length_ + 1, &result_));
+ EXPECT_FALSE(ReadCStringSizeLimited(
+ memory, string4_, expected_length_ + 1, &result_));
+ } else {
+ ASSERT_TRUE(ReadCString(memory, string1_, &result_));
+ EXPECT_EQ(result_, string1_);
+ ASSERT_TRUE(ReadCString(memory, string2_, &result_));
+ EXPECT_EQ(result_, string2_);
+ EXPECT_FALSE(ReadCString(memory, string3_, &result_));
+ EXPECT_FALSE(ReadCString(memory, string4_, &result_));
+ }
+ }
+
+ std::string result_;
+ ScopedMmap pages_;
+ const size_t page_size_;
+ const size_t region_size_;
+ static const size_t expected_length_ = 10;
+ char* string1_;
+ char* string2_;
+ char* string3_;
+ char* string4_;
+ const bool limit_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReadCStringUnmappedTest);
+};
+
+TEST(ProcessMemory, ReadCStringUnmappedSelf) {
+ ReadCStringUnmappedTest test(/* limit_size= */ false);
+ ASSERT_FALSE(testing::Test::HasFailure());
+ test.RunAgainstSelf();
+}
+
+TEST(ProcessMemory, ReadCStringUnmappedForked) {
+ ReadCStringUnmappedTest test(/* limit_size= */ false);
+ ASSERT_FALSE(testing::Test::HasFailure());
+ test.RunAgainstForked();
+}
+
+TEST(ProcessMemory, ReadCStringSizeLimitedUnmappedSelf) {
+ ReadCStringUnmappedTest test(/* limit_size= */ true);
+ ASSERT_FALSE(testing::Test::HasFailure());
+ test.RunAgainstSelf();
+}
+
+TEST(ProcessMemory, ReadCStringSizeLimitedUnmappedForked) {
+ ReadCStringUnmappedTest test(/* limit_size= */ true);
+ ASSERT_FALSE(testing::Test::HasFailure());
+ test.RunAgainstForked();
+}
+
+} // namespace
+} // namespace test
+} // namespace crashpad

Powered by Google App Engine
This is Rietveld 408576698