“Promote” test::Paths::Executable() to Paths::Executable()

This supports the “double handler” or “double handler with low
probability” models from https://crashpad.chromium.org/bug/143.

For crashpad_handler to be become its own client, it needs access to its
own executable path to pass to CrashpadClient::StartHandler(). This was
formerly available in the test-only test::Paths::Executable(). Bring
that function’s implementation to the non-test Paths::Executable() in
util/misc, and rename test::Paths to test::TestPaths to avoid future
confusion.

test::TestPaths must still be used to access TestDataRoot(), which does
not make any sense to non-test code.

test::TestPaths::Executable() is retained for use by tests, which most
likely prefer the fatal semantics of that function. Paths::Executable()
is not fatal because for the purposes of implementing the double
handler, a failure to locate the executable path (which may happen on
some systems in deeply-nested directory hierarchies) shouldn’t cause the
initial crashpad_handler to abort, even if it does prevent a second
crashpad_handler from being started.

Bug: crashpad:143
Test: crashpad_util_test Paths.*, crashpad_test_test TestPaths.*
Change-Id: I9f75bf61839ce51e33c9f7c0d7031cebead6a156
Reviewed-on: https://chromium-review.googlesource.com/466346
Reviewed-by: Scott Graham <scottmg@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Mark Mentovai 2017-04-03 13:53:11 -04:00 committed by Commit Bot
parent c39e4dc976
commit 4688351623
30 changed files with 205 additions and 121 deletions

View File

@ -24,10 +24,10 @@
#include "base/logging.h" #include "base/logging.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/errors.h" #include "test/errors.h"
#include "test/paths.h"
#include "test/scoped_temp_dir.h" #include "test/scoped_temp_dir.h"
#include "util/win/process_info.h" #include "test/test_paths.h"
#include "test/win/win_multiprocess.h" #include "test/win/win_multiprocess.h"
#include "util/win/process_info.h"
#include "util/win/scoped_handle.h" #include "util/win/scoped_handle.h"
#include "util/win/termination_codes.h" #include "util/win/termination_codes.h"
@ -189,7 +189,7 @@ void WaitForAllChildProcessesOf(HANDLE parent) {
} }
void StartAndUseHandler(const base::FilePath& temp_dir) { void StartAndUseHandler(const base::FilePath& temp_dir) {
base::FilePath handler_path = Paths::Executable().DirName().Append( base::FilePath handler_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("crashpad_handler.com")); FILE_PATH_LITERAL("crashpad_handler.com"));
CrashpadClient client; CrashpadClient client;
@ -280,7 +280,7 @@ TEST(CrashpadClient, StartWithSameStdoutStderr) {
void StartAndUseBrokenHandler(CrashpadClient* client) { void StartAndUseBrokenHandler(CrashpadClient* client) {
ScopedTempDir temp_dir; ScopedTempDir temp_dir;
base::FilePath handler_path = Paths::Executable().DirName().Append( base::FilePath handler_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("fake_handler_that_crashes_at_startup.exe")); FILE_PATH_LITERAL("fake_handler_that_crashes_at_startup.exe"));
ASSERT_TRUE(client->StartHandler(handler_path, ASSERT_TRUE(client->StartHandler(handler_path,
temp_dir.path(), temp_dir.path(),

View File

@ -214,9 +214,9 @@ $ adb push \
/data/local/tmp/ /data/local/tmp/
[100%] /data/local/tmp/crashpad_test_test_multiprocess_exec_test_child [100%] /data/local/tmp/crashpad_test_test_multiprocess_exec_test_child
$ adb shell mkdir -p /data/local/tmp/crashpad_test_data_root/test $ adb shell mkdir -p /data/local/tmp/crashpad_test_data_root/test
$ adb push test/paths_test_data_root.txt \ $ adb push test/test_paths_test_data_root.txt \
/data/local/tmp/crashpad_test_data_root/test/ /data/local/tmp/crashpad_test_data_root/test/
[100%] /data/local/tmp/crashpad_test_data_root/test/paths_test_data_root.txt [100%] /data/local/tmp/crashpad_test_data_root/test/test_paths_test_data_root.txt
$ adb shell $ adb shell
device:/ $ cd /data/local/tmp device:/ $ cd /data/local/tmp
device:/data/local/tmp $ CRASHPAD_TEST_DATA_ROOT=crashpad_test_data_root \ device:/data/local/tmp $ CRASHPAD_TEST_DATA_ROOT=crashpad_test_data_root \

View File

@ -20,7 +20,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "client/crashpad_client.h" #include "client/crashpad_client.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "test/win/child_launcher.h" #include "test/win/child_launcher.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/win/scoped_handle.h" #include "util/win/scoped_handle.h"
@ -88,7 +88,7 @@ int CrashOtherProgram(int argc, wchar_t* argv[]) {
} }
// Launch another process that hangs. // Launch another process that hangs.
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable = std::wstring child_test_executable =
test_executable.DirName().Append(L"hanging_program.exe").value(); test_executable.DirName().Append(L"hanging_program.exe").value();
ChildLauncher child(child_test_executable, argv[1]); ChildLauncher child(child_test_executable, argv[1]);

View File

@ -19,7 +19,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "client/crashpad_client.h" #include "client/crashpad_client.h"
#include "test/paths.h" #include "test/test_paths.h"
#if !defined(ARCH_CPU_X86) #if !defined(ARCH_CPU_X86)
#error This test is only supported on x86. #error This test is only supported on x86.
@ -43,7 +43,7 @@ int CrashyLoadZ7Main(int argc, wchar_t* argv[]) {
// The DLL has /Z7 symbols embedded in the binary (rather than in a .pdb). // The DLL has /Z7 symbols embedded in the binary (rather than in a .pdb).
// There's only an x86 version of this dll as newer x64 toolchains can't // There's only an x86 version of this dll as newer x64 toolchains can't
// generate this format any more. // generate this format any more.
base::FilePath z7_path = test::Paths::TestDataRoot().Append( base::FilePath z7_path = test::TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("handler/win/z7_test.dll")); FILE_PATH_LITERAL("handler/win/z7_test.dll"));
HMODULE z7_test = LoadLibrary(z7_path.value().c_str()); HMODULE z7_test = LoadLibrary(z7_path.value().c_str());
if (!z7_test) { if (!z7_test) {

View File

@ -21,7 +21,7 @@
#include "client/crashpad_info.h" #include "client/crashpad_info.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/errors.h" #include "test/errors.h"
#include "test/paths.h" #include "test/test_paths.h"
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
#include <dlfcn.h> #include <dlfcn.h>
@ -187,7 +187,7 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
#elif defined(OS_WIN) #elif defined(OS_WIN)
const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".dll"); const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".dll");
#endif #endif
base::FilePath module_path = Paths::Executable().DirName().Append( base::FilePath module_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("crashpad_snapshot_test_module") + kDlExtension); FILE_PATH_LITERAL("crashpad_snapshot_test_module") + kDlExtension);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
ScopedDlHandle dl_handle( ScopedDlHandle dl_handle(

View File

@ -35,7 +35,7 @@
#include "test/errors.h" #include "test/errors.h"
#include "test/mac/mach_errors.h" #include "test/mac/mach_errors.h"
#include "test/mac/mach_multiprocess.h" #include "test/mac/mach_multiprocess.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/mac/mac_util.h" #include "util/mac/mac_util.h"
#include "util/mach/exc_server_variants.h" #include "util/mach/exc_server_variants.h"
@ -50,12 +50,12 @@ namespace {
// \return The path to crashpad_snapshot_test_module_crashy_initializer.so // \return The path to crashpad_snapshot_test_module_crashy_initializer.so
std::string ModuleWithCrashyInitializer() { std::string ModuleWithCrashyInitializer() {
return Paths::Executable().value() + "_module_crashy_initializer.so"; return TestPaths::Executable().value() + "_module_crashy_initializer.so";
} }
//! \return The path to the crashpad_snapshot_test_no_op executable. //! \return The path to the crashpad_snapshot_test_no_op executable.
base::FilePath NoOpExecutable() { base::FilePath NoOpExecutable() {
return base::FilePath(Paths::Executable().value() + "_no_op"); return base::FilePath(TestPaths::Executable().value() + "_no_op");
} }
class TestMachOImageAnnotationsReader final class TestMachOImageAnnotationsReader final

View File

@ -23,7 +23,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "snapshot/win/process_snapshot_win.h" #include "snapshot/win/process_snapshot_win.h"
#include "test/errors.h" #include "test/errors.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "test/win/child_launcher.h" #include "test/win/child_launcher.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/thread/thread.h" #include "util/thread/thread.h"
@ -140,7 +140,7 @@ void TestCrashingChild(const base::string16& directory_modification) {
<< ErrorMessage("WaitForSingleObject"); << ErrorMessage("WaitForSingleObject");
// Spawn a child process, passing it the pipe name to connect to. // Spawn a child process, passing it the pipe name to connect to.
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable = std::wstring child_test_executable =
test_executable.DirName() test_executable.DirName()
.Append(directory_modification) .Append(directory_modification)
@ -248,7 +248,7 @@ void TestDumpWithoutCrashingChild(
<< ErrorMessage("WaitForSingleObject"); << ErrorMessage("WaitForSingleObject");
// Spawn a child process, passing it the pipe name to connect to. // Spawn a child process, passing it the pipe name to connect to.
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable = std::wstring child_test_executable =
test_executable.DirName() test_executable.DirName()
.Append(directory_modification) .Append(directory_modification)

View File

@ -25,7 +25,7 @@
#include "client/simple_address_range_bag.h" #include "client/simple_address_range_bag.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "snapshot/win/process_snapshot_win.h" #include "snapshot/win/process_snapshot_win.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "test/win/child_launcher.h" #include "test/win/child_launcher.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/win/process_info.h" #include "util/win/process_info.h"
@ -45,7 +45,7 @@ enum TestType {
void TestExtraMemoryRanges(TestType type, void TestExtraMemoryRanges(TestType type,
const base::string16& directory_modification) { const base::string16& directory_modification) {
// Spawn a child process, passing it the pipe name to connect to. // Spawn a child process, passing it the pipe name to connect to.
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable = std::wstring child_test_executable =
test_executable.DirName() test_executable.DirName()
.Append(directory_modification) .Append(directory_modification)

View File

@ -29,7 +29,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "snapshot/win/pe_image_reader.h" #include "snapshot/win/pe_image_reader.h"
#include "snapshot/win/process_reader_win.h" #include "snapshot/win/process_reader_win.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "test/win/child_launcher.h" #include "test/win/child_launcher.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/win/process_info.h" #include "util/win/process_info.h"
@ -49,7 +49,7 @@ enum TestType {
void TestAnnotationsOnCrash(TestType type, void TestAnnotationsOnCrash(TestType type,
const base::string16& directory_modification) { const base::string16& directory_modification) {
// Spawn a child process, passing it the pipe name to connect to. // Spawn a child process, passing it the pipe name to connect to.
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable = std::wstring child_test_executable =
test_executable.DirName() test_executable.DirName()
.Append(directory_modification) .Append(directory_modification)

View File

@ -21,7 +21,7 @@
#include "snapshot/win/pe_image_reader.h" #include "snapshot/win/pe_image_reader.h"
#include "snapshot/win/process_reader_win.h" #include "snapshot/win/process_reader_win.h"
#include "test/errors.h" #include "test/errors.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "test/win/child_launcher.h" #include "test/win/child_launcher.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/win/scoped_handle.h" #include "util/win/scoped_handle.h"
@ -38,7 +38,7 @@ void TestImageReaderChild(const base::string16& directory_modification) {
CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str())); CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str()));
ASSERT_TRUE(done.is_valid()) << ErrorMessage("CreateEvent"); ASSERT_TRUE(done.is_valid()) << ErrorMessage("CreateEvent");
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable = std::wstring child_test_executable =
test_executable.DirName() test_executable.DirName()
.Append(directory_modification) .Append(directory_modification)

View File

@ -18,7 +18,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
namespace crashpad { namespace crashpad {
@ -48,7 +48,7 @@ class TestMultiprocessExec final : public MultiprocessExec {
TEST(MultiprocessExec, MultiprocessExec) { TEST(MultiprocessExec, MultiprocessExec) {
TestMultiprocessExec multiprocess_exec; TestMultiprocessExec multiprocess_exec;
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
#if defined(OS_POSIX) #if defined(OS_POSIX)
std::string child_test_executable = test_executable.value(); std::string child_test_executable = test_executable.value();
#elif defined(OS_WIN) #elif defined(OS_WIN)

View File

@ -49,15 +49,12 @@
'multiprocess_exec_posix.cc', 'multiprocess_exec_posix.cc',
'multiprocess_exec_win.cc', 'multiprocess_exec_win.cc',
'multiprocess_posix.cc', 'multiprocess_posix.cc',
'paths.cc',
'paths.h',
'paths_linux.cc',
'paths_mac.cc',
'paths_win.cc',
'scoped_temp_dir.cc', 'scoped_temp_dir.cc',
'scoped_temp_dir.h', 'scoped_temp_dir.h',
'scoped_temp_dir_posix.cc', 'scoped_temp_dir_posix.cc',
'scoped_temp_dir_win.cc', 'scoped_temp_dir_win.cc',
'test_paths.cc',
'test_paths.h',
'win/child_launcher.cc', 'win/child_launcher.cc',
'win/child_launcher.h', 'win/child_launcher.h',
'win/win_child_process.cc', 'win/win_child_process.cc',
@ -86,13 +83,6 @@
}, },
}], }],
], ],
'target_conditions': [
['OS=="android"', {
'sources/': [
['include', '^paths_linux\\.cc$'],
],
}],
],
}, },
{ {
'target_name': 'crashpad_gtest_main', 'target_name': 'crashpad_gtest_main',

View File

@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "test/paths.h" #include "test/test_paths.h"
#include <stdlib.h> #include <stdlib.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "base/logging.h" #include "base/logging.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "util/misc/paths.h"
namespace crashpad { namespace crashpad {
namespace test { namespace test {
@ -28,7 +29,7 @@ namespace {
bool IsTestDataRoot(const base::FilePath& candidate) { bool IsTestDataRoot(const base::FilePath& candidate) {
const base::FilePath marker_path = const base::FilePath marker_path =
candidate.Append(FILE_PATH_LITERAL("test")) candidate.Append(FILE_PATH_LITERAL("test"))
.Append(FILE_PATH_LITERAL("paths_test_data_root.txt")); .Append(FILE_PATH_LITERAL("test_paths_test_data_root.txt"));
#if !defined(OS_WIN) #if !defined(OS_WIN)
struct stat stat_buf; struct stat stat_buf;
@ -59,23 +60,25 @@ base::FilePath TestDataRootInternal() {
// In a standalone build, the test executable is usually at // In a standalone build, the test executable is usually at
// out/{Debug,Release} relative to the Crashpad root. // out/{Debug,Release} relative to the Crashpad root.
const base::FilePath executable = Paths::Executable(); base::FilePath executable_path;
base::FilePath candidate = if (Paths::Executable(&executable_path)) {
base::FilePath(executable.DirName() base::FilePath candidate =
.Append(base::FilePath::kParentDirectory) base::FilePath(executable_path.DirName()
.Append(base::FilePath::kParentDirectory)); .Append(base::FilePath::kParentDirectory)
if (IsTestDataRoot(candidate)) { .Append(base::FilePath::kParentDirectory));
return candidate; if (IsTestDataRoot(candidate)) {
} return candidate;
}
// In an in-Chromium build, the test executable is usually at // In an in-Chromium build, the test executable is usually at
// out/{Debug,Release} relative to the Chromium root, and the Crashpad root is // out/{Debug,Release} relative to the Chromium root, and the Crashpad root
// at third_party/crashpad/crashpad relative to the Chromium root. // is at third_party/crashpad/crashpad relative to the Chromium root.
candidate = candidate.Append(FILE_PATH_LITERAL("third_party")) candidate = candidate.Append(FILE_PATH_LITERAL("third_party"))
.Append(FILE_PATH_LITERAL("crashpad")) .Append(FILE_PATH_LITERAL("crashpad"))
.Append(FILE_PATH_LITERAL("crashpad")); .Append(FILE_PATH_LITERAL("crashpad"));
if (IsTestDataRoot(candidate)) { if (IsTestDataRoot(candidate)) {
return candidate; return candidate;
}
} }
// If nothing else worked, use the current directory, issuing a warning if it // If nothing else worked, use the current directory, issuing a warning if it
@ -90,7 +93,14 @@ base::FilePath TestDataRootInternal() {
} // namespace } // namespace
// static // static
base::FilePath Paths::TestDataRoot() { base::FilePath TestPaths::Executable() {
base::FilePath executable_path;
CHECK(Paths::Executable(&executable_path));
return executable_path;
}
// static
base::FilePath TestPaths::TestDataRoot() {
static base::FilePath* test_data_root = static base::FilePath* test_data_root =
new base::FilePath(TestDataRootInternal()); new base::FilePath(TestDataRootInternal());
return *test_data_root; return *test_data_root;

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef CRASHPAD_TEST_PATHS_H_ #ifndef CRASHPAD_TEST_TEST_PATHS_H_
#define CRASHPAD_TEST_PATHS_H_ #define CRASHPAD_TEST_TEST_PATHS_H_
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/macros.h" #include "base/macros.h"
@ -22,9 +22,11 @@ namespace crashpad {
namespace test { namespace test {
//! \brief Functions to obtain paths from within tests. //! \brief Functions to obtain paths from within tests.
class Paths { class TestPaths {
public: public:
//! \brief Returns the pathname of the currently-running test executable. //! \brief Returns the pathname of the currently-running test executable.
//!
//! On failure, aborts execution.
static base::FilePath Executable(); static base::FilePath Executable();
//! \brief Returns the pathname of the test data root. //! \brief Returns the pathname of the test data root.
@ -40,10 +42,10 @@ class Paths {
//! files. //! files.
static base::FilePath TestDataRoot(); static base::FilePath TestDataRoot();
DISALLOW_IMPLICIT_CONSTRUCTORS(Paths); DISALLOW_IMPLICIT_CONSTRUCTORS(TestPaths);
}; };
} // namespace test } // namespace test
} // namespace crashpad } // namespace crashpad
#endif // CRASHPAD_TEST_PATHS_H_ #endif // CRASHPAD_TEST_TEST_PATHS_H_

View File

@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "test/paths.h" #include "test/test_paths.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "build/build_config.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
@ -23,22 +22,11 @@ namespace crashpad {
namespace test { namespace test {
namespace { namespace {
TEST(Paths, Executable) { TEST(TestPaths, TestDataRoot) {
base::FilePath executable_path = Paths::Executable(); base::FilePath test_data_root = TestPaths::TestDataRoot();
base::FilePath executable_name = executable_path.BaseName();
#if defined(OS_WIN)
EXPECT_EQ(FILE_PATH_LITERAL("crashpad_test_test.exe"),
executable_name.value());
#else
EXPECT_EQ("crashpad_test_test", executable_name.value());
#endif // OS_WIN
}
TEST(Paths, TestDataRoot) {
base::FilePath test_data_root = Paths::TestDataRoot();
ScopedFileHandle file(LoggingOpenFileForRead( ScopedFileHandle file(LoggingOpenFileForRead(
test_data_root.Append(FILE_PATH_LITERAL("test")) test_data_root.Append(FILE_PATH_LITERAL("test"))
.Append(FILE_PATH_LITERAL("paths_test_data_root.txt")))); .Append(FILE_PATH_LITERAL("test_paths_test_data_root.txt"))));
EXPECT_TRUE(file.is_valid()); EXPECT_TRUE(file.is_valid());
} }

View File

@ -12,5 +12,5 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
This file is used by Paths::TestDataRoot() to locate the test data root. It This file is used by TestPaths::TestDataRoot() to locate the test data root. It
is present at a known path from the test data root. is present at a known path from the test data root.

View File

@ -39,8 +39,8 @@
'main_arguments_test.cc', 'main_arguments_test.cc',
'multiprocess_exec_test.cc', 'multiprocess_exec_test.cc',
'multiprocess_posix_test.cc', 'multiprocess_posix_test.cc',
'paths_test.cc',
'scoped_temp_dir_test.cc', 'scoped_temp_dir_test.cc',
'test_paths_test.cc',
'win/win_child_process_test.cc', 'win/win_child_process_test.cc',
'win/win_multiprocess_test.cc', 'win/win_multiprocess_test.cc',
], ],

View File

@ -24,11 +24,11 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/test_paths.h"
#include "util/stdlib/string_number_conversion.h" #include "util/stdlib/string_number_conversion.h"
#include "util/string/split_string.h" #include "util/string/split_string.h"
#include "util/win/handle.h" #include "util/win/handle.h"
#include "util/win/scoped_local_alloc.h" #include "util/win/scoped_local_alloc.h"
#include "test/paths.h"
namespace crashpad { namespace crashpad {
namespace test { namespace test {
@ -70,7 +70,7 @@ ScopedKernelHANDLE LaunchCommandLine(wchar_t* command_line) {
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.dwFlags = STARTF_USESTDHANDLES;
PROCESS_INFORMATION process_info; PROCESS_INFORMATION process_info;
if (!CreateProcess(Paths::Executable().value().c_str(), if (!CreateProcess(TestPaths::Executable().value().c_str(),
&command_line[0], // This cannot be constant, per MSDN. &command_line[0], // This cannot be constant, per MSDN.
nullptr, nullptr,
nullptr, nullptr,
@ -186,7 +186,7 @@ std::unique_ptr<WinChildProcess::Handles> WinChildProcess::Launch() {
const ::testing::TestInfo* const test_info = const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info(); ::testing::UnitTest::GetInstance()->current_test_info();
std::wstring command_line = std::wstring command_line =
Paths::Executable().value() + L" " + TestPaths::Executable().value() + L" " +
base::UTF8ToUTF16(base::StringPrintf("--gtest_filter=%s.%s %s=0x%x|0x%x", base::UTF8ToUTF16(base::StringPrintf("--gtest_filter=%s.%s %s=0x%x|0x%x",
test_info->test_case_name(), test_info->test_case_name(),
test_info->name(), test_info->name(),

View File

@ -22,7 +22,6 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "util/stdlib/string_number_conversion.h" #include "util/stdlib/string_number_conversion.h"
#include "util/string/split_string.h" #include "util/string/split_string.h"
#include "test/paths.h"
namespace crashpad { namespace crashpad {
namespace test { namespace test {

40
util/misc/paths.h Normal file
View File

@ -0,0 +1,40 @@
// 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.
#ifndef CRASHPAD_UTIL_PATHS_H_
#define CRASHPAD_UTIL_PATHS_H_
#include "base/files/file_path.h"
#include "base/macros.h"
namespace crashpad {
//! \brief Functions to obtain paths.
class Paths {
public:
//! \brief Obtains the pathname of the currently-running executable.
//!
//! \param[out] path The pathname of the currently-running executable.
//!
//! \return `true` on success. `false` on failure, with a message logged.
//!
//! \note In test code, use test::TestPaths::Executable() instead.
static bool Executable(base::FilePath* path);
DISALLOW_IMPLICIT_CONSTRUCTORS(Paths);
};
} // namespace crashpad
#endif // CRASHPAD_UTIL_TEST_PATHS_H_

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "test/paths.h" #include "util/misc/paths.h"
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
@ -21,42 +21,41 @@
#include <string> #include <string>
#include "base/logging.h" #include "base/logging.h"
#include "util/misc/implicit_cast.h"
namespace crashpad { namespace crashpad {
namespace test {
// static // static
base::FilePath Paths::Executable() { bool Paths::Executable(base::FilePath* path) {
// Linux does not provide a straightforward way to size the buffer before // Linux does not provide a straightforward way to size the buffer before
// calling readlink(). Normally, the st_size field returned by lstat() could // calling readlink(). Normally, the st_size field returned by lstat() could
// be used, but this is usually zero for things in /proc. // be used, but this is usually zero for things in /proc.
// //
// The /proc filesystem does not provide any way to read “exe” links for // The /proc filesystem does not provide any way to read “exe” links for
// pathnames longer than a page. See linux-4.4.27/fs/proc/base.c // pathnames longer than a page. See linux-4.9.20/fs/proc/base.c
// do_proc_readlink(), which allocates a single page to receive the path // do_proc_readlink(), which allocates a single page to receive the path
// string. Coincidentally, the page size and PATH_MAX are normally the same // string. Coincidentally, the page size and PATH_MAX are normally the same
// value, although neither is strictly a limit on the length of a pathname. // value, although neither is strictly a limit on the length of a pathname.
// //
// On Android, the smaller of the page size and PATH_MAX actually does serve // On Android, the smaller of the page size and PATH_MAX actually does serve
// as an effective limit on the length of an executables pathname. See // as an effective limit on the length of an executables pathname. See
// Android 7.0.0 bionic/linker/linker.cpp get_executable_path(), which aborts // Android 7.1.1 bionic/linker/linker.cpp get_executable_path(), which aborts
// via __libc_fatal() if the “exe” link cant be read into a PATH_MAX-sized // via __libc_fatal() if the “exe” link cant be read into a PATH_MAX-sized
// buffer. // buffer.
std::string exe_path(std::max(implicit_cast<size_t>(sysconf(_SC_PAGESIZE)), std::string exe_path(std::max(getpagesize(), PATH_MAX),
implicit_cast<size_t>(PATH_MAX)),
std::string::value_type()); std::string::value_type());
ssize_t exe_path_len = ssize_t exe_path_len =
readlink("/proc/self/exe", &exe_path[0], exe_path.size()); readlink("/proc/self/exe", &exe_path[0], exe_path.size());
if (exe_path_len < 0) { if (exe_path_len < 0) {
PLOG(FATAL) << "readlink"; PLOG(ERROR) << "readlink";
return false;
} else if (static_cast<size_t>(exe_path_len) >= exe_path.size()) { } else if (static_cast<size_t>(exe_path_len) >= exe_path.size()) {
LOG(FATAL) << "readlink"; LOG(ERROR) << "readlink";
return false;
} }
exe_path.resize(exe_path_len); exe_path.resize(exe_path_len);
return base::FilePath(exe_path); *path = base::FilePath(exe_path);
return true;
} }
} // namespace test
} // namespace crashpad } // namespace crashpad

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "test/paths.h" #include "util/misc/paths.h"
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#include <stdint.h> #include <stdint.h>
@ -20,20 +20,25 @@
#include "base/logging.h" #include "base/logging.h"
namespace crashpad { namespace crashpad {
namespace test {
// static // static
base::FilePath Paths::Executable() { bool Paths::Executable(base::FilePath* path) {
uint32_t executable_length = 0; uint32_t executable_length = 0;
_NSGetExecutablePath(nullptr, &executable_length); _NSGetExecutablePath(nullptr, &executable_length);
CHECK_GT(executable_length, 1u); if (executable_length <= 1) {
LOG(ERROR) << "_NSGetExecutablePath";
return false;
}
std::string executable_path(executable_length - 1, std::string::value_type()); std::string executable_path(executable_length - 1, std::string::value_type());
int rv = _NSGetExecutablePath(&executable_path[0], &executable_length); int rv = _NSGetExecutablePath(&executable_path[0], &executable_length);
CHECK_EQ(rv, 0); if (rv != 0) {
LOG(ERROR) << "_NSGetExecutablePath";
return false;
}
return base::FilePath(executable_path); *path = base::FilePath(executable_path);
return true;
} }
} // namespace test
} // namespace crashpad } // namespace crashpad

39
util/misc/paths_test.cc Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2014 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/misc/paths.h"
#include "base/files/file_path.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
namespace crashpad {
namespace test {
namespace {
TEST(Paths, Executable) {
base::FilePath executable_path;
ASSERT_TRUE(Paths::Executable(&executable_path));
const base::FilePath executable_name(executable_path.BaseName());
#if defined(OS_WIN)
EXPECT_EQ(FILE_PATH_LITERAL("crashpad_util_test.exe"),
executable_name.value());
#else
EXPECT_EQ("crashpad_util_test", executable_name.value());
#endif // OS_WIN
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -12,23 +12,29 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "test/paths.h" #include "util/misc/paths.h"
#include <windows.h> #include <windows.h>
#include "base/logging.h" #include "base/logging.h"
namespace crashpad { namespace crashpad {
namespace test {
// static // static
base::FilePath Paths::Executable() { bool Paths::Executable(base::FilePath* path) {
wchar_t executable_path[_MAX_PATH]; wchar_t executable_path[_MAX_PATH];
unsigned int len = unsigned int len =
GetModuleFileName(nullptr, executable_path, arraysize(executable_path)); GetModuleFileName(nullptr, executable_path, arraysize(executable_path));
PCHECK(len != 0 && len < arraysize(executable_path)) << "GetModuleFileName"; if (len == 0) {
return base::FilePath(executable_path); PLOG(ERROR) << "GetModuleFileName";
return false;
} else if (len >= arraysize(executable_path)) {
LOG(ERROR) << "GetModuleFileName";
return false;
}
*path = base::FilePath(executable_path);
return true;
} }
} // namespace test
} // namespace crashpad } // namespace crashpad

View File

@ -17,7 +17,7 @@
#include <string.h> #include <string.h>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "util/misc/implicit_cast.h" #include "util/misc/implicit_cast.h"
#include "util/net/http_body_test_util.h" #include "util/net/http_body_test_util.h"
@ -97,7 +97,7 @@ TEST(StringHTTPBodyStream, MultipleReads) {
} }
TEST(FileHTTPBodyStream, ReadASCIIFile) { TEST(FileHTTPBodyStream, ReadASCIIFile) {
base::FilePath path = Paths::TestDataRoot().Append( base::FilePath path = TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt")); FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt"));
FileHTTPBodyStream stream(path); FileHTTPBodyStream stream(path);
std::string contents = ReadStreamToString(&stream, 32); std::string contents = ReadStreamToString(&stream, 32);
@ -115,7 +115,7 @@ TEST(FileHTTPBodyStream, ReadASCIIFile) {
TEST(FileHTTPBodyStream, ReadBinaryFile) { TEST(FileHTTPBodyStream, ReadBinaryFile) {
// HEX contents of file: |FEEDFACE A11A15|. // HEX contents of file: |FEEDFACE A11A15|.
base::FilePath path = Paths::TestDataRoot().Append( base::FilePath path = TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("util/net/testdata/binary_http_body.dat")); FILE_PATH_LITERAL("util/net/testdata/binary_http_body.dat"));
// This buffer size was chosen so that reading the file takes multiple reads. // This buffer size was chosen so that reading the file takes multiple reads.
uint8_t buf[4]; uint8_t buf[4];
@ -199,7 +199,7 @@ TEST_P(CompositeHTTPBodyStreamBufferSize, StringsAndFile) {
std::vector<HTTPBodyStream*> parts; std::vector<HTTPBodyStream*> parts;
parts.push_back(new StringHTTPBodyStream(string1)); parts.push_back(new StringHTTPBodyStream(string1));
base::FilePath path = Paths::TestDataRoot().Append( base::FilePath path = TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt")); FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt"));
parts.push_back(new FileHTTPBodyStream(path)); parts.push_back(new FileHTTPBodyStream(path));
parts.push_back(new StringHTTPBodyStream(string2)); parts.push_back(new StringHTTPBodyStream(string2));

View File

@ -20,7 +20,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/gtest_death_check.h" #include "test/gtest_death_check.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "util/net/http_body.h" #include "util/net/http_body.h"
#include "util/net/http_body_test_util.h" #include "util/net/http_body_test_util.h"
@ -100,7 +100,7 @@ TEST(HTTPMultipartBuilder, ThreeStringFields) {
TEST(HTTPMultipartBuilder, ThreeFileAttachments) { TEST(HTTPMultipartBuilder, ThreeFileAttachments) {
HTTPMultipartBuilder builder; HTTPMultipartBuilder builder;
base::FilePath ascii_http_body_path = Paths::TestDataRoot().Append( base::FilePath ascii_http_body_path = TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt")); FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt"));
builder.SetFileAttachment("first", builder.SetFileAttachment("first",
"minidump.dmp", "minidump.dmp",
@ -186,7 +186,7 @@ TEST(HTTPMultipartBuilder, OverwriteFileAttachment) {
const char kValue[] = "1 2 3 test"; const char kValue[] = "1 2 3 test";
builder.SetFormData("a key", kValue); builder.SetFormData("a key", kValue);
base::FilePath testdata_path = base::FilePath testdata_path =
Paths::TestDataRoot().Append(FILE_PATH_LITERAL("util/net/testdata")); TestPaths::TestDataRoot().Append(FILE_PATH_LITERAL("util/net/testdata"));
builder.SetFileAttachment("minidump", builder.SetFileAttachment("minidump",
"minidump.dmp", "minidump.dmp",
testdata_path.Append(FILE_PATH_LITERAL( testdata_path.Append(FILE_PATH_LITERAL(
@ -242,7 +242,7 @@ TEST(HTTPMultipartBuilder, SharedFormDataAndAttachmentKeyNamespace) {
HTTPMultipartBuilder builder; HTTPMultipartBuilder builder;
const char kValue1[] = "11111"; const char kValue1[] = "11111";
builder.SetFormData("one", kValue1); builder.SetFormData("one", kValue1);
base::FilePath ascii_http_body_path = Paths::TestDataRoot().Append( base::FilePath ascii_http_body_path = TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt")); FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt"));
builder.SetFileAttachment("minidump", builder.SetFileAttachment("minidump",
"minidump.dmp", "minidump.dmp",

View File

@ -31,7 +31,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/multiprocess_exec.h" #include "test/multiprocess_exec.h"
#include "test/paths.h" #include "test/test_paths.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/misc/random_string.h" #include "util/misc/random_string.h"
#include "util/net/http_body.h" #include "util/net/http_body.h"
@ -56,7 +56,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
body_stream_(std::move(body_stream)), body_stream_(std::move(body_stream)),
response_code_(http_response_code), response_code_(http_response_code),
request_validator_(request_validator) { request_validator_(request_validator) {
base::FilePath server_path = Paths::TestDataRoot().Append( base::FilePath server_path = TestPaths::TestDataRoot().Append(
FILE_PATH_LITERAL("util/net/http_transport_test_server.py")); FILE_PATH_LITERAL("util/net/http_transport_test_server.py"));
#if defined(OS_POSIX) #if defined(OS_POSIX)
SetChildCommand(server_path.value(), nullptr); SetChildCommand(server_path.value(), nullptr);

View File

@ -99,6 +99,10 @@
'misc/initialization_state_dcheck.h', 'misc/initialization_state_dcheck.h',
'misc/metrics.cc', 'misc/metrics.cc',
'misc/metrics.h', 'misc/metrics.h',
'misc/paths.h',
'misc/paths_mac.cc',
'misc/paths_linux.cc',
'misc/paths_win.cc',
'misc/pdb_structures.cc', 'misc/pdb_structures.cc',
'misc/pdb_structures.h', 'misc/pdb_structures.h',
'misc/random_string.cc', 'misc/random_string.cc',
@ -321,6 +325,7 @@
'target_conditions': [ 'target_conditions': [
['OS=="android"', { ['OS=="android"', {
'sources/': [ 'sources/': [
['include', '^misc/paths_linux\\.cc$'],
['include', '^posix/process_info_linux\\.cc$'], ['include', '^posix/process_info_linux\\.cc$'],
], ],
}], }],

View File

@ -62,6 +62,7 @@
'misc/clock_test.cc', 'misc/clock_test.cc',
'misc/initialization_state_dcheck_test.cc', 'misc/initialization_state_dcheck_test.cc',
'misc/initialization_state_test.cc', 'misc/initialization_state_test.cc',
'misc/paths_test.cc',
'misc/scoped_forbid_return_test.cc', 'misc/scoped_forbid_return_test.cc',
'misc/random_string_test.cc', 'misc/random_string_test.cc',
'misc/uuid_test.cc', 'misc/uuid_test.cc',

View File

@ -26,8 +26,8 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "test/errors.h" #include "test/errors.h"
#include "test/paths.h"
#include "test/scoped_temp_dir.h" #include "test/scoped_temp_dir.h"
#include "test/test_paths.h"
#include "test/win/child_launcher.h" #include "test/win/child_launcher.h"
#include "util/file/file_io.h" #include "util/file/file_io.h"
#include "util/misc/random_string.h" #include "util/misc/random_string.h"
@ -139,7 +139,7 @@ void TestOtherProcess(const base::string16& directory_modification) {
CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str())); CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str()));
ASSERT_TRUE(done.get()) << ErrorMessage("CreateEvent"); ASSERT_TRUE(done.get()) << ErrorMessage("CreateEvent");
base::FilePath test_executable = Paths::Executable(); base::FilePath test_executable = TestPaths::Executable();
std::wstring child_test_executable = std::wstring child_test_executable =
test_executable.DirName() test_executable.DirName()