Rework ElfImageReader.MainExecutableChild to not rely on fork()

Switches from test::Multiprocess to test::MultiprocessExec for
ElfImageReader.MainExecutableChild.

Uses the new child process launching, and passes the expected symbol
address from the child to the parent, rather than assuming the value
will be the same in both processes.

And, enables the test on Fuchsia since it now works.

Bug: crashpad:196, crashpad:215
Change-Id: I3b43407b6584275d61bedc9c13d1625b950fc23b
Reviewed-on: https://chromium-review.googlesource.com/884993
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Scott Graham 2018-01-25 13:37:12 -08:00 committed by Commit Bot
parent 48abd4a60f
commit 11589d9b32
5 changed files with 55 additions and 12 deletions

View File

@ -21,6 +21,7 @@
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "test/multiprocess.h"
#include "test/multiprocess_exec.h"
#include "test/process_type.h"
#include "util/file/file_io.h"
#include "util/misc/address_types.h"
@ -68,6 +69,8 @@ void LocateExecutable(ProcessType process,
sizeof(debug_address));
ASSERT_EQ(status, ZX_OK)
<< "zx_object_get_property: ZX_PROP_PROCESS_DEBUG_ADDR";
// Can be 0 if requested before the loader has loaded anything.
EXPECT_NE(debug_address, 0u);
constexpr auto k_r_debug_map_offset = offsetof(r_debug, r_map);
uintptr_t map;
@ -120,7 +123,8 @@ void ExpectSymbol(ElfImageReader* reader,
reader->GetDynamicSymbol("notasymbol", &symbol_address, &symbol_size));
}
void ReadThisExecutableInTarget(ProcessType process) {
void ReadThisExecutableInTarget(ProcessType process,
VMAddress exported_symbol_address) {
#if defined(ARCH_CPU_64_BITS)
constexpr bool am_64_bit = true;
#else
@ -139,9 +143,8 @@ void ReadThisExecutableInTarget(ProcessType process) {
ElfImageReader reader;
ASSERT_TRUE(reader.Initialize(range, elf_address));
ExpectSymbol(&reader,
"ElfImageReaderTestExportedSymbol",
FromPointerCast<VMAddress>(ElfImageReaderTestExportedSymbol));
ExpectSymbol(
&reader, "ElfImageReaderTestExportedSymbol", exported_symbol_address);
ElfImageReader::NoteReader::Result result;
std::string note_name;
@ -201,25 +204,45 @@ void ReadLibcInTarget(ProcessType process) {
}
TEST(ElfImageReader, MainExecutableSelf) {
ReadThisExecutableInTarget(GetSelfProcess());
ReadThisExecutableInTarget(
GetSelfProcess(),
FromPointerCast<VMAddress>(ElfImageReaderTestExportedSymbol));
}
#if !defined(OS_FUCHSIA) // TODO(scottmg): Port to MultiprocessExec.
class ReadExecutableChildTest : public Multiprocess {
CRASHPAD_CHILD_TEST_MAIN(ReadExecutableChild) {
VMAddress exported_symbol_address =
FromPointerCast<VMAddress>(ElfImageReaderTestExportedSymbol);
CheckedWriteFile(StdioFileHandle(StdioStream::kStandardOutput),
&exported_symbol_address,
sizeof(exported_symbol_address));
CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput));
return 0;
}
class ReadExecutableChildTest : public MultiprocessExec {
public:
ReadExecutableChildTest() : Multiprocess() {}
~ReadExecutableChildTest() {}
ReadExecutableChildTest() : MultiprocessExec() {}
private:
void MultiprocessParent() { ReadThisExecutableInTarget(ChildPID()); }
void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); }
void MultiprocessParent() {
// This read serves two purposes -- on Fuchsia, the loader may have not
// filled in debug address as soon as the child process handle is valid, so
// this causes a wait at least until the main() of the child, at which point
// it will always be valid. Secondarily, the address of the symbol to be
// looked up needs to be communicated.
VMAddress exported_symbol_address;
CheckedReadFileExactly(ReadPipeHandle(),
&exported_symbol_address,
sizeof(exported_symbol_address));
ReadThisExecutableInTarget(ChildProcess(), exported_symbol_address);
}
};
TEST(ElfImageReader, MainExecutableChild) {
ReadExecutableChildTest test;
test.SetChildTestMainFunction("ReadExecutableChild");
test.Run();
}
#endif // !OS_FUCHSIA
TEST(ElfImageReader, OneModuleSelf) {
ReadLibcInTarget(GetSelfProcess());

View File

@ -22,6 +22,7 @@
#include "base/macros.h"
#include "build/build_config.h"
#include "test/multiprocess.h"
#include "test/process_type.h"
//! \file
@ -117,6 +118,13 @@ class MultiprocessExec : public Multiprocess {
//! CRASHPAD_CHILD_TEST_MAIN().
void SetChildTestMainFunction(const std::string& function_name);
//! \brief Returns a ProcessType representing the child process.
//!
//! This method is only valid during the body of MultiprocessParent().
//!
//! \return A platform-specific type representing the child process.
ProcessType ChildProcess();
protected:
~MultiprocessExec();

View File

@ -177,5 +177,9 @@ void MultiprocessExec::MultiprocessChild() {
info()->child.reset(child);
}
ProcessType MultiprocessExec::ChildProcess() {
return info()->child.get();
}
} // namespace test
} // namespace crashpad

View File

@ -148,5 +148,9 @@ void MultiprocessExec::MultiprocessChild() {
FAIL() << ErrnoMessage("execv") << ": " << argv_[0];
}
ProcessType MultiprocessExec::ChildProcess() {
return ChildPID();
}
} // namespace test
} // namespace crashpad

View File

@ -170,5 +170,9 @@ void MultiprocessExec::MultiprocessChild() {
&info()->process_info));
}
ProcessType MultiprocessExec::ChildProcess() {
return info()->process_info.hProcess;
}
} // namespace test
} // namespace crashpad