Merge master e616638c9d87 into doc

This commit is contained in:
Mark Mentovai 2016-11-01 15:01:08 -04:00
commit 6da4a15869
25 changed files with 430 additions and 85 deletions

2
DEPS
View File

@ -25,7 +25,7 @@ deps = {
'93cc6e2c23e4d5ebd179f388e67aa907d0dfd43d',
'crashpad/third_party/mini_chromium/mini_chromium':
Var('chromium_git') + '/chromium/mini_chromium@' +
'88e0a3e1a965c698d7ead8bcfc0cfb6aacdc3524',
'8e8d3cc9a245f1bf63296e97fb6ac1c90f6d86f5',
'buildtools':
Var('chromium_git') + '/chromium/buildtools.git@' +
'f8fc76ea5ce4a60cda2fa5d7df3d4a62935b3113',

View File

@ -38,7 +38,7 @@ present in the `$PATH` environment variable:
* Chromiums
https://dev.chromium.org/developers/how-tos/depottools[depot_tools].
* http://git-scm.com/[Git]. This is provided by Xcode on Mac OS X and by
* https://git-scm.com/[Git]. This is provided by Xcode on Mac OS X and by
depot_tools on Windows.
* https://www.python.org/[Python]. This is provided by the operating system on
Mac OS X, and by depot_tools on Windows.
@ -69,8 +69,8 @@ $ *cd ~/crashpad*
$ *fetch crashpad*
----
`fetch crashpad` performs the initial `gclient sync`, establishing a
fully-functional local checkout.
`fetch crashpad` performs the initial `git clone` and `gclient sync`,
establishing a fully-functional local checkout.
=== Subsequent Checkouts
@ -84,10 +84,10 @@ $ *gclient sync*
== Building
Crashpad uses https://gyp.gsrc.io/[GYP] to generate
https://martine.github.io/ninja/[Ninja] build files. The build is described by
`.gyp` files throughout the Crashpad source code tree. The
`build/gyp_crashpad.py` script runs GYP properly for Crashpad, and is also
called when you run `fetch crashpad`, `gclient sync`, or `gclient runhooks`.
https://ninja-build.org/[Ninja] build files. The build is described by `.gyp`
files throughout the Crashpad source code tree. The `build/gyp_crashpad.py`
script runs GYP properly for Crashpad, and is also called when you run `fetch
crashpad`, `gclient sync`, or `gclient runhooks`.
The Ninja build files and build output are in the `out` directory. Both debug-
and release-mode configurations are available. The examples below show the debug
@ -104,6 +104,80 @@ Ninja is part of the
https://dev.chromium.org/developers/how-tos/depottools[depot_tools]. Theres no
need to install it separately.
=== Android
Crashpads Android port is in its early stages. This build relies on
cross-compilation. Its possible to develop Crashpad for Android on any platform
that the https://developer.android.com/ndk/[Android NDK (Native Development
Kit)] runs on.
If its not already present on your system,
https://developer.android.com/ndk/downloads/[download the NDK package for your
system] and expand it to a suitable location. These instructions assume that
its been expanded to `~/android-ndk-r13`.
To build Crashpad, portions of the NDK must be reassembled into a
https://developer.android.com/ndk/guides/standalone_toolchain.html[standalone
toolchain]. This is a repackaged subset of the NDK suitable for cross-compiling
for a single Android architecture (such as `arm`, `arm64`, `x86`, and `x86_64`)
targeting a specific
https://source.android.com/source/build-numbers.html[Android API level]. The
standalone toolchain only needs to be built from the NDK one time for each set
of options desired. To build a standalone toolchain targeting 64-bit ARM and API
level 21 (Android 5.0 “Lollipop”), run:
[subs="verbatim,quotes"]
----
$ *cd ~*
$ *python android-ndk-r13/build/tools/make_standalone_toolchain.py \
--arch=arm64 --api=21 --install-dir=android-ndk-r13_arm64_api21*
----
Note that Chrome uses Android API level 21 for 64-bit platforms and 16 for
32-bit platforms. See Chromes
https://chromium.googlesource.com/chromium/src/+/master/build/config/android/config.gni[`build/config/android/config.gni`]
which sets `_android_api_level` and `_android64_api_level`.
To configure a Crashpad build for Android using this standalone toolchain,
set several environment variables directing the build to the standalone
toolchain, along with GYP options to identify an Android build. This must be
done after any `gclient sync`, or instead of any `gclient runhooks` operation.
The environment variables only need to be set for this `gyp_crashpad.py`
invocation, and need not be permanent.
[subs="verbatim,quotes"]
----
$ *cd \~/crashpad/crashpad*
$ *CC_target=\~/android-ndk-r13_arm64_api21/bin/clang \
CXX_target=\~/android-ndk-r13_arm64_api21/bin/clang++ \
AR_target=\~/android-ndk-r13_arm64_api21/bin/aarch64-linux-android-ar \
NM_target=\~/android-ndk-r13_arm64_api21/bin/aarch64-linux-android-nm \
READELF_target=~/android-ndk-r13_arm64_api21/bin/aarch64-linux-android-readelf \
python build/gyp_crashpad.py \
-DOS=android -Dtarget_arch=arm64 -Dclang=1 \
--generator-output=out_android_arm64_api21 -f ninja-android*
----
Target “triplets” to use for `ar`, `nm`, and `readelf` are:
[width="40%",cols="1,3",frame="topbot"]
|===
|`arm` |`arm-linux-androideabi`
|`arm64` |`aarch64-linux-android`
|`x86` |`i686-linux-android`
|`x86_64` |`x86_64-linux-android`
|===
The port is incomplete, but targets known to be working include `crashpad_util`,
`crashpad_test`, and `crashpad_test_test`. This list will grow over time. To
build, direct `ninja` to the specific `out` directory chosen by
`--generator-output` above.
[subs="verbatim,quotes"]
----
$ *ninja -C out_android_arm64_api21/out/Debug crashpad_test_test*
----
== Testing
Crashpad uses https://github.com/google/googletest/[Google Test] as its
@ -130,6 +204,39 @@ $ *cd ~/crashpad/crashpad*
$ *python build/run_tests.py Debug*
----
=== Android
To test on Android, use
https://developer.android.com/studio/command-line/adb.html[ADB (Android Debug
Bridge)] to `adb push` test executables and test data to a device or emulator,
then use `adb shell` to get a shell to run the test executables from. ADB is
part of the https://developer.android.com/sdk/[Android SDK]. Note that it is
sufficient to install just the command-line tools. The entire Android Studio IDE
is not necessary to obtain ADB.
This example runs `crashpad_test_test` on a device. This test executable has a
run-time dependency on a second executable and a test data file, which are also
transferred to the device prior to running the test.
[subs="verbatim,quotes"]
----
$ *cd ~/crashpad/crashpad*
$ *adb push out_android_arm64_api21/out/Debug/crashpad_test_test /data/local/tmp/*
[100%] /data/local/tmp/crashpad_test_test
$ *adb push \
out_android_arm64_api21/out/Debug/crashpad_test_test_multiprocess_exec_test_child \
/data/local/tmp/*
[100%] /data/local/tmp/crashpad_test_test_multiprocess_exec_test_child
$ *adb shell mkdir -p /data/local/tmp/crashpad_test_data_root/test*
$ *adb push test/paths_test_data_root.txt \
/data/local/tmp/crashpad_test_data_root/test/*
[100%] /data/local/tmp/crashpad_test_data_root/test/paths_test_data_root.txt
$ *adb shell*
device:/ $ *cd /data/local/tmp*
device:/data/local/tmp $ *CRASHPAD_TEST_DATA_ROOT=crashpad_test_data_root \
./crashpad_test_test*
----
== Contributing
Crashpads contribution process is very similar to
@ -139,9 +246,9 @@ process].
=== Code Review
A code review must be conducted for every change to Crashpads source code. Code
review is conducted on https://codereview.chromium.org/[Chromiums Rietveld]
system, and all code reviews must be sent to an appropriate reviewer, with a Cc
sent to
review is conducted on https://chromium-review.googlesource.com/[Chromiums
Gerrit] system, and all code reviews must be sent to an appropriate reviewer,
with a Cc sent to
https://groups.google.com/a/chromium.org/group/crashpad-dev[crashpad-dev]. The
`codereview.settings` file specifies this environment to `git-cl`.
@ -159,14 +266,18 @@ $ *git commit*
$ *git cl upload*
----
Uploading a patch to Rietveld does not automatically request a review. You must
select a reviewer and mail your request to them (with a Cc to crashpad-dev) from
the Rietveld issue page after running `git cl upload`. If you have lost track of
the issue page, `git cl issue` will remind you of its URL. Alternatively, you
can request review when uploading to Rietveld by using `git cl upload
--send-mail`
The https://polygerrit.appspot.com/[PolyGerrit interface] to Gerrit, undergoing
active development, is recommended. To switch from the classic GWT-based Gerrit
UI to PolyGerrit, click the PolyGerrit link in a Gerrit review pages footer.
Git branches maintain their association with Rietveld issues, so if you need to
Uploading a patch to Gerrit does not automatically request a review. You must
select a reviewer on the Gerrit review page after running `git cl upload`. This
action notifies your reviewer of the code review request. If you have lost track
of the review page, `git cl issue` will remind you of its URL. Alternatively,
you can request review when uploading to Gerrit by using `git cl upload
--send-mail`.
Git branches maintain their association with Gerrit reviews, so if you need to
make changes based on review feedback, you can do so on the correct Git branch,
committing your changes locally with `git commit`. You can then upload a new
patch set with `git cl upload` and let your reviewer know youve addressed the
@ -174,8 +285,8 @@ feedback.
=== Landing Changes
After code review is complete and “LGTM” (“looks good to me”) has been received
from all reviewers, project members can commit the patch themselves:
After code review is complete and “Code-Review: +1”) has been received from all
reviewers, project members can commit the patch themselves:
[subs="verbatim,quotes"]
----
@ -184,19 +295,14 @@ $ *git checkout work_branch*
$ *git cl land*
----
Alternatively, patches can be committed by clicking the “Submit” button in the
Gerrit UI.
Crashpad does not currently have a
https://dev.chromium.org/developers/testing/commit-queue[commit queue], so
contributors that are not project members will have to ask a project member to
contributors who are not project members will have to ask a project member to
commit the patch for them. Project members can commit changes on behalf of
external contributors by patching the change into a local branch and landing it:
[subs="verbatim,quotes"]
----
$ *cd ~/crashpad/crashpad*
$ *git checkout -b for_external_contributor origin/master*
$ *git cl patch 12345678* _# 12345678 is the Rietveld issue number_
$ *git cl land -c \'External Contributor <external@contributor.org>'*
----
external contributors by clicking the “Submit” button in the Gerrit UI.
=== External Contributions

View File

@ -31,7 +31,7 @@ https://chromium.googlesource.com/chromium/src/\+/cfa5b01bb1d06bf96967bd37e21a44
Initial work on a Crashpad client for
https://crashpad.chromium.org/bug/30[Android] has begun. This is currently in
the design phase.
the early implementation phase.
== Future

View File

@ -207,9 +207,12 @@ void CrashReportUploadThread::ProcessPendingReport(
// hour, and retire reports that would exceed this limit or for which the
// upload fails on the first attempt.
//
// If upload was requested explicitly (i.e. by user action), we do not
// throttle the upload.
//
// TODO(mark): Provide a proper rate-limiting strategy and allow for failed
// upload attempts to be retried.
if (rate_limit_) {
if (!report.upload_explicitly_requested && rate_limit_) {
time_t last_upload_attempt_time;
if (settings->GetLastUploadAttemptTime(&last_upload_attempt_time)) {
time_t now = time(nullptr);

View File

@ -25,6 +25,10 @@
#include "util/misc/scoped_forbid_return.h"
#include "util/posix/close_multiple.h"
#if defined(OS_LINUX)
#include <stdio_ext.h>
#endif
namespace crashpad {
namespace test {
@ -78,8 +82,14 @@ void MultiprocessExec::MultiprocessChild() {
ASSERT_NE(read_handle, STDOUT_FILENO);
ASSERT_EQ(STDIN_FILENO, fileno(stdin));
int rv = fpurge(stdin);
int rv;
#if defined(OS_LINUX)
__fpurge(stdin);
#else
rv = fpurge(stdin);
ASSERT_EQ(0, rv) << ErrnoMessage("fpurge");
#endif
rv = HANDLE_EINTR(dup2(read_handle, STDIN_FILENO));
ASSERT_EQ(STDIN_FILENO, rv) << ErrnoMessage("dup2");

View File

@ -27,6 +27,7 @@
#endif
#if defined(OS_POSIX)
#include <sys/resource.h>
#include <unistd.h>
#elif defined(OS_WIN)
#include <windows.h>
@ -37,9 +38,13 @@ int main(int argc, char* argv[]) {
// Make sure that theres nothing open at any FD higher than 3. All FDs other
// than stdin, stdout, and stderr should have been closed prior to or at
// exec().
int max_fd = std::max(static_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX);
max_fd = std::max(max_fd, getdtablesize());
for (int fd = STDERR_FILENO + 1; fd < max_fd; ++fd) {
rlimit rlimit_nofile;
if (getrlimit(RLIMIT_NOFILE, &rlimit_nofile) != 0) {
abort();
}
for (int fd = STDERR_FILENO + 1;
fd < static_cast<int>(rlimit_nofile.rlim_cur);
++fd) {
if (close(fd) == 0 || errno != EBADF) {
abort();
}

View File

@ -14,8 +14,8 @@
#include "test/multiprocess.h"
#include <signal.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <unistd.h>
#include "base/macros.h"

62
test/paths_linux.cc Normal file
View File

@ -0,0 +1,62 @@
// Copyright 2016 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 "test/paths.h"
#include <limits.h>
#include <unistd.h>
#include <algorithm>
#include <string>
#include "base/logging.h"
#include "util/misc/implicit_cast.h"
namespace crashpad {
namespace test {
// static
base::FilePath Paths::Executable() {
// Linux does not provide a straightforward way to size the buffer before
// calling readlink(). Normally, the st_size field returned by lstat() could
// be used, but this is usually zero for things in /proc.
//
// 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
// do_proc_readlink(), which allocates a single page to receive the path
// 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.
//
// 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
// Android 7.0.0 bionic/linker/linker.cpp get_executable_path(), which aborts
// via __libc_fatal() if the “exe” link cant be read into a PATH_MAX-sized
// buffer.
std::string exe_path(std::max(implicit_cast<size_t>(sysconf(_SC_PAGESIZE)),
implicit_cast<size_t>(PATH_MAX)),
std::string::value_type());
ssize_t exe_path_len =
readlink("/proc/self/exe", &exe_path[0], exe_path.size());
if (exe_path_len < 0) {
PLOG(FATAL) << "readlink";
} else if (static_cast<size_t>(exe_path_len) >= exe_path.size()) {
LOG(FATAL) << "readlink";
}
exe_path.resize(exe_path_len);
return base::FilePath(exe_path);
}
} // namespace test
} // namespace crashpad

View File

@ -26,10 +26,11 @@ namespace test {
base::FilePath Paths::Executable() {
uint32_t executable_length = 0;
_NSGetExecutablePath(nullptr, &executable_length);
DCHECK_GT(executable_length, 1u);
CHECK_GT(executable_length, 1u);
std::string executable_path(executable_length - 1, std::string::value_type());
int rv = _NSGetExecutablePath(&executable_path[0], &executable_length);
DCHECK_EQ(rv, 0);
CHECK_EQ(rv, 0);
return base::FilePath(executable_path);
}

View File

@ -16,13 +16,17 @@
#include <windows.h>
#include "base/logging.h"
namespace crashpad {
namespace test {
// static
base::FilePath Paths::Executable() {
wchar_t executable_path[_MAX_PATH];
GetModuleFileName(nullptr, executable_path, sizeof(executable_path));
unsigned int len =
GetModuleFileName(nullptr, executable_path, arraysize(executable_path));
PCHECK(len != 0 && len < arraysize(executable_path)) << "GetModuleFileName";
return base::FilePath(executable_path);
}

View File

@ -15,10 +15,12 @@
#include "test/scoped_temp_dir.h"
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "base/logging.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "test/errors.h"
@ -33,9 +35,25 @@ void ScopedTempDir::Rename() {
// static
base::FilePath ScopedTempDir::CreateTemporaryDirectory() {
char dir_template[] = "/tmp/org.chromium.crashpad.test.XXXXXX";
PCHECK(mkdtemp(dir_template)) << "mkdtemp " << dir_template;
return base::FilePath(dir_template);
char* tmpdir = getenv("TMPDIR");
std::string dir;
if (tmpdir && tmpdir[0] != '\0') {
dir.assign(tmpdir);
} else {
#if defined(OS_ANDROID)
dir.assign("/data/local/tmp");
#else
dir.assign("/tmp");
#endif
}
if (dir[dir.size() - 1] != '/') {
dir.append(1, '/');
}
dir.append("org.chromium.crashpad.test.XXXXXX");
PCHECK(mkdtemp(&dir[0])) << "mkdtemp " << dir;
return base::FilePath(dir);
}
// static

View File

@ -47,6 +47,7 @@
'multiprocess_posix.cc',
'paths.cc',
'paths.h',
'paths_linux.cc',
'paths_mac.cc',
'paths_win.cc',
'scoped_temp_dir.cc',
@ -76,6 +77,13 @@
},
}],
],
'target_conditions': [
['OS=="android"', {
'sources/': [
['include', '^paths_linux\\.cc$'],
],
}],
],
},
],
}

View File

@ -73,9 +73,19 @@ bool WeakFileHandleFileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
iovec* iov = reinterpret_cast<iovec*>(&(*iovecs)[0]);
size_t remaining_iovecs = iovecs->size();
#if defined(OS_ANDROID)
// Android does not expose the IOV_MAX macro, but makes its value available
// via sysconf(). See Android 7.0.0 bionic/libc/bionic/sysconf.cpp sysconf().
// Bionic defines IOV_MAX at bionic/libc/include/limits.h, but does not ship
// this file to the NDK as <limits.h>, substituting
// bionic/libc/include/bits/posix_limits.h.
const size_t kIovMax = sysconf(_SC_IOV_MAX);
#else
const size_t kIovMax = IOV_MAX;
#endif
while (size > 0) {
size_t writev_iovec_count =
std::min(remaining_iovecs, implicit_cast<size_t>(IOV_MAX));
size_t writev_iovec_count = std::min(remaining_iovecs, kIovMax);
ssize_t written =
HANDLE_EINTR(writev(file_handle_, iov, writev_iovec_count));
if (written < 0) {

View File

@ -14,11 +14,11 @@
#include "util/misc/clock.h"
#include <stdint.h>
#include <sys/types.h>
#include <algorithm>
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/stringprintf.h"
@ -85,8 +85,8 @@ TEST(Clock, SleepNanoseconds) {
for (size_t index = 0; index < arraysize(kTestData); ++index) {
const uint64_t nanoseconds = kTestData[index];
SCOPED_TRACE(
base::StringPrintf("index %zu, nanoseconds %llu", index, nanoseconds));
SCOPED_TRACE(base::StringPrintf(
"index %zu, nanoseconds %" PRIu64, index, nanoseconds));
TestSleepNanoseconds(nanoseconds);
}

View File

@ -18,6 +18,16 @@
#include "base/metrics/sparse_histogram.h"
#include "build/build_config.h"
#if defined(OS_MACOSX)
#define METRICS_OS_NAME "Mac"
#elif defined(OS_WIN)
#define METRICS_OS_NAME "Win"
#elif defined(OS_ANDROID)
#define METRICS_OS_NAME "Android"
#elif defined(OS_LINUX)
#define METRICS_OS_NAME "Linux"
#endif
namespace crashpad {
namespace {
@ -79,12 +89,7 @@ void Metrics::ExceptionCaptureResult(CaptureResult result) {
// static
void Metrics::ExceptionCode(uint32_t exception_code) {
#if defined(OS_WIN)
static const char kExceptionCodeString[] = "Crashpad.ExceptionCode.Win";
#elif defined(OS_MACOSX)
static const char kExceptionCodeString[] = "Crashpad.ExceptionCode.Mac";
#endif
UMA_HISTOGRAM_SPARSE_SLOWLY(kExceptionCodeString,
UMA_HISTOGRAM_SPARSE_SLOWLY("Crashpad.ExceptionCode." METRICS_OS_NAME,
static_cast<int32_t>(exception_code));
}
@ -94,15 +99,9 @@ void Metrics::ExceptionEncountered() {
}
void Metrics::HandlerCrashed(uint32_t exception_code) {
#if defined(OS_WIN)
static const char kExceptionCodeString[] =
"Crashpad.HandlerCrash.ExceptionCode.Win";
#elif defined(OS_MACOSX)
static const char kExceptionCodeString[] =
"Crashpad.HandlerCrash.ExceptionCode.Mac";
#endif
UMA_HISTOGRAM_SPARSE_SLOWLY(kExceptionCodeString,
static_cast<int32_t>(exception_code));
UMA_HISTOGRAM_SPARSE_SLOWLY(
"Crashpad.HandlerCrash.ExceptionCode." METRICS_OS_NAME,
static_cast<int32_t>(exception_code));
}
} // namespace crashpad

View File

@ -23,6 +23,7 @@
#include <string.h>
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_byteorder.h"
@ -109,6 +110,16 @@ bool UUID::InitializeWithNew() {
return false;
}
InitializeFromSystemUUID(&system_uuid);
return true;
#elif defined(OS_LINUX) || defined(OS_ANDROID)
// Linux does not provide a UUID generator in a widely-available system
// library. uuid_generate() from libuuid is not available everywhere.
base::RandBytes(this, sizeof(*this));
// Set six bits per RFC 4122 §4.4 to identify this as a pseudo-random UUID.
data_3 = (4 << 12) | (data_3 & 0x0fff); // §4.1.3
data_4[0] = 0x80 | (data_4[0] & 0x3f); // §4.1.1
return true;
#else
#error Port.

View File

@ -122,7 +122,7 @@ TEST(CheckedAddressRange, IsValid) {
for (size_t index = 0; index < arraysize(kTestData); ++index) {
const TestData& testcase = kTestData[index];
SCOPED_TRACE(base::StringPrintf("index %" PRIuS
", base 0x%llx, size 0x%llx",
", base 0x%" PRIx64 ", size 0x%" PRIx64,
index,
testcase.base,
testcase.size));
@ -173,7 +173,7 @@ TEST(CheckedAddressRange, ContainsValue) {
for (size_t index = 0; index < arraysize(kTestData); ++index) {
const TestData& testcase = kTestData[index];
SCOPED_TRACE(base::StringPrintf(
"index %" PRIuS ", value 0x%llx", index, testcase.value));
"index %" PRIuS ", value 0x%" PRIx64, index, testcase.value));
EXPECT_EQ(testcase.expectation,
parent_range_32.ContainsValue(testcase.value));
@ -230,7 +230,7 @@ TEST(CheckedAddressRange, ContainsRange) {
for (size_t index = 0; index < arraysize(kTestData); ++index) {
const TestData& testcase = kTestData[index];
SCOPED_TRACE(base::StringPrintf("index %" PRIuS
", base 0x%llx, size 0x%llx",
", base 0x%" PRIx64 ", size 0x%" PRIx64,
index,
testcase.base,
testcase.size));

View File

@ -18,6 +18,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -25,12 +26,17 @@
#include <algorithm>
#include <memory>
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
#include "util/misc/implicit_cast.h"
#include "util/numeric/safe_assignment.h"
#if defined(OS_MACOSX)
#include <sys/sysctl.h>
#endif
// Everything in this file is expected to execute between fork() and exec(),
// so everything called here must be acceptable in this context. However,
// logging code that is not expected to execute under normal circumstances is
@ -82,7 +88,7 @@ using ScopedDIR = std::unique_ptr<DIR, ScopedDIRCloser>;
bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) {
#if defined(OS_MACOSX)
const char kFDDir[] = "/dev/fd";
#elif defined(OS_LINUX)
#elif defined(OS_LINUX) || defined(OS_ANDROID)
const char kFDDir[] = "/proc/self/fd";
#endif
@ -100,10 +106,19 @@ bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) {
return false;
}
dirent entry;
dirent* result;
int rv;
while ((rv = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) {
#if defined(OS_LINUX)
// readdir_r() is deprecated as of glibc 2.24. See
// https://sourceware.org/bugzilla/show_bug.cgi?id=19056 and
// https://git.kernel.org/cgit/docs/man-pages/man-pages.git/commit?id=0c52f6d623636a61eacd0f7b7a3bb942793a2a05.
const char kReaddirName[] = "readdir";
while ((errno = 0, result = readdir(dir)) != nullptr)
#else
const char kReaddirName[] = "readdir_r";
dirent entry;
while ((errno = readdir_r(dir, &entry, &result)) == 0 && result != nullptr)
#endif
{
const char* entry_name = &(*result->d_name);
if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) {
continue;
@ -127,6 +142,11 @@ bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) {
}
}
if (errno != 0) {
PLOG(WARNING) << kReaddirName;
return false;
}
return true;
}
@ -141,12 +161,68 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) {
// systems file descriptor limit. Check a few values and use the highest as
// the limit, because these may be based on the file descriptor limit set by
// setrlimit(), and higher-numbered file descriptors may have been opened
// prior to the limit being lowered. For Mac OS X, see 10.9.2
// Libc-997.90.3/gen/FreeBSD/sysconf.c sysconf() and 10.9.4
// xnu-2422.110.17/bsd/kern/kern_descrip.c getdtablesize(), which both return
// the current RLIMIT_NOFILE value, not the maximum possible file descriptor.
int max_fd = std::max(implicit_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX);
// prior to the limit being lowered. On both macOS and Linux glibc, both
// sysconf() and getdtablesize() return the current RLIMIT_NOFILE value, not
// the maximum possible file descriptor. For macOS, see 10.11.5
// Libc-1082.50.1/gen/FreeBSD/sysconf.c sysconf() and 10.11.6
// xnu-3248.60.10/bsd/kern/kern_descrip.c getdtablesize(). For Linux glibc,
// see glibc-2.24/sysdeps/posix/sysconf.c __sysconf() and
// glibc-2.24/sysdeps/posix/getdtsz.c __getdtablesize(). For Android, see
// 7.0.0 bionic/libc/bionic/sysconf.cpp sysconf() and
// bionic/libc/bionic/ndk_cruft.cpp getdtablesize().
int max_fd = implicit_cast<int>(sysconf(_SC_OPEN_MAX));
#if !defined(OS_ANDROID)
// getdtablesize() was removed effective Android 5.0.0 (API 21). Since it
// returns the same thing as the sysconf() above, just skip it. See
// https://android.googlesource.com/platform/bionic/+/462abab12b074c62c0999859e65d5a32ebb41951.
max_fd = std::max(max_fd, getdtablesize());
#endif
#if !defined(OS_LINUX) || defined(OPEN_MAX)
// Linux does not provide OPEN_MAX. See
// https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/include/linux/limits.h?id=77293034696e3e0b6c8b8fc1f96be091104b3d2b.
max_fd = std::max(max_fd, OPEN_MAX);
#endif
// Consult a sysctl to determine the system-wide limit on the maximum number
// of open files per process. Note that it is possible to change this limit
// while the system is running, but its still a better upper bound than the
// current RLIMIT_NOFILE value.
#if defined(OS_MACOSX)
// See 10.11.6 xnu-3248.60.10/bsd/kern/kern_resource.c maxfilesperproc,
// referenced by dosetrlimit().
int oid[] = {CTL_KERN, KERN_MAXFILESPERPROC};
int maxfilesperproc;
size_t maxfilesperproc_size = sizeof(maxfilesperproc);
if (sysctl(oid,
arraysize(oid),
&maxfilesperproc,
&maxfilesperproc_size,
nullptr,
0) == 0) {
max_fd = std::max(max_fd, maxfilesperproc);
} else {
PLOG(WARNING) << "sysctl";
}
#elif defined(OS_LINUX) || defined(OS_ANDROID)
// See linux-4.4.27/fs/file.c sysctl_nr_open, referenced by kernel/sys.c
// do_prlimit() and kernel/sysctl.c fs_table. Inability to open this file is
// not considered an error, because /proc may not be available or usable.
{
base::ScopedFILE nr_open_file(fopen("/proc/sys/fs/nr_open", "r"));
if (nr_open_file.get() != nullptr) {
int nr_open;
if (fscanf(nr_open_file.get(), "%d\n", &nr_open) == 1 &&
feof(nr_open_file.get())) {
max_fd = std::max(max_fd, nr_open);
} else {
LOG(WARNING) << "/proc/sys/fs/nr_open format error";
}
}
}
#endif
for (int entry_fd = fd; entry_fd < max_fd; ++entry_fd) {
if (entry_fd != preserve_fd) {

View File

@ -71,7 +71,7 @@ void DropPrivileges() {
CHECK_EQ(setegid(egid), -1);
}
}
#elif defined(OS_LINUX)
#elif defined(OS_LINUX) || defined(OS_ANDROID)
PCHECK(setresgid(gid, gid, gid) == 0) << "setresgid";
PCHECK(setresuid(uid, uid, uid) == 0) << "setresuid";

View File

@ -15,7 +15,6 @@
#ifndef CRASHPAD_UTIL_POSIX_PROCESS_INFO_H_
#define CRASHPAD_UTIL_POSIX_PROCESS_INFO_H_
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
@ -30,6 +29,7 @@
#if defined(OS_MACOSX)
#include <mach/mach.h>
#include <sys/sysctl.h>
#endif
namespace crashpad {

View File

@ -15,12 +15,14 @@
#include "util/posix/process_info.h"
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <set>
#include <string>
#include <vector>
#include "base/files/scoped_file.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "test/errors.h"
@ -98,6 +100,34 @@ void TestSelfProcess(const ProcessInfo& process_info) {
#if defined(OS_MACOSX)
int expect_argc = *_NSGetArgc();
char** expect_argv = *_NSGetArgv();
#elif defined(OS_LINUX) || defined(OS_ANDROID)
std::vector<std::string> expect_arg_vector;
{
base::ScopedFILE cmdline(fopen("/proc/self/cmdline", "r"));
ASSERT_NE(nullptr, cmdline.get()) << ErrnoMessage("fopen");
int expect_arg_char;
std::string expect_arg_string;
while ((expect_arg_char = fgetc(cmdline.get())) != EOF) {
if (expect_arg_char != '\0') {
expect_arg_string.append(1, expect_arg_char);
} else {
expect_arg_vector.push_back(expect_arg_string);
expect_arg_string.clear();
}
}
ASSERT_EQ(0, ferror(cmdline.get())) << ErrnoMessage("fgetc");
ASSERT_TRUE(expect_arg_string.empty());
}
std::vector<const char*> expect_argv_storage;
for (const std::string& expect_arg_string : expect_arg_vector) {
expect_argv_storage.push_back(expect_arg_string.c_str());
}
int expect_argc = expect_argv_storage.size();
const char* const* expect_argv =
!expect_argv_storage.empty() ? &expect_argv_storage[0] : nullptr;
#else
#error Obtain expect_argc and expect_argv correctly on your system.
#endif

View File

@ -14,9 +14,9 @@
#include "util/posix/symbolic_constants_posix.h"
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/signal.h>
#include "base/macros.h"
#include "base/strings/stringprintf.h"
@ -64,7 +64,7 @@ const char* kSignalNames[] = {
"INFO",
"USR1",
"USR2",
#elif defined(OS_LINUX)
#elif defined(OS_LINUX) || defined(OS_ANDROID)
// sed -Ene 's/^#define[[:space:]]SIG([[:alnum:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/ "\1",/p'
// /usr/include/asm-generic/signal.h
// and fix up by removing SIGIOT, SIGLOST, SIGUNUSED, and SIGRTMIN.
@ -101,7 +101,7 @@ const char* kSignalNames[] = {
"SYS",
#endif
};
#if defined(OS_LINUX)
#if defined(OS_LINUX) || defined(OS_ANDROID)
// NSIG is 64 to account for real-time signals.
static_assert(arraysize(kSignalNames) == 32, "kSignalNames length");
#else

View File

@ -14,7 +14,7 @@
#include "util/posix/symbolic_constants_posix.h"
#include <sys/signal.h>
#include <signal.h>
#include <sys/types.h>
#include "base/macros.h"
@ -65,7 +65,7 @@ const struct {
#if defined(OS_MACOSX)
{SIGEMT, "SIGEMT", "EMT"},
{SIGINFO, "SIGINFO", "INFO"},
#elif defined(OS_LINUX)
#elif defined(OS_LINUX) || defined(OS_ANDROID)
{SIGPWR, "SIGPWR", "PWR"},
{SIGSTKFLT, "SIGSTKFLT", "STKFLT"},
#endif
@ -120,7 +120,7 @@ TEST(SymbolicConstantsPOSIX, SignalToString) {
kSignalTestData[index].short_name);
}
#if defined(OS_LINUX)
#if defined(OS_LINUX) || defined(OS_ANDROID)
// NSIG is 64 to account for real-time signals.
const int kSignalCount = 32;
#else

View File

@ -103,6 +103,7 @@ struct StringToUnsignedIntTraits
: public StringToUnsignedIntegerTraits<unsigned int, unsigned long> {
static LongType Convert(const char* str, char** end, int base) {
if (str[0] == '-') {
*end = const_cast<char*>(str);
return 0;
}
return strtoul(str, end, base);
@ -113,6 +114,7 @@ struct StringToUnsignedInt64Traits
: public StringToUnsignedIntegerTraits<uint64_t, uint64_t> {
static LongType Convert(const char* str, char** end, int base) {
if (str[0] == '-') {
*end = const_cast<char*>(str);
return 0;
}
return strtoull(str, end, base);

View File

@ -46,14 +46,14 @@ class ThreadLogMessagesMaster {
}
~ThreadLogMessagesMaster() {
DCHECK_EQ(logging::GetLogMessageHandler(), LogMessageHandler);
DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler);
logging::SetLogMessageHandler(nullptr);
tls_.Free();
}
void SetThreadMessageList(std::vector<std::string>* message_list) {
DCHECK_EQ(logging::GetLogMessageHandler(), LogMessageHandler);
DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler);
DCHECK_NE(tls_.Get() != nullptr, message_list != nullptr);
tls_.Set(message_list);
}