Rework ReadCString[SizeLimited](Self|Forked) to not use fork()

Instead of using pointers shared between the parent/child due to fork,
explicitly builds and passes them between processes. This is
unfortunately a bit more verbose, but seems like it tests functionality
a little better, and is required to have the test work on Fuchsia.

Also renames the ...Forked to ...Child to be correct after the change
from Multiprocess to MultiprocessExec.

Bug: crashpad:196, crashpad:215
Change-Id: I610a7f1e35b6513805c27d9e610f7a9b9820cabc
Reviewed-on: https://chromium-review.googlesource.com/892286
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Scott Graham 2018-01-30 10:16:57 -08:00 committed by Commit Bot
parent ec71b63d6f
commit 693ff6d550

View File

@ -147,6 +147,181 @@ TEST(ProcessMemory, ReadChild) {
test.RunAgainstChild();
}
constexpr char kConstCharEmpty[] = "";
constexpr char kConstCharShort[] = "A short const char[]";
#define SHORT_LOCAL_STRING "A short local variable char[]"
std::string MakeLongString() {
std::string long_string;
const size_t kStringLongSize = 4 * getpagesize();
for (size_t index = 0; index < kStringLongSize; ++index) {
long_string.push_back((index % 255) + 1);
}
EXPECT_EQ(long_string.size(), kStringLongSize);
return long_string;
}
void DoChildCStringReadTestSetup(const char** const_empty,
const char** const_short,
const char** local_empty,
const char** local_short,
std::string* long_string) {
*const_empty = kConstCharEmpty;
*const_short = kConstCharShort;
*local_empty = "";
*local_short = SHORT_LOCAL_STRING;
*long_string = MakeLongString();
}
CRASHPAD_CHILD_TEST_MAIN(ReadCStringTestChild) {
const char* const_empty;
const char* const_short;
const char* local_empty;
const char* local_short;
std::string long_string;
DoChildCStringReadTestSetup(
&const_empty, &const_short, &local_empty, &local_short, &long_string);
const auto write_address = [](const char* p) {
VMAddress address = FromPointerCast<VMAddress>(p);
CheckedWriteFile(StdioFileHandle(StdioStream::kStandardOutput),
&address,
sizeof(address));
};
write_address(const_empty);
write_address(const_short);
write_address(local_empty);
write_address(local_short);
write_address(long_string.c_str());
CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput));
return 0;
}
class ReadCStringTest : public MultiprocessExec {
public:
ReadCStringTest(bool limit_size)
: MultiprocessExec(), limit_size_(limit_size) {
SetChildTestMainFunction("ReadCStringTestChild");
}
void RunAgainstSelf() {
const char* const_empty;
const char* const_short;
const char* local_empty;
const char* local_short;
std::string long_string;
DoChildCStringReadTestSetup(
&const_empty, &const_short, &local_empty, &local_short, &long_string);
DoTest(GetSelfProcess(),
FromPointerCast<VMAddress>(const_empty),
FromPointerCast<VMAddress>(const_short),
FromPointerCast<VMAddress>(local_empty),
FromPointerCast<VMAddress>(local_short),
FromPointerCast<VMAddress>(long_string.c_str()));
}
void RunAgainstChild() { Run(); }
private:
void MultiprocessParent() override {
#define DECLARE_AND_READ_ADDRESS(name) \
VMAddress name; \
ASSERT_TRUE(ReadFileExactly(ReadPipeHandle(), &name, sizeof(name)));
DECLARE_AND_READ_ADDRESS(const_empty_address);
DECLARE_AND_READ_ADDRESS(const_short_address);
DECLARE_AND_READ_ADDRESS(local_empty_address);
DECLARE_AND_READ_ADDRESS(local_short_address);
DECLARE_AND_READ_ADDRESS(long_string_address);
#undef DECLARE_AND_READ_ADDRESS
DoTest(ChildProcess(),
const_empty_address,
const_short_address,
local_empty_address,
local_short_address,
long_string_address);
}
void DoTest(ProcessType process,
VMAddress const_empty_address,
VMAddress const_short_address,
VMAddress local_empty_address,
VMAddress local_short_address,
VMAddress long_string_address) {
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(process));
std::string result;
if (limit_size_) {
ASSERT_TRUE(memory.ReadCStringSizeLimited(
const_empty_address, arraysize(kConstCharEmpty), &result));
EXPECT_EQ(result, kConstCharEmpty);
ASSERT_TRUE(memory.ReadCStringSizeLimited(
const_short_address, arraysize(kConstCharShort), &result));
EXPECT_EQ(result, kConstCharShort);
EXPECT_FALSE(memory.ReadCStringSizeLimited(
const_short_address, arraysize(kConstCharShort) - 1, &result));
ASSERT_TRUE(
memory.ReadCStringSizeLimited(local_empty_address, 1, &result));
EXPECT_EQ(result, "");
ASSERT_TRUE(memory.ReadCStringSizeLimited(
local_short_address, strlen(SHORT_LOCAL_STRING) + 1, &result));
EXPECT_EQ(result, SHORT_LOCAL_STRING);
EXPECT_FALSE(memory.ReadCStringSizeLimited(
local_short_address, strlen(SHORT_LOCAL_STRING), &result));
std::string long_string_for_comparison = MakeLongString();
ASSERT_TRUE(memory.ReadCStringSizeLimited(
long_string_address, long_string_for_comparison.size() + 1, &result));
EXPECT_EQ(result, long_string_for_comparison);
EXPECT_FALSE(memory.ReadCStringSizeLimited(
long_string_address, long_string_for_comparison.size(), &result));
} else {
ASSERT_TRUE(memory.ReadCString(const_empty_address, &result));
EXPECT_EQ(result, kConstCharEmpty);
ASSERT_TRUE(memory.ReadCString(const_short_address, &result));
EXPECT_EQ(result, kConstCharShort);
ASSERT_TRUE(memory.ReadCString(local_empty_address, &result));
EXPECT_EQ(result, "");
ASSERT_TRUE(memory.ReadCString(local_short_address, &result));
EXPECT_EQ(result, SHORT_LOCAL_STRING);
ASSERT_TRUE(memory.ReadCString(long_string_address, &result));
EXPECT_EQ(result, MakeLongString());
}
}
const bool limit_size_;
DISALLOW_COPY_AND_ASSIGN(ReadCStringTest);
};
TEST(ProcessMemory, ReadCStringSelf) {
ReadCStringTest test(/* limit_size= */ false);
test.RunAgainstSelf();
}
TEST(ProcessMemory, ReadCStringChild) {
ReadCStringTest test(/* limit_size= */ false);
test.RunAgainstChild();
}
TEST(ProcessMemory, ReadCStringSizeLimitedSelf) {
ReadCStringTest test(/* limit_size= */ true);
test.RunAgainstSelf();
}
TEST(ProcessMemory, ReadCStringSizeLimitedChild) {
ReadCStringTest test(/* limit_size= */ true);
test.RunAgainstChild();
}
// TODO(scottmg): Need to be ported to MultiprocessExec and not rely on fork().
#if !defined(OS_FUCHSIA)
@ -183,102 +358,6 @@ bool ReadCStringSizeLimited(const ProcessMemory& memory,
FromPointerCast<VMAddress>(pointer), size, result);
}
constexpr char kConstCharEmpty[] = "";
constexpr 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 {
ProcessMemoryNative 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()