From bf52da0f1bc1fddf55a8ca4fc7ba8f01d48c5f37 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 21 Jun 2017 01:17:58 -0700 Subject: [PATCH 01/30] posix: Fix Semaphore::TimedWait wait time TimedWait is implemented using `sem_timedwait` which waits until an absolute time (time since the epoch) has passed. Previously, the time to wait (relative to now) was passed without adding the current time. Change-Id: I3c169d5b107b8263577c21a8f47dc504058bd708 Reviewed-on: https://chromium-review.googlesource.com/540984 Commit-Queue: Joshua Peraza Reviewed-by: Mark Mentovai --- util/synchronization/semaphore_posix.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/util/synchronization/semaphore_posix.cc b/util/synchronization/semaphore_posix.cc index c781e4c6..9696e9da 100644 --- a/util/synchronization/semaphore_posix.cc +++ b/util/synchronization/semaphore_posix.cc @@ -15,6 +15,7 @@ #include "util/synchronization/semaphore.h" #include +#include #include @@ -25,6 +26,19 @@ namespace crashpad { #if !defined(OS_MACOSX) +namespace { + +void AddTimespec(const timespec& ts1, const timespec& ts2, timespec* result) { + result->tv_sec = ts1.tv_sec + ts2.tv_sec; + result->tv_nsec = ts1.tv_nsec + ts2.tv_nsec; + if (result->tv_nsec > static_cast(1E9)) { + ++result->tv_sec; + result->tv_nsec -= static_cast(1E9); + } +} + +} // namespace + Semaphore::Semaphore(int value) { PCHECK(sem_init(&semaphore_, 0, value) == 0) << "sem_init"; } @@ -45,9 +59,15 @@ bool Semaphore::TimedWait(double seconds) { return true; } + timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) { + PLOG(ERROR) << "clock_gettime"; + return false; + } timespec timeout; timeout.tv_sec = seconds; timeout.tv_nsec = (seconds - trunc(seconds)) * 1E9; + AddTimespec(current_time, timeout, &timeout); int rv = HANDLE_EINTR(sem_timedwait(&semaphore_, &timeout)); PCHECK(rv == 0 || errno == ETIMEDOUT) << "sem_timedwait"; From d2d10d1dc8f3e714b3e6e0776cc464862fe33fa4 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 21 Jun 2017 10:46:34 -0400 Subject: [PATCH 02/30] posix: Use std::trunc() from instead of trunc() Change-Id: Ief90846020a4fea46e5008e8ddff5825d23ce8b9 Reviewed-on: https://chromium-review.googlesource.com/543216 Reviewed-by: Joshua Peraza --- util/synchronization/semaphore_posix.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/synchronization/semaphore_posix.cc b/util/synchronization/semaphore_posix.cc index 9696e9da..0dd8c26e 100644 --- a/util/synchronization/semaphore_posix.cc +++ b/util/synchronization/semaphore_posix.cc @@ -66,7 +66,7 @@ bool Semaphore::TimedWait(double seconds) { } timespec timeout; timeout.tv_sec = seconds; - timeout.tv_nsec = (seconds - trunc(seconds)) * 1E9; + timeout.tv_nsec = (seconds - std::trunc(seconds)) * 1E9; AddTimespec(current_time, timeout, &timeout); int rv = HANDLE_EINTR(sem_timedwait(&semaphore_, &timeout)); From 7819ecbed662061eadd60c543dafe54cd32930ca Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Thu, 22 Jun 2017 16:46:26 -0400 Subject: [PATCH 03/30] posix: Use trunc() from instead of std::trunc() This folow-up to d2d10d1dc8f3 is for compatibility with 32-bit Android platforms using NDK API 16. isinf() is also caught up in the switch. Change-Id: I652e27061c01afa3dd932f494cc4eeaca4236f40 Reviewed-on: https://chromium-review.googlesource.com/544238 Reviewed-by: Joshua Peraza --- util/synchronization/semaphore_posix.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/util/synchronization/semaphore_posix.cc b/util/synchronization/semaphore_posix.cc index 0dd8c26e..f6e8bea1 100644 --- a/util/synchronization/semaphore_posix.cc +++ b/util/synchronization/semaphore_posix.cc @@ -15,10 +15,9 @@ #include "util/synchronization/semaphore.h" #include +#include #include -#include - #include "base/logging.h" #include "base/posix/eintr_wrapper.h" @@ -54,7 +53,7 @@ void Semaphore::Wait() { bool Semaphore::TimedWait(double seconds) { DCHECK_GE(seconds, 0.0); - if (std::isinf(seconds)) { + if (isinf(seconds)) { Wait(); return true; } @@ -66,7 +65,7 @@ bool Semaphore::TimedWait(double seconds) { } timespec timeout; timeout.tv_sec = seconds; - timeout.tv_nsec = (seconds - std::trunc(seconds)) * 1E9; + timeout.tv_nsec = (seconds - trunc(seconds)) * 1E9; AddTimespec(current_time, timeout, &timeout); int rv = HANDLE_EINTR(sem_timedwait(&semaphore_, &timeout)); From f37b382687c0353785a94a993a6ac75198013720 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 26 Jun 2017 17:20:26 -0400 Subject: [PATCH 04/30] linux/android: Reenable util test, and enable snapshot test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 107fb7631788 added the snapshot library as a dependency of crashpad_util_test. Most of snapshot has not yet been ported to Linux or Android. snapshot/capture_memory.cc only supports x86 and x86_64, and will #error on other CPUs. We don’t build for other CPUs on Mac or Windows, but we do for Android. To make it easy to run crashpad_util_test on non-x86 again, conditionally remove capture_memory.cc on Linux and Android. crashpad_snapshot_test can be enabled for Linux and Android too by disabling the CrashpadInfoClientOptions tests which require OS support. There’s not much left in crashpad_snapshot_test currently for Linux except for CPUContextX86 and ProcessSnapshotMinidump.EmptyFile, but both pass. Bug: crashpad:30 Change-Id: Ic19a79932072710c69a296bc0156cbe5656b8cb3 Reviewed-on: https://chromium-review.googlesource.com/549116 Reviewed-by: Joshua Peraza --- snapshot/snapshot.gyp | 6 ++++++ snapshot/snapshot_test.gyp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 667ca2cc..7150cdc5 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -130,6 +130,12 @@ ], }, }], + ['OS=="linux" or OS=="android"', { + 'sources!': [ + 'capture_memory.cc', + 'capture_memory.h', + ], + }], ] }, { diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index b31b0601..ad58defa 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -107,6 +107,11 @@ 'crashpad_snapshot_test_image_reader_module', ], }], + ['OS=="linux" or OS=="android"', { + 'sources!': [ + 'crashpad_info_client_options_test.cc', + ], + }], ], }, { From a8493c9b3148654d4e885e2a09124f0adad9333e Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 26 Jun 2017 18:09:35 -0400 Subject: [PATCH 05/30] android: Fix FloatContext::NativeFpxregs for x86 with unified headers user_fxsr_struct is only used in traditional NDK headers. Unified headers always use user_fpxregs_struct regardless of API level. Bug: crashpad:30, b/63025548 Change-Id: Id9d350801e659673b136e6fb8c0cbbbeb6055c4b Reviewed-on: https://chromium-review.googlesource.com/549376 Reviewed-by: Joshua Peraza --- util/linux/thread_info.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/util/linux/thread_info.h b/util/linux/thread_info.h index e9eeff31..9cb77d06 100644 --- a/util/linux/thread_info.h +++ b/util/linux/thread_info.h @@ -220,7 +220,10 @@ union FloatContext { } f64; #if defined(ARCH_CPU_X86) -#if defined(OS_ANDROID) && __ANDROID_API__ <= 19 +// __ANDROID_API_N__ is a proxy for determining whether unified headers are in +// use. It’s only defined by unified headers. Unified headers call this +// structure user_fpxregs_struct regardless of API level. +#if defined(OS_ANDROID) && __ANDROID_API__ <= 19 && !defined(__ANDROID_API_N__) using NativeFpxregs = user_fxsr_struct; #else using NativeFpxregs = user_fpxregs_struct; From 376cddee9eea5c0cf827893dc1c721956ef2ba9b Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 27 Jun 2017 11:17:08 -0400 Subject: [PATCH 06/30] doc: Update for NDK r15b Change-Id: I5a9104d6dcfa74ce2aadd8f62dbef47e2d56d73f Reviewed-on: https://chromium-review.googlesource.com/550355 Reviewed-by: Joshua Peraza --- doc/developing.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/developing.md b/doc/developing.md index 6a4c4fd1..6b2a9e4e 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -119,7 +119,7 @@ Kit)](https://developer.android.com/ndk/) runs on. If it’s not already present on your system, [download the NDK package for your system](https://developer.android.com/ndk/downloads/) and expand it to a suitable location. These instructions assume that it’s been expanded to -`~/android-ndk-r14`. +`~/android-ndk-r15b`. To build Crashpad, portions of the NDK must be reassembled into a [standalone toolchain](https://developer.android.com/ndk/guides/standalone_toolchain.html). @@ -133,8 +133,8 @@ desired. To build a standalone toolchain targeting 64-bit ARM and API level 21 ``` $ cd ~ -$ python android-ndk-r14/build/tools/make_standalone_toolchain.py \ - --arch=arm64 --api=21 --install-dir=android-ndk-r14_arm64_api21 +$ python android-ndk-r15b/build/tools/make_standalone_toolchain.py \ + --arch=arm64 --api=21 --install-dir=android-ndk-r15b_arm64_api21 ``` Note that Chrome uses Android API level 21 for 64-bit platforms and 16 for @@ -152,7 +152,7 @@ operation. ``` $ cd ~/crashpad/crashpad $ python build/gyp_crashpad_android.py \ - --ndk ~/android-ndk-r14_arm64_api21 \ + --ndk ~/android-ndk-r15b_arm64_api21 \ --generator-output out/android_arm64_api21 ``` From 6823f6783082faee54da823623ad4a01edcd1865 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 27 Jun 2017 11:13:16 -0400 Subject: [PATCH 07/30] Limit alignas to 64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although GCC will silently accept larger alignments with __attribute__((aligned())), it warn on alignas() with an alignment larger than the target’s supported maximum. 8c35d92ae403 switched to alignas() where possible. The maxima are at least 128 on x86, x86_64, and arm64, and 64 on arm, in the common configurations, but may be even larger with certain features such as AVX enabled. These are ultimately derived from BIGGEST_ALIGNMENT in gcc/config/*/*.h. One alignment request in a test specified 1024 as a big alignment constraint, solely as a test that alignment worked correctly. For this, it’s perfectly reasonable to limit the alignment request to what GCC supports on the most constrained target we’ll encounter. Test: crashapd_util_test AlignedAllocator.AlignedVector Change-Id: I42af443f437e01228934ab34dc04983742f0ab3f Reviewed-on: https://chromium-review.googlesource.com/550236 Reviewed-by: Scott Graham Commit-Queue: Mark Mentovai --- util/stdlib/aligned_allocator_test.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/util/stdlib/aligned_allocator_test.cc b/util/stdlib/aligned_allocator_test.cc index 4a018f58..d52dcfa2 100644 --- a/util/stdlib/aligned_allocator_test.cc +++ b/util/stdlib/aligned_allocator_test.cc @@ -52,10 +52,10 @@ TEST(AlignedAllocator, AlignedVector) { IsAligned(&natural_aligned_vector[2], alignof(NaturalAlignedStruct))); // Test a structure that declares its own alignment. - struct alignas(32) AlignedStruct { + struct alignas(16) AlignedStruct { int i; }; - ASSERT_EQ(alignof(AlignedStruct), 32u); + ASSERT_EQ(alignof(AlignedStruct), 16u); AlignedVector aligned_vector; aligned_vector.push_back(AlignedStruct()); @@ -69,15 +69,15 @@ TEST(AlignedAllocator, AlignedVector) { // Try a custom alignment. Since the structure itself doesn’t specify an // alignment constraint, only the base address will be aligned to the // requested boundary. - AlignedVector custom_aligned_vector; + AlignedVector custom_aligned_vector; custom_aligned_vector.push_back(NaturalAlignedStruct()); - EXPECT_TRUE(IsAligned(&custom_aligned_vector[0], 64)); + EXPECT_TRUE(IsAligned(&custom_aligned_vector[0], 32)); // Try a structure with a pretty big alignment request. - struct alignas(1024) BigAlignedStruct { + struct alignas(64) BigAlignedStruct { int i; }; - ASSERT_EQ(alignof(BigAlignedStruct), 1024u); + ASSERT_EQ(alignof(BigAlignedStruct), 64u); AlignedVector big_aligned_vector; big_aligned_vector.push_back(BigAlignedStruct()); From 3d6f7bcf90f5a27558c4c8cbab3bd2f00ad165aa Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 28 Jun 2017 15:57:45 -0400 Subject: [PATCH 08/30] Enable x86 optimizations for zlib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were intended to be enabled previously, but GYP uses “ia32” and “x64” for x86 and x86_64, and zlib.gyp erroneously used “x86” and “amd64” instead. In order to make this work, gcc and clang need -mpclmul to enable the pclmul extension used by crc_folding.c. The optimized code will only be used if, at runtime, SSE2, SSE4.2, and PCLMULQDQ support is detected. Change-Id: Ic709cd2a6c38892083c44c4004573a64b3581eb5 Reviewed-on: https://chromium-review.googlesource.com/553337 Reviewed-by: Robert Sesek Commit-Queue: Mark Mentovai --- third_party/zlib/zlib.gyp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/third_party/zlib/zlib.gyp b/third_party/zlib/zlib.gyp index f92cdf26..b6a6bc91 100644 --- a/third_party/zlib/zlib.gyp +++ b/third_party/zlib/zlib.gyp @@ -103,10 +103,20 @@ 'zlib_crashpad.h', ], 'conditions': [ - ['target_arch=="x86" or target_arch=="amd64"', { + ['target_arch=="ia32" or target_arch=="x64"', { 'sources!': [ 'zlib/simd_stub.c', ], + 'cflags': [ + '-msse4.2', + '-mpclmul', + ], + 'xcode_settings': { + 'OTHER_CFLAGS': [ + '-msse4.2', + '-mpclmul', + ], + }, }, { 'sources!': [ 'zlib/crc_folding.c', From 13e8672410d8170fb509b1af2ebc2634e9648744 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 28 Jun 2017 17:30:00 -0400 Subject: [PATCH 09/30] Update mini_chromium to ee67585e3115982282b86e210939ead1791e696d ee67585e3115 linux: Switch between x86 and x86_64 with the target_arch GYP variable Bug: crashpad:30 Change-Id: Ia7860cda42daae698a179b65d22ef7897141de59 Reviewed-on: https://chromium-review.googlesource.com/553557 Reviewed-by: Robert Sesek Commit-Queue: Mark Mentovai --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 742430d5..f4136874 100644 --- a/DEPS +++ b/DEPS @@ -38,7 +38,7 @@ deps = { 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '723e840a2f100a525f7feaad2e93df31d701780a', + 'ee67585e3115982282b86e210939ead1791e696d', 'crashpad/third_party/zlib/zlib': Var('chromium_git') + '/chromium/src/third_party/zlib@' + '13dc246a58e4b72104d35f9b1809af95221ebda7', From 1c87c92932d05f613c385e6e6ac2ba7a2242b251 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Thu, 29 Jun 2017 15:18:45 -0700 Subject: [PATCH 10/30] linux: Add ProcessMemoryRange to restrict memory reads to a range Bug: crashpad:30 Change-Id: I0debf3b47d0f79c5c5397e5ad2faf760191381ec Reviewed-on: https://chromium-review.googlesource.com/553657 Commit-Queue: Joshua Peraza Reviewed-by: Mark Mentovai --- util/linux/process_memory_range.cc | 93 ++++++++++++++++++ util/linux/process_memory_range.h | 123 ++++++++++++++++++++++++ util/linux/process_memory_range_test.cc | 91 ++++++++++++++++++ util/util.gyp | 2 + util/util_test.gyp | 1 + 5 files changed, 310 insertions(+) create mode 100644 util/linux/process_memory_range.cc create mode 100644 util/linux/process_memory_range.h create mode 100644 util/linux/process_memory_range_test.cc diff --git a/util/linux/process_memory_range.cc b/util/linux/process_memory_range.cc new file mode 100644 index 00000000..bdf9adca --- /dev/null +++ b/util/linux/process_memory_range.cc @@ -0,0 +1,93 @@ +// 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_range.h" + +#include +#include + +#include "base/logging.h" + +namespace crashpad { + +ProcessMemoryRange::ProcessMemoryRange() + : memory_(nullptr), range_(), initialized_() {} + +ProcessMemoryRange::~ProcessMemoryRange() {} + +bool ProcessMemoryRange::Initialize(const ProcessMemory* memory, + bool is_64_bit, + LinuxVMAddress base, + LinuxVMSize size) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + memory_ = memory; + range_.SetRange(is_64_bit, base, size); + if (!range_.IsValid()) { + LOG(ERROR) << "invalid range"; + return false; + } + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +bool ProcessMemoryRange::Initialize(const ProcessMemory* memory, + bool is_64_bit) { + LinuxVMSize max = is_64_bit ? std::numeric_limits::max() + : std::numeric_limits::max(); + return Initialize(memory, is_64_bit, 0, max); +} + +bool ProcessMemoryRange::Initialize(const ProcessMemoryRange& other) { + return Initialize(other.memory_, + other.range_.Is64Bit(), + other.range_.Base(), + other.range_.Size()); +} + +bool ProcessMemoryRange::RestrictRange(LinuxVMAddress base, LinuxVMSize size) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + CheckedLinuxAddressRange new_range(range_.Is64Bit(), base, size); + if (!new_range.IsValid() || !range_.ContainsRange(new_range)) { + LOG(ERROR) << "invalid range"; + return false; + } + range_ = new_range; + return true; +} + +bool ProcessMemoryRange::Read(LinuxVMAddress address, + size_t size, + void* buffer) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + CheckedLinuxAddressRange read_range(range_.Is64Bit(), address, size); + if (!read_range.IsValid() || !range_.ContainsRange(read_range)) { + LOG(ERROR) << "read out of range"; + return false; + } + return memory_->Read(address, size, buffer); +} + +bool ProcessMemoryRange::ReadCStringSizeLimited(LinuxVMAddress address, + size_t size, + std::string* string) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!range_.ContainsValue(address)) { + LOG(ERROR) << "read out of range"; + return false; + } + size = std::min(static_cast(size), range_.End() - address); + return memory_->ReadCStringSizeLimited(address, size, string); +} + +} // namespace crashpad diff --git a/util/linux/process_memory_range.h b/util/linux/process_memory_range.h new file mode 100644 index 00000000..eb08de86 --- /dev/null +++ b/util/linux/process_memory_range.h @@ -0,0 +1,123 @@ +// 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_LINUX_PROCESS_MEMORY_RANGE_H_ +#define CRASHPAD_UTIL_LINUX_PROCESS_MEMORY_RANGE_H_ + +#include + +#include + +#include "base/macros.h" +#include "util/linux/address_types.h" +#include "util/linux/checked_linux_address_range.h" +#include "util/linux/process_memory.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +//! \brief Provides range protected access to the memory of another process. +class ProcessMemoryRange { + public: + ProcessMemoryRange(); + ~ProcessMemoryRange(); + + //! \brief Initializes this object. + //! + //! One of the Initialize methods must be successfully called on this object + //! before calling any other. + //! + //! \param[in] memory The memory reader to delegate to. + //! \param[in] is_64_bit Whether the target process is 64-bit. + //! \param[in] base The base address of the initial range. + //! \param[in] size The size of the initial range. + //! \return `true` on success. `false` on failure with a message logged. + bool Initialize(const ProcessMemory* memory, + bool is_64_bit, + LinuxVMAddress base, + LinuxVMSize size); + + //! \brief Initializes this object with the maximum range for the address + //! space. + //! + //! One of the Initialize methods must be successfully called on this object + //! before calling any other. + //! + //! \param[in] memory The memory reader to delegate to. + //! \param[in] is_64_bit Whether the target process is 64-bit. + bool Initialize(const ProcessMemory* memory, bool is_64_bit); + + //! \brief Initializes this object from an existing memory range. + //! + //! One of the Initialize methods must be successfully called on this object + //! before calling any other. + //! + //! \param[in] other The memory range object to initialize from. + //! \return `true` on success. `false` on failure with a message logged. + bool Initialize(const ProcessMemoryRange& other); + + //! \brief Returns whether the range is part of a 64-bit address space. + bool Is64Bit() const { return range_.Is64Bit(); } + + //! \brief Shrinks the range to the new base and size. + //! + //! The new range must be contained within the existing range for this object. + //! + //! \param[in] base The new base of the range. + //! \param[in] size The new size of the range. + //! \return `true` on success. `false` on failure with a message logged. + bool RestrictRange(LinuxVMAddress base, LinuxVMSize size); + + //! \brief Copies memory from the target process into a caller-provided buffer + //! in the current process. + //! + //! \param[in] address The address, in the target process' address space, of + //! the memory region to copy. + //! \param[in] size The size, in bytes, of the memory region to copy. + //! \a buffer must be at least this size. + //! \param[out] buffer The buffer into which the contents of the other + //! process' memory will be copied. + //! + //! \return `true` on success, with \a buffer filled appropriately. `false` on + //! failure, with a message logged. + bool Read(LinuxVMAddress address, size_t size, void* buffer) const; + + //! \brief Reads a `NUL`-terminated C string from the target process into a + //! string in the current process. + //! + //! \param[in] address The address, in the target process’s address space, of + //! the string to copy. + //! \param[in] size The maximum number of bytes to read. The string is + //! required to be `NUL`-terminated within this many bytes. + //! \param[out] string The string read from the other process. + //! + //! \return `true` on success, with \a string set appropriately. `false` on + //! failure, with a message logged. Failures can occur, for example, when + //! a `NUL` terminator is not found within \a size bytes, or when + //! encountering unmapped or unreadable pages. + bool ReadCStringSizeLimited(LinuxVMAddress address, + size_t size, + std::string* string) const; + + private: + const ProcessMemory* memory_; // weak + CheckedLinuxAddressRange range_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProcessMemoryRange); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_LINUX_PROCESS_MEMORY_RANGE_H_ diff --git a/util/linux/process_memory_range_test.cc b/util/linux/process_memory_range_test.cc new file mode 100644 index 00000000..bd23ae55 --- /dev/null +++ b/util/linux/process_memory_range_test.cc @@ -0,0 +1,91 @@ +// 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_range.h" + +#include + +#include + +#include "base/logging.h" +#include "build/build_config.h" +#include "gtest/gtest.h" +#include "util/misc/from_pointer_cast.h" + +namespace crashpad { +namespace test { +namespace { + +struct TestObject { + char string1[16]; + char string2[16]; +} kTestObject = {"string1", "string2"}; + +TEST(ProcessMemoryRange, Basic) { + pid_t pid = getpid(); +#if defined(ARCH_CPU_64_BITS) + constexpr bool is_64_bit = true; +#else + constexpr bool is_64_bit = false; +#endif // ARCH_CPU_64_BITS + + ProcessMemory memory; + ASSERT_TRUE(memory.Initialize(pid)); + + ProcessMemoryRange range; + ASSERT_TRUE(range.Initialize(&memory, is_64_bit)); + EXPECT_EQ(range.Is64Bit(), is_64_bit); + + // Both strings are accessible within the object's range. + auto object_addr = FromPointerCast(&kTestObject); + EXPECT_TRUE(range.RestrictRange(object_addr, sizeof(kTestObject))); + + TestObject object; + ASSERT_TRUE(range.Read(object_addr, sizeof(object), &object)); + EXPECT_EQ(memcmp(&object, &kTestObject, sizeof(object)), 0); + + std::string string; + auto string1_addr = FromPointerCast(kTestObject.string1); + auto string2_addr = FromPointerCast(kTestObject.string2); + ASSERT_TRUE(range.ReadCStringSizeLimited( + string1_addr, arraysize(kTestObject.string1), &string)); + EXPECT_STREQ(string.c_str(), kTestObject.string1); + + ASSERT_TRUE(range.ReadCStringSizeLimited( + string2_addr, arraysize(kTestObject.string2), &string)); + EXPECT_STREQ(string.c_str(), kTestObject.string2); + + // Limit the range to remove access to string2. + ProcessMemoryRange range2; + ASSERT_TRUE(range2.Initialize(range)); + ASSERT_TRUE( + range2.RestrictRange(string1_addr, arraysize(kTestObject.string1))); + EXPECT_TRUE(range2.ReadCStringSizeLimited( + string1_addr, arraysize(kTestObject.string1), &string)); + EXPECT_FALSE(range2.ReadCStringSizeLimited( + string2_addr, arraysize(kTestObject.string2), &string)); + EXPECT_FALSE(range2.Read(object_addr, sizeof(object), &object)); + + // String reads fail if the NUL terminator is outside the range. + ASSERT_TRUE(range2.RestrictRange(string1_addr, strlen(kTestObject.string1))); + EXPECT_FALSE(range2.ReadCStringSizeLimited( + string1_addr, arraysize(kTestObject.string1), &string)); + + // New range outside the old range. + EXPECT_FALSE(range2.RestrictRange(string1_addr - 1, 1)); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/util.gyp b/util/util.gyp index 6a052273..0d2364b5 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -52,6 +52,8 @@ 'linux/memory_map.h', 'linux/process_memory.cc', 'linux/process_memory.h', + 'linux/process_memory_range.cc', + 'linux/process_memory_range.h', 'linux/thread_info.cc', 'linux/thread_info.h', 'linux/scoped_ptrace_attach.cc', diff --git a/util/util_test.gyp b/util/util_test.gyp index 1b4cff95..72f25533 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -41,6 +41,7 @@ 'file/string_file_test.cc', 'linux/auxiliary_vector_test.cc', 'linux/memory_map_test.cc', + 'linux/process_memory_range_test.cc', 'linux/process_memory_test.cc', 'linux/thread_info_test.cc', 'linux/scoped_ptrace_attach_test.cc', From 4224be41d7d1938c61ce730c887209731c64faac Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 5 Jul 2017 18:23:32 -0700 Subject: [PATCH 11/30] linux: Add ElfImageReader to read ELF images via ProcessMemory Bug: crashpad:30 Change-Id: Id2a6a1868103b0f4374816e58aab365a977b010d Reviewed-on: https://chromium-review.googlesource.com/508836 Reviewed-by: Joshua Peraza Commit-Queue: Joshua Peraza --- compat/android/elf.h | 38 ++ snapshot/linux/elf_dynamic_array_reader.cc | 75 ++++ snapshot/linux/elf_dynamic_array_reader.h | 73 ++++ snapshot/linux/elf_image_reader.cc | 468 +++++++++++++++++++++ snapshot/linux/elf_image_reader.h | 120 ++++++ snapshot/linux/elf_image_reader_test.cc | 154 +++++++ snapshot/linux/elf_symbol_table_reader.cc | 87 ++++ snapshot/linux/elf_symbol_table_reader.h | 87 ++++ snapshot/linux/test_exported_symbols.sym | 18 + snapshot/snapshot.gyp | 15 +- snapshot/snapshot_test.gyp | 22 + util/linux/address_types.h | 4 + 12 files changed, 1160 insertions(+), 1 deletion(-) create mode 100644 compat/android/elf.h create mode 100644 snapshot/linux/elf_dynamic_array_reader.cc create mode 100644 snapshot/linux/elf_dynamic_array_reader.h create mode 100644 snapshot/linux/elf_image_reader.cc create mode 100644 snapshot/linux/elf_image_reader.h create mode 100644 snapshot/linux/elf_image_reader_test.cc create mode 100644 snapshot/linux/elf_symbol_table_reader.cc create mode 100644 snapshot/linux/elf_symbol_table_reader.h create mode 100644 snapshot/linux/test_exported_symbols.sym diff --git a/compat/android/elf.h b/compat/android/elf.h new file mode 100644 index 00000000..79e44fca --- /dev/null +++ b/compat/android/elf.h @@ -0,0 +1,38 @@ +// 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_COMPAT_ANDROID_ELF_H_ +#define CRASHPAD_COMPAT_ANDROID_ELF_H_ + +#include_next + +#if !defined(ELF32_ST_VISIBILITY) +#define ELF32_ST_VISIBILITY(other) ((other) & 0x3) +#endif + +#if !defined(ELF64_ST_VISIBILITY) +#define ELF64_ST_VISIBILITY(other) ELF32_ST_VISIBILITY(other) +#endif + +// Android 5.0.0 (API 21) NDK + +#if !defined(STT_COMMON) +#define STT_COMMON 5 +#endif + +#if !defined(STT_TLS) +#define STT_TLS 6 +#endif + +#endif // CRASHPAD_COMPAT_ANDROID_ELF_H_ diff --git a/snapshot/linux/elf_dynamic_array_reader.cc b/snapshot/linux/elf_dynamic_array_reader.cc new file mode 100644 index 00000000..c4a7e616 --- /dev/null +++ b/snapshot/linux/elf_dynamic_array_reader.cc @@ -0,0 +1,75 @@ +// 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 "snapshot/linux/elf_dynamic_array_reader.h" + +#include + +#include "util/stdlib/map_insert.h" + +namespace crashpad { + +namespace { + +template +bool Read(const ProcessMemoryRange& memory, + LinuxVMAddress address, + LinuxVMSize size, + std::map* values) { + std::map local_values; + + while (size > 0) { + DynType entry; + if (!memory.Read(address, sizeof(entry), &entry)) { + return false; + } + size -= sizeof(entry); + address += sizeof(entry); + + switch (entry.d_tag) { + case DT_NULL: + values->swap(local_values); + if (size != 0) { + LOG(WARNING) << size << " trailing bytes not read"; + } + return true; + case DT_NEEDED: + // Skip these entries for now. + break; + default: + if (!MapInsertOrReplace( + &local_values, entry.d_tag, entry.d_un.d_val, nullptr)) { + LOG(ERROR) << "duplicate dynamic array entry"; + return false; + } + } + } + LOG(ERROR) << "missing DT_NULL"; + return false; +} + +} // namespace + +ElfDynamicArrayReader::ElfDynamicArrayReader() : values_() {} + +ElfDynamicArrayReader::~ElfDynamicArrayReader() {} + +bool ElfDynamicArrayReader::Initialize(const ProcessMemoryRange& memory, + LinuxVMAddress address, + LinuxVMSize size) { + return memory.Is64Bit() ? Read(memory, address, size, &values_) + : Read(memory, address, size, &values_); +} + +} // namespace crashpad diff --git a/snapshot/linux/elf_dynamic_array_reader.h b/snapshot/linux/elf_dynamic_array_reader.h new file mode 100644 index 00000000..df06113c --- /dev/null +++ b/snapshot/linux/elf_dynamic_array_reader.h @@ -0,0 +1,73 @@ +// 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_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_ +#define CRASHPAD_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_ + +#include + +#include + +#include "base/logging.h" +#include "base/macros.h" +#include "util/linux/address_types.h" +#include "util/linux/process_memory_range.h" +#include "util/misc/reinterpret_bytes.h" + +namespace crashpad { + +//! \brief A reader for ELF dynamic arrays mapped into another process. +class ElfDynamicArrayReader { + public: + ElfDynamicArrayReader(); + ~ElfDynamicArrayReader(); + + //! \brief Initializes the reader. + //! + //! This method must be called once on an object and must be successfully + //! called before any other method in this class may be called. + //! + //! \param[in] memory A memory reader for the remote process. + //! \param[in] address The address in the remote process' address space where + //! the ELF dynamic table is loaded. + //! \param[in] size The maximum number of bytes to read. + bool Initialize(const ProcessMemoryRange& memory, + LinuxVMAddress address, + LinuxVMSize size); + + //! \brief Retrieve a value from the array. + //! + //! \param[in] tag Specifies which value should be retrieved. The possible + //! values for this parameter are the `DT_*` values from ``. + //! \param[out] value The value, casted to an appropriate type, if found. + //! \return `true` if the value is found. + template + bool GetValue(uint64_t tag, V* value) { + auto iter = values_.find(tag); + if (iter == values_.end()) { + LOG(ERROR) << "tag not found"; + return false; + } + return ReinterpretBytes(iter->second, value); + } + + private: + std::map values_; + + DISALLOW_COPY_AND_ASSIGN(ElfDynamicArrayReader); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_ diff --git a/snapshot/linux/elf_image_reader.cc b/snapshot/linux/elf_image_reader.cc new file mode 100644 index 00000000..029746f7 --- /dev/null +++ b/snapshot/linux/elf_image_reader.cc @@ -0,0 +1,468 @@ +// 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 "snapshot/linux/elf_image_reader.h" + +#include +#include + +#include "base/logging.h" + +namespace crashpad { + +class ElfImageReader::ProgramHeaderTable { + public: + virtual ~ProgramHeaderTable() {} + + virtual bool VerifyLoadSegments() const = 0; + virtual size_t Size() const = 0; + virtual bool GetDynamicSegment(LinuxVMAddress* address, + LinuxVMSize* size) const = 0; + virtual bool GetPreferredElfHeaderAddress(LinuxVMAddress* address) const = 0; + virtual bool GetPreferredLoadedMemoryRange(LinuxVMAddress* address, + LinuxVMSize* size) const = 0; + + protected: + ProgramHeaderTable() {} +}; + +template +class ElfImageReader::ProgramHeaderTableSpecific + : public ElfImageReader::ProgramHeaderTable { + public: + ProgramHeaderTableSpecific() {} + ~ProgramHeaderTableSpecific() {} + + bool Initialize(const ProcessMemoryRange& memory, + LinuxVMAddress address, + LinuxVMSize num_segments) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + table_.resize(num_segments); + if (!memory.Read(address, sizeof(PhdrType) * num_segments, table_.data())) { + return false; + } + + if (!VerifyLoadSegments()) { + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; + } + + bool VerifyLoadSegments() const override { + constexpr bool is_64_bit = std::is_same::value; + LinuxVMAddress last_vaddr; + bool load_found = false; + for (const auto& header : table_) { + if (header.p_type == PT_LOAD) { + CheckedLinuxAddressRange load_range( + is_64_bit, header.p_vaddr, header.p_memsz); + + if (!load_range.IsValid()) { + LOG(ERROR) << "bad load range"; + return false; + } + + if (load_found && header.p_vaddr <= last_vaddr) { + LOG(ERROR) << "out of order load segments"; + return false; + } + load_found = true; + last_vaddr = header.p_vaddr; + } + } + return true; + } + + size_t Size() const override { return sizeof(PhdrType) * table_.size(); } + + bool GetPreferredElfHeaderAddress(LinuxVMAddress* address) const override { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + for (const auto& header : table_) { + if (header.p_type == PT_LOAD && header.p_offset == 0) { + *address = header.p_vaddr; + return true; + } + } + LOG(ERROR) << "no preferred header address"; + return false; + } + + bool GetPreferredLoadedMemoryRange(LinuxVMAddress* base, + LinuxVMSize* size) const override { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + LinuxVMAddress preferred_base = 0; + LinuxVMAddress preferred_end = 0; + bool load_found = false; + for (const auto& header : table_) { + if (header.p_type == PT_LOAD) { + if (!load_found) { + preferred_base = header.p_vaddr; + load_found = true; + } + preferred_end = header.p_vaddr + header.p_memsz; + } + } + if (load_found) { + *base = preferred_base; + *size = preferred_end - preferred_base; + return true; + } + LOG(ERROR) << "no load segments"; + return false; + } + + bool GetDynamicSegment(LinuxVMAddress* address, + LinuxVMSize* size) const override { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + const PhdrType* phdr; + if (!GetProgramHeader(PT_DYNAMIC, &phdr)) { + return false; + } + *address = phdr->p_vaddr; + *size = phdr->p_memsz; + return true; + } + + bool GetProgramHeader(uint32_t type, const PhdrType** header_out) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + for (const auto& header : table_) { + if (header.p_type == type) { + *header_out = &header; + return true; + } + } + return false; + } + + private: + std::vector table_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProgramHeaderTableSpecific); +}; + +ElfImageReader::ElfImageReader() + : header_64_(), + ehdr_address_(0), + load_bias_(0), + memory_(), + program_headers_(), + dynamic_array_(), + symbol_table_(), + initialized_(), + dynamic_array_initialized_(), + symbol_table_initialized_() {} + +ElfImageReader::~ElfImageReader() {} + +bool ElfImageReader::Initialize(const ProcessMemoryRange& memory, + LinuxVMAddress address) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + ehdr_address_ = address; + if (!memory_.Initialize(memory)) { + return false; + } + + uint8_t e_ident[EI_NIDENT]; + if (!memory_.Read(ehdr_address_, EI_NIDENT, e_ident)) { + return false; + } + + if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) { + LOG(ERROR) << "Incorrect ELF magic number"; + return false; + } + + if (!(memory_.Is64Bit() && e_ident[EI_CLASS] == ELFCLASS64) && + !(!memory_.Is64Bit() && e_ident[EI_CLASS] == ELFCLASS32)) { + LOG(ERROR) << "unexpected bitness"; + return false; + } + +#if defined(ARCH_CPU_LITTLE_ENDIAN) + constexpr uint8_t expected_encoding = ELFDATA2LSB; +#elif defined(ARCH_CPU_BIG_ENDIAN) + constexpr uint8_t expected_encoding = ELFDATA2MSB; +#endif + if (e_ident[EI_DATA] != expected_encoding) { + LOG(ERROR) << "unexpected encoding"; + return false; + } + + if (e_ident[EI_VERSION] != EV_CURRENT) { + LOG(ERROR) << "unexpected version"; + return false; + } + + if (!(memory_.Is64Bit() + ? memory_.Read(ehdr_address_, sizeof(header_64_), &header_64_) + : memory_.Read(ehdr_address_, sizeof(header_32_), &header_32_))) { + return false; + } + +#define VERIFY_HEADER(header) \ + do { \ + if (header.e_type != ET_EXEC && header.e_type != ET_DYN) { \ + LOG(ERROR) << "unexpected image type"; \ + return false; \ + } \ + if (header.e_version != EV_CURRENT) { \ + LOG(ERROR) << "unexpected version"; \ + return false; \ + } \ + if (header.e_ehsize != sizeof(header)) { \ + LOG(ERROR) << "unexpected header size"; \ + return false; \ + } \ + } while (false); + + if (memory_.Is64Bit()) { + VERIFY_HEADER(header_64_); + } else { + VERIFY_HEADER(header_32_); + } + + if (!InitializeProgramHeaders()) { + return false; + } + + LinuxVMAddress preferred_ehdr_address; + if (!program_headers_.get()->GetPreferredElfHeaderAddress( + &preferred_ehdr_address)) { + return false; + } + load_bias_ = ehdr_address_ - preferred_ehdr_address; + + LinuxVMAddress base_address; + LinuxVMSize loaded_size; + if (!program_headers_.get()->GetPreferredLoadedMemoryRange(&base_address, + &loaded_size)) { + return false; + } + base_address += load_bias_; + + if (!memory_.RestrictRange(base_address, loaded_size)) { + return false; + } + + LinuxVMSize ehdr_size; + LinuxVMAddress phdr_address; + if (memory_.Is64Bit()) { + ehdr_size = sizeof(header_64_); + phdr_address = ehdr_address_ + header_64_.e_phoff; + } else { + ehdr_size = sizeof(header_32_); + phdr_address = ehdr_address_ + header_32_.e_phoff; + } + + CheckedLinuxAddressRange range(memory_.Is64Bit(), base_address, loaded_size); + if (!range.ContainsRange(CheckedLinuxAddressRange( + memory_.Is64Bit(), ehdr_address_, ehdr_size))) { + LOG(ERROR) << "ehdr out of range"; + return false; + } + if (!range.ContainsRange(CheckedLinuxAddressRange( + memory.Is64Bit(), phdr_address, program_headers_->Size()))) { + LOG(ERROR) << "phdrs out of range"; + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +uint16_t ElfImageReader::FileType() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return memory_.Is64Bit() ? header_64_.e_type : header_32_.e_type; +} + +bool ElfImageReader::GetDynamicSymbol(const std::string& name, + LinuxVMAddress* address, + LinuxVMSize* size) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!InitializeDynamicSymbolTable()) { + return false; + } + + ElfSymbolTableReader::SymbolInformation info; + if (!symbol_table_->GetSymbol(name, &info)) { + return false; + } + if (info.shndx == SHN_UNDEF || info.shndx == SHN_COMMON) { + return false; + } + + switch (info.binding) { + case STB_GLOBAL: + case STB_WEAK: + break; + + case STB_LOCAL: + default: + return false; + } + + switch (info.type) { + case STT_OBJECT: + case STT_FUNC: + break; + + case STT_COMMON: + case STT_NOTYPE: + case STT_SECTION: + case STT_FILE: + case STT_TLS: + default: + return false; + } + + if (info.shndx != SHN_ABS) { + info.address += GetLoadBias(); + } + + *address = info.address; + *size = info.size; + return true; +} + +bool ElfImageReader::ReadDynamicStringTableAtOffset(LinuxVMSize offset, + std::string* string) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!InitializeDynamicArray()) { + return false; + } + + LinuxVMAddress string_table_address; + LinuxVMSize string_table_size; + if (!GetAddressFromDynamicArray(DT_STRTAB, &string_table_address) || + !dynamic_array_->GetValue(DT_STRSZ, &string_table_size)) { + LOG(ERROR) << "missing string table info"; + return false; + } + if (offset >= string_table_size) { + LOG(ERROR) << "bad offset"; + return false; + } + + if (!memory_.ReadCStringSizeLimited( + string_table_address + offset, string_table_size - offset, string)) { + LOG(ERROR) << "missing nul-terminator"; + return false; + } + return true; +} + +bool ElfImageReader::GetDebugAddress(LinuxVMAddress* debug) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!InitializeDynamicArray()) { + return false; + } + return GetAddressFromDynamicArray(DT_DEBUG, debug); +} + +bool ElfImageReader::InitializeProgramHeaders() { +#define INITIALIZE_PROGRAM_HEADERS(PhdrType, header) \ + do { \ + if (header.e_phentsize != sizeof(PhdrType)) { \ + LOG(ERROR) << "unexpected phdr size"; \ + return false; \ + } \ + auto phdrs = new ProgramHeaderTableSpecific(); \ + program_headers_.reset(phdrs); \ + if (!phdrs->Initialize( \ + memory_, ehdr_address_ + header.e_phoff, header.e_phnum)) { \ + return false; \ + } \ + } while (false); + + if (memory_.Is64Bit()) { + INITIALIZE_PROGRAM_HEADERS(Elf64_Phdr, header_64_); + } else { + INITIALIZE_PROGRAM_HEADERS(Elf32_Phdr, header_32_); + } + return true; +} + +bool ElfImageReader::InitializeDynamicArray() { + if (dynamic_array_initialized_.is_valid()) { + return true; + } + if (!dynamic_array_initialized_.is_uninitialized()) { + return false; + } + dynamic_array_initialized_.set_invalid(); + + LinuxVMAddress dyn_segment_address; + LinuxVMSize dyn_segment_size; + if (!program_headers_.get()->GetDynamicSegment(&dyn_segment_address, + &dyn_segment_size)) { + LOG(ERROR) << "no dynamic segment"; + return false; + } + dyn_segment_address += GetLoadBias(); + + dynamic_array_.reset(new ElfDynamicArrayReader()); + if (!dynamic_array_->Initialize( + memory_, dyn_segment_address, dyn_segment_size)) { + return false; + } + dynamic_array_initialized_.set_valid(); + return true; +} + +bool ElfImageReader::InitializeDynamicSymbolTable() { + if (symbol_table_initialized_.is_valid()) { + return true; + } + if (!symbol_table_initialized_.is_uninitialized()) { + return false; + } + symbol_table_initialized_.set_invalid(); + + if (!InitializeDynamicArray()) { + return false; + } + + LinuxVMAddress symbol_table_address; + if (!GetAddressFromDynamicArray(DT_SYMTAB, &symbol_table_address)) { + LOG(ERROR) << "no symbol table"; + return false; + } + + symbol_table_.reset( + new ElfSymbolTableReader(&memory_, this, symbol_table_address)); + symbol_table_initialized_.set_valid(); + return true; +} + +bool ElfImageReader::GetAddressFromDynamicArray(uint64_t tag, + LinuxVMAddress* address) { + if (!dynamic_array_->GetValue(tag, address)) { + return false; + } +#if defined(OS_ANDROID) + // The GNU loader updates the dynamic array according to the load bias while + // the Android loader only updates the debug address. + if (tag != DT_DEBUG) { + *address += GetLoadBias(); + } +#endif // OS_ANDROID + return true; +} + +} // namespace crashpad diff --git a/snapshot/linux/elf_image_reader.h b/snapshot/linux/elf_image_reader.h new file mode 100644 index 00000000..6c620095 --- /dev/null +++ b/snapshot/linux/elf_image_reader.h @@ -0,0 +1,120 @@ +// 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_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_ +#define CRASHPAD_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_ + +#include +#include + +#include +#include + +#include "base/macros.h" +#include "util/linux/address_types.h" +#include "snapshot/linux/elf_dynamic_array_reader.h" +#include "snapshot/linux/elf_symbol_table_reader.h" +#include "util/linux/process_memory_range.h" +#include "util/misc/initialization_state.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +//! \brief A reader for ELF images mapped into another process. +//! +//! This class is capable of reading both 32-bit and 64-bit images. +class ElfImageReader { + public: + ElfImageReader(); + ~ElfImageReader(); + + //! \brief Initializes the reader. + //! + //! This method must be called once on an object and must be successfully + //! called before any other method in this class may be called. + //! + //! \param[in] memory A memory reader for the remote process. + //! \param[in] address The address in the remote process' address space where + //! the ELF image is loaded. + bool Initialize(const ProcessMemoryRange& memory, LinuxVMAddress address); + + //! \brief Returns the file type for the image. + //! + //! Possible values include `ET_EXEC` or `ET_DYN` from ``. + uint16_t FileType() const; + + //! \brief Returns the load bias for the image. + //! + //! The load bias is the actual load address minus the preferred load address. + LinuxVMOffset GetLoadBias() const { return load_bias_; } + + //! \brief Reads information from the dynamic symbol table about the symbol + //! identified by \a name. + //! + //! \param[in] name The name of the symbol to search for. + //! \param[out] address The address of the symbol in the target process' + //! address space, if found. + //! \param[out] size The size of the symbol, if found. + //! \return `true` if the symbol was found. + bool GetDynamicSymbol(const std::string& name, + LinuxVMAddress* address, + LinuxVMSize* size); + + //! \brief Reads a `NUL`-terminated C string from this image's dynamic string + //! table. + //! + //! \param[in] offset the byte offset in the string table to start reading. + //! \param[out] string the string read. + //! \return `true` on success. Otherwise `false` with a message logged. + bool ReadDynamicStringTableAtOffset(LinuxVMSize offset, std::string* string); + + //! \brief Determine the debug address. + //! + //! The debug address is a pointer to an `r_debug` struct defined in + //! ``. + //! + //! \param[out] debug the debug address, if found. + //! \return `true` if the debug address was found. + bool GetDebugAddress(LinuxVMAddress* debug); + + private: + class ProgramHeaderTable; + template + class ProgramHeaderTableSpecific; + + bool InitializeProgramHeaders(); + bool InitializeDynamicArray(); + bool InitializeDynamicSymbolTable(); + bool GetAddressFromDynamicArray(uint64_t tag, LinuxVMAddress* address); + + union { + Elf32_Ehdr header_32_; + Elf64_Ehdr header_64_; + }; + LinuxVMAddress ehdr_address_; + LinuxVMOffset load_bias_; + ProcessMemoryRange memory_; + std::unique_ptr program_headers_; + std::unique_ptr dynamic_array_; + std::unique_ptr symbol_table_; + InitializationStateDcheck initialized_; + InitializationState dynamic_array_initialized_; + InitializationState symbol_table_initialized_; + + DISALLOW_COPY_AND_ASSIGN(ElfImageReader); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_ diff --git a/snapshot/linux/elf_image_reader_test.cc b/snapshot/linux/elf_image_reader_test.cc new file mode 100644 index 00000000..c45e5655 --- /dev/null +++ b/snapshot/linux/elf_image_reader_test.cc @@ -0,0 +1,154 @@ +// 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 "snapshot/linux/elf_image_reader.h" + +#include +#include + +#include "base/logging.h" +#include "gtest/gtest.h" +#include "test/multiprocess.h" +#include "util/file/file_io.h" +#include "util/linux/address_types.h" +#include "util/linux/auxiliary_vector.h" +#include "util/linux/memory_map.h" +#include "util/misc/from_pointer_cast.h" + +extern "C" { +__attribute__((visibility("default"))) void +ElfImageReaderTestExportedSymbol(){}; +} // extern "C" + +namespace crashpad { +namespace test { +namespace { + +void LocateExecutable(pid_t pid, bool is_64_bit, LinuxVMAddress* elf_address) { + AuxiliaryVector aux; + ASSERT_TRUE(aux.Initialize(pid, is_64_bit)); + + LinuxVMAddress phdrs; + ASSERT_TRUE(aux.GetValue(AT_PHDR, &phdrs)); + + MemoryMap memory_map; + ASSERT_TRUE(memory_map.Initialize(pid)); + const MemoryMap::Mapping* exe_mapping = memory_map.FindMapping(phdrs); + ASSERT_TRUE(exe_mapping); + *elf_address = exe_mapping->range.Base(); +} + +void ExpectElfImageWithSymbol(pid_t pid, + LinuxVMAddress address, + bool is_64_bit, + std::string symbol_name, + LinuxVMAddress expected_symbol_address) { + ProcessMemory memory; + ASSERT_TRUE(memory.Initialize(pid)); + ProcessMemoryRange range; + ASSERT_TRUE(range.Initialize(&memory, is_64_bit)); + + ElfImageReader reader; + ASSERT_TRUE(reader.Initialize(range, address)); + + LinuxVMAddress symbol_address; + LinuxVMSize symbol_size; + ASSERT_TRUE( + reader.GetDynamicSymbol(symbol_name, &symbol_address, &symbol_size)); + EXPECT_EQ(symbol_address, expected_symbol_address); + + EXPECT_FALSE( + reader.GetDynamicSymbol("notasymbol", &symbol_address, &symbol_size)); +} + +void ReadThisExecutableInTarget(pid_t pid) { +#if defined(ARCH_CPU_64_BITS) + constexpr bool am_64_bit = true; +#else + constexpr bool am_64_bit = false; +#endif // ARCH_CPU_64_BITS + + LinuxVMAddress elf_address; + LocateExecutable(pid, am_64_bit, &elf_address); + + ExpectElfImageWithSymbol( + pid, + elf_address, + am_64_bit, + "ElfImageReaderTestExportedSymbol", + FromPointerCast(ElfImageReaderTestExportedSymbol)); +} + +// Assumes that libc is loaded at the same address in this process as in the +// target, which it is for the fork test below. +void ReadLibcInTarget(pid_t pid) { +#if defined(ARCH_CPU_64_BITS) + constexpr bool am_64_bit = true; +#else + constexpr bool am_64_bit = false; +#endif // ARCH_CPU_64_BITS + + Dl_info info; + ASSERT_TRUE(dladdr(reinterpret_cast(getpid), &info)) << "dladdr:" + << dlerror(); + LinuxVMAddress elf_address = FromPointerCast(info.dli_fbase); + + ExpectElfImageWithSymbol(pid, + elf_address, + am_64_bit, + "getpid", + FromPointerCast(getpid)); +} + +class ReadExecutableChildTest : public Multiprocess { + public: + ReadExecutableChildTest() : Multiprocess() {} + ~ReadExecutableChildTest() {} + + private: + void MultiprocessParent() { ReadThisExecutableInTarget(ChildPID()); } + void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); } +}; + +TEST(ElfImageReader, MainExecutableSelf) { + ReadThisExecutableInTarget(getpid()); +} + +TEST(ElfImageReader, MainExecutableChild) { + ReadExecutableChildTest test; + test.Run(); +} + +TEST(ElfImageReader, OneModuleSelf) { + ReadLibcInTarget(getpid()); +} + +class ReadLibcChildTest : public Multiprocess { + public: + ReadLibcChildTest() : Multiprocess() {} + ~ReadLibcChildTest() {} + + private: + void MultiprocessParent() { ReadLibcInTarget(ChildPID()); } + void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); } +}; + +TEST(ElfImageReader, OneModuleChild) { + ReadLibcChildTest test; + test.Run(); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/snapshot/linux/elf_symbol_table_reader.cc b/snapshot/linux/elf_symbol_table_reader.cc new file mode 100644 index 00000000..d36e46ac --- /dev/null +++ b/snapshot/linux/elf_symbol_table_reader.cc @@ -0,0 +1,87 @@ +// 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 "snapshot/linux/elf_symbol_table_reader.h" + +#include + +#include "base/logging.h" +#include "snapshot/linux/elf_image_reader.h" + +namespace crashpad { + +namespace { + +uint8_t GetBinding(const Elf32_Sym& sym) { + return ELF32_ST_BIND(sym.st_info); +} + +uint8_t GetBinding(const Elf64_Sym& sym) { + return ELF64_ST_BIND(sym.st_info); +} + +uint8_t GetType(const Elf32_Sym& sym) { + return ELF32_ST_TYPE(sym.st_info); +} + +uint8_t GetType(const Elf64_Sym& sym) { + return ELF64_ST_TYPE(sym.st_info); +} + +uint8_t GetVisibility(const Elf32_Sym& sym) { + return ELF32_ST_VISIBILITY(sym.st_other); +} + +uint8_t GetVisibility(const Elf64_Sym& sym) { + return ELF64_ST_VISIBILITY(sym.st_other); +} + +} // namespace + +ElfSymbolTableReader::ElfSymbolTableReader(const ProcessMemoryRange* memory, + ElfImageReader* elf_reader, + LinuxVMAddress address) + : memory_(memory), elf_reader_(elf_reader), base_address_(address) {} + +ElfSymbolTableReader::~ElfSymbolTableReader() {} + +bool ElfSymbolTableReader::GetSymbol(const std::string& name, + SymbolInformation* info) { + return memory_->Is64Bit() ? ScanSymbolTable(name, info) + : ScanSymbolTable(name, info); +} + +template +bool ElfSymbolTableReader::ScanSymbolTable(const std::string& name, + SymbolInformation* info_out) { + LinuxVMAddress address = base_address_; + SymEnt entry; + std::string string; + while (memory_->Read(address, sizeof(entry), &entry) && + elf_reader_->ReadDynamicStringTableAtOffset(entry.st_name, &string)) { + if (string == name) { + info_out->address = entry.st_value; + info_out->size = entry.st_size; + info_out->shndx = entry.st_shndx; + info_out->binding = GetBinding(entry); + info_out->type = GetType(entry); + info_out->visibility = GetVisibility(entry); + return true; + } + address += sizeof(entry); + } + return false; +} + +} // namespace crashpad diff --git a/snapshot/linux/elf_symbol_table_reader.h b/snapshot/linux/elf_symbol_table_reader.h new file mode 100644 index 00000000..1eda29b5 --- /dev/null +++ b/snapshot/linux/elf_symbol_table_reader.h @@ -0,0 +1,87 @@ +// 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_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_ +#define CRASHPAD_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_ + +#include + +#include + +#include "base/macros.h" +#include "util/linux/address_types.h" +#include "util/linux/process_memory_range.h" + +namespace crashpad { + +class ElfImageReader; + +//! \brief A reader for symbol tables in ELF images mapped into another process. +class ElfSymbolTableReader { + public: + //! \brief Information about a symbol in a module's symbol table. + struct SymbolInformation { + //! \brief The address of the symbol as it exists in the symbol table, not + //! adjusted for any load bias. + LinuxVMAddress address; + + //! \brief The size of the symbol. + LinuxVMSize size; + + //! \brief The section index that the symbol definition is in relation to. + uint16_t shndx; + + //! \brief Specifies the type of symbol. Possible values include + //! `STT_OBJECT`, `STT_FUNC`, etc. + uint8_t type; + + //! \brief Specifies the default scope at which a symbol takes precedence. + //! Possible values include `STB_LOCAL`, `STB_GLOBAL`, `STB_WEAK`, or + //! OS/processor specific values. + uint8_t binding; + + //! \brief Together with binding, can limit the visibility of a symbol to + //! the module that defines it. Possible values include `STV_DEFAULT`, + //! `STV_INTERNAL`, `STV_HIDDEN`, and `STV_PROTECTED`. + uint8_t visibility; + }; + + // TODO(jperaza): Support using .hash and .gnu.hash sections to improve symbol + // lookup. + ElfSymbolTableReader(const ProcessMemoryRange* memory, + ElfImageReader* elf_reader, + LinuxVMAddress address); + ~ElfSymbolTableReader(); + + //! \brief Lookup information about a symbol. + //! + //! \param[in] name The name of the symbol to search for. + //! \param[out] info The symbol information, if found. + //! \return `true` if the symbol is found. + bool GetSymbol(const std::string& name, SymbolInformation* info); + + private: + template + bool ScanSymbolTable(const std::string& name, SymbolInformation* info); + + const ProcessMemoryRange* const memory_; // weak + ElfImageReader* const elf_reader_; // weak + const LinuxVMAddress base_address_; + + DISALLOW_COPY_AND_ASSIGN(ElfSymbolTableReader); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_ diff --git a/snapshot/linux/test_exported_symbols.sym b/snapshot/linux/test_exported_symbols.sym new file mode 100644 index 00000000..e0785c6e --- /dev/null +++ b/snapshot/linux/test_exported_symbols.sym @@ -0,0 +1,18 @@ +# 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. + +# This symbol is used by elf_image_reader_test.cc. +{ + ElfImageReaderTestExportedSymbol; +}; diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 7150cdc5..b4efc2ce 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -40,6 +40,12 @@ 'exception_snapshot.h', 'handle_snapshot.cc', 'handle_snapshot.h', + 'linux/elf_dynamic_array_reader.cc', + 'linux/elf_dynamic_array_reader.h', + 'linux/elf_image_reader.cc', + 'linux/elf_image_reader.h', + 'linux/elf_symbol_table_reader.cc', + 'linux/elf_symbol_table_reader.h', 'mac/cpu_context_mac.cc', 'mac/cpu_context_mac.h', 'mac/exception_snapshot_mac.cc', @@ -136,7 +142,14 @@ 'capture_memory.h', ], }], - ] + ], + 'target_conditions': [ + ['OS=="android"', { + 'sources/': [ + ['include', '^linux/'], + ], + }], + ], }, { 'variables': { diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index ad58defa..d8a2d143 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -70,6 +70,7 @@ 'cpu_context_test.cc', 'crashpad_info_client_options_test.cc', 'api/module_annotations_win_test.cc', + 'linux/elf_image_reader_test.cc', 'mac/cpu_context_mac_test.cc', 'mac/mach_o_image_annotations_reader_test.cc', 'mac/mach_o_image_reader_test.cc', @@ -111,6 +112,27 @@ 'sources!': [ 'crashpad_info_client_options_test.cc', ], + 'copies': [{ + 'destination': '<(PRODUCT_DIR)', + 'files': [ + 'linux/test_exported_symbols.sym', + ], + }], + 'ldflags': [ + '-Wl,--dynamic-list=test_exported_symbols.sym', + ], + 'link_settings': { + 'libraries': [ + '-ldl', + ], + }, + }], + ], + 'target_conditions': [ + ['OS=="android"', { + 'sources/': [ + ['include', '^linux/'], + ], }], ], }, diff --git a/util/linux/address_types.h b/util/linux/address_types.h index 8c8f13d7..fb17500d 100644 --- a/util/linux/address_types.h +++ b/util/linux/address_types.h @@ -27,6 +27,10 @@ using LinuxVMAddress = uint64_t; //! LinuxVMAddress), potentially across bitness. using LinuxVMSize = uint64_t; +//! \brief Type used to represent an offset from a LinuxVMAddress, potentially +//! across bitness. +using LinuxVMOffset = int64_t; + } // namespace crashpad #endif // CRASHPAD_UTIL_LINUX_ADDRESS_TYPES_H_ From a79791969d0382cc2668f5823d22487a665ba325 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Tue, 11 Jul 2017 08:59:24 -0700 Subject: [PATCH 12/30] linux: Add MemoryMap::FindFileMmapStart ELF executables and libraries may be loaded into memory in several mappings, possibly with holes containing anonymous mappings or mappings of other files. This method takes an input mapping and attempts to find the mapping for file offset 0 of the same file. Bug: crashpad:30 Change-Id: I79abf060b015d58ef0eba54a399a74315d7d2d77 Reviewed-on: https://chromium-review.googlesource.com/565223 Commit-Queue: Joshua Peraza Reviewed-by: Mark Mentovai --- snapshot/linux/elf_image_reader_test.cc | 5 +- util/linux/memory_map.cc | 46 ++++++++ util/linux/memory_map.h | 16 +++ util/linux/memory_map_test.cc | 133 ++++++++++++++++++++++-- 4 files changed, 190 insertions(+), 10 deletions(-) diff --git a/snapshot/linux/elf_image_reader_test.cc b/snapshot/linux/elf_image_reader_test.cc index c45e5655..0f3f5848 100644 --- a/snapshot/linux/elf_image_reader_test.cc +++ b/snapshot/linux/elf_image_reader_test.cc @@ -44,7 +44,10 @@ void LocateExecutable(pid_t pid, bool is_64_bit, LinuxVMAddress* elf_address) { MemoryMap memory_map; ASSERT_TRUE(memory_map.Initialize(pid)); - const MemoryMap::Mapping* exe_mapping = memory_map.FindMapping(phdrs); + const MemoryMap::Mapping* phdr_mapping = memory_map.FindMapping(phdrs); + ASSERT_TRUE(phdr_mapping); + const MemoryMap::Mapping* exe_mapping = + memory_map.FindFileMmapStart(*phdr_mapping); ASSERT_TRUE(exe_mapping); *elf_address = exe_mapping->range.Base(); } diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 4283cb84..32547134 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -202,6 +202,16 @@ MemoryMap::MemoryMap() : mappings_(), initialized_() {} MemoryMap::~MemoryMap() {} +bool MemoryMap::Mapping::Equals(const Mapping& other) const { + DCHECK_EQ(range.Is64Bit(), other.range.Is64Bit()); + return range.Base() == other.range.Base() && + range.Size() == other.range.Size() && name == other.name && + offset == other.offset && device == other.device && + inode == other.inode && readable == other.readable && + writable == other.writable && executable == other.executable && + shareable == other.shareable; +} + bool MemoryMap::Initialize(pid_t pid) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); @@ -267,4 +277,40 @@ const MemoryMap::Mapping* MemoryMap::FindMappingWithName( return nullptr; } +const MemoryMap::Mapping* MemoryMap::FindFileMmapStart( + const Mapping& mapping) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + size_t index = 0; + for (; index < mappings_.size(); ++index) { + if (mappings_[index].Equals(mapping)) { + break; + } + } + if (index >= mappings_.size()) { + LOG(ERROR) << "mapping not found"; + return nullptr; + } + + // If the mapping is anonymous, as is for the VDSO, there is no mapped file to + // find the start of, so just return the input mapping. + if (mapping.device == 0 && mapping.inode == 0) { + return &mappings_[index]; + } + + do { + // There may by anonymous mappings or other files mapped into the holes, + // so check that the mapping uses the same file as the input, but keep + // searching if it doesn't. + if (mappings_[index].device == mapping.device && + mappings_[index].inode == mapping.inode && + mappings_[index].offset == 0) { + return &mappings_[index]; + } + } while (index--); + + LOG(ERROR) << "mapping not found"; + return nullptr; +} + } // namespace crashpad diff --git a/util/linux/memory_map.h b/util/linux/memory_map.h index 22f4448b..6e5b40c8 100644 --- a/util/linux/memory_map.h +++ b/util/linux/memory_map.h @@ -37,6 +37,7 @@ class MemoryMap { //! \brief Information about a mapped region of memory. struct Mapping { Mapping(); + bool Equals(const Mapping& other) const; std::string name; CheckedLinuxAddressRange range; @@ -74,6 +75,21 @@ class MemoryMap { //! it was obtained from. const Mapping* FindMappingWithName(const std::string& name) const; + //! \brief Find the first Mapping in a series of mappings for the same file. + //! + //! Executables and libaries are typically loaded into several mappings with + //! varying permissions for different segments. This method searches for the + //! mapping with the highest address at or below \a mapping, which maps the + //! same file as \a mapping from file offset 0. + //! + //! If \a mapping is not found, `nullptr` is returned. If \a mapping is found + //! but does not map a file, \a mapping is returned. + //! + //! \param[in] mapping A Mapping whose series to find the start of. + //! \return The first Mapping in the series or `nullptr` on failure with a + //! message logged. + const Mapping* FindFileMmapStart(const Mapping& mapping) const; + private: std::vector mappings_; InitializationStateDcheck initialized_; diff --git a/util/linux/memory_map_test.cc b/util/linux/memory_map_test.cc index aab5c4ac..8578a7e5 100644 --- a/util/linux/memory_map_test.cc +++ b/util/linux/memory_map_test.cc @@ -22,6 +22,7 @@ #include "base/files/file_path.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/file.h" @@ -78,6 +79,18 @@ TEST(MemoryMap, SelfBasic) { EXPECT_TRUE(mapping->shareable); } +void InitializeFile(const base::FilePath& path, + size_t size, + ScopedFileHandle* handle) { + ASSERT_FALSE(FileExists(path)); + + handle->reset(LoggingOpenFileForReadAndWrite( + path, FileWriteMode::kReuseOrCreate, FilePermissions::kOwnerOnly)); + ASSERT_TRUE(handle->is_valid()); + std::string file_contents(size, std::string::value_type()); + CheckedWriteFile(handle->get(), file_contents.c_str(), file_contents.size()); +} + class MapChildTest : public Multiprocess { public: MapChildTest() : Multiprocess(), page_size_(getpagesize()) {} @@ -169,13 +182,8 @@ class MapChildTest : public Multiprocess { ScopedTempDir temp_dir; base::FilePath path = temp_dir.path().Append(FILE_PATH_LITERAL("test_file")); - ASSERT_FALSE(FileExists(path)); - std::string path_string = path.value(); - ScopedFileHandle handle(LoggingOpenFileForReadAndWrite( - path, FileWriteMode::kReuseOrCreate, FilePermissions::kOwnerOnly)); - ASSERT_TRUE(handle.is_valid()); - std::string file_contents(page_size_ * 2, std::string::value_type()); - CheckedWriteFile(handle.get(), file_contents.c_str(), file_contents.size()); + ScopedFileHandle handle; + ASSERT_NO_FATAL_FAILURE(InitializeFile(path, page_size_ * 2, &handle)); ScopedMmap file_mapping; ASSERT_TRUE(file_mapping.ResetMmap(nullptr, @@ -188,9 +196,9 @@ class MapChildTest : public Multiprocess { auto mapped_file_address = file_mapping.addr_as(); CheckedWriteFile( WritePipeHandle(), &mapped_file_address, sizeof(mapped_file_address)); - LinuxVMSize path_length = path_string.size(); + LinuxVMSize path_length = path.value().size(); CheckedWriteFile(WritePipeHandle(), &path_length, sizeof(path_length)); - CheckedWriteFile(WritePipeHandle(), path_string.c_str(), path_length); + CheckedWriteFile(WritePipeHandle(), path.value().c_str(), path_length); CheckedReadFileAtEOF(ReadPipeHandle()); } @@ -337,6 +345,113 @@ TEST(MemoryMap, MapRunningChild) { test.Run(); } +// Expects first and third pages from mapping_start to refer to the same mapped +// file. The second page should not. +void ExpectFindFileMmapStart(LinuxVMAddress mapping_start, + LinuxVMSize page_size) { + MemoryMap map; + ASSERT_TRUE(map.Initialize(getpid())); + + auto mapping1 = map.FindMapping(mapping_start); + ASSERT_TRUE(mapping1); + auto mapping2 = map.FindMapping(mapping_start + page_size); + ASSERT_TRUE(mapping2); + auto mapping3 = map.FindMapping(mapping_start + page_size * 2); + ASSERT_TRUE(mapping3); + + ASSERT_NE(mapping1, mapping2); + ASSERT_NE(mapping2, mapping3); + + EXPECT_EQ(map.FindFileMmapStart(*mapping1), mapping1); + EXPECT_EQ(map.FindFileMmapStart(*mapping2), mapping2); + EXPECT_EQ(map.FindFileMmapStart(*mapping3), mapping1); +} + +TEST(MemoryMap, FindFileMmapStart) { + const size_t page_size = getpagesize(); + + ScopedTempDir temp_dir; + base::FilePath path = + temp_dir.path().Append(FILE_PATH_LITERAL("FindFileMmapStartTestFile")); + ScopedFileHandle handle; + size_t file_length = page_size * 3; + ASSERT_NO_FATAL_FAILURE(InitializeFile(path, file_length, &handle)); + + ScopedMmap file_mapping; + ASSERT_TRUE(file_mapping.ResetMmap( + nullptr, file_length, PROT_READ, MAP_PRIVATE, handle.get(), 0)); + auto mapping_start = file_mapping.addr_as(); + + // Change the permissions on the second page to split the mapping into three + // parts. + ASSERT_EQ(mprotect(file_mapping.addr_as() + page_size, + page_size, + PROT_READ | PROT_WRITE), + 0); + + // Basic + { + MemoryMap map; + ASSERT_TRUE(map.Initialize(getpid())); + + auto mapping1 = map.FindMapping(mapping_start); + ASSERT_TRUE(mapping1); + auto mapping2 = map.FindMapping(mapping_start + page_size); + ASSERT_TRUE(mapping2); + auto mapping3 = map.FindMapping(mapping_start + page_size * 2); + ASSERT_TRUE(mapping3); + + ASSERT_NE(mapping1, mapping2); + ASSERT_NE(mapping2, mapping3); + + EXPECT_EQ(map.FindFileMmapStart(*mapping1), mapping1); + EXPECT_EQ(map.FindFileMmapStart(*mapping2), mapping1); + EXPECT_EQ(map.FindFileMmapStart(*mapping3), mapping1); + +#if defined(ARCH_CPU_64_BITS) + constexpr bool is_64_bit = true; +#else + constexpr bool is_64_bit = false; +#endif + MemoryMap::Mapping bad_mapping; + bad_mapping.range.SetRange(is_64_bit, 0, 1); + EXPECT_EQ(map.FindFileMmapStart(bad_mapping), nullptr); + } + + // Make the second page an anonymous mapping + file_mapping.ResetAddrLen(file_mapping.addr_as(), page_size); + ScopedMmap page2_mapping; + ASSERT_TRUE(page2_mapping.ResetMmap(file_mapping.addr_as() + page_size, + page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, + -1, + 0)); + ScopedMmap page3_mapping; + ASSERT_TRUE( + page3_mapping.ResetMmap(file_mapping.addr_as() + page_size * 2, + page_size, + PROT_READ, + MAP_PRIVATE | MAP_FIXED, + handle.get(), + page_size * 2)); + ExpectFindFileMmapStart(mapping_start, page_size); + + // Map the second page to another file. + ScopedFileHandle handle2; + base::FilePath path2 = + temp_dir.path().Append(FILE_PATH_LITERAL("FindFileMmapStartTestFile2")); + ASSERT_NO_FATAL_FAILURE(InitializeFile(path2, page_size, &handle2)); + + page2_mapping.ResetMmap(file_mapping.addr_as() + page_size, + page_size, + PROT_READ, + MAP_PRIVATE | MAP_FIXED, + handle2.get(), + 0); + ExpectFindFileMmapStart(mapping_start, page_size); +} + } // namespace } // namespace test } // namespace crashpad From 041a50d75c4c74215b1952c38e18b34156a28171 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Fri, 14 Jul 2017 10:00:28 -0700 Subject: [PATCH 13/30] linux: Add DebugRendezvous to read dynamic linker data structures Dynamic linkers use `struct r_debug` and `struct link_map` (defined in ``) to communicate lists of loaded modules to debuggers. Bug: crashpad:30 Change-Id: Id903a1c199288dd85c34e38710cdb4c6b5fedb5b Reviewed-on: https://chromium-review.googlesource.com/534853 Reviewed-by: Mark Mentovai --- snapshot/linux/debug_rendezvous.cc | 143 +++++++++++++++ snapshot/linux/debug_rendezvous.h | 88 ++++++++++ snapshot/linux/debug_rendezvous_test.cc | 220 ++++++++++++++++++++++++ snapshot/linux/elf_image_reader.h | 13 ++ snapshot/snapshot.gyp | 2 + snapshot/snapshot_test.gyp | 1 + util/linux/process_memory_range.h | 6 + 7 files changed, 473 insertions(+) create mode 100644 snapshot/linux/debug_rendezvous.cc create mode 100644 snapshot/linux/debug_rendezvous.h create mode 100644 snapshot/linux/debug_rendezvous_test.cc diff --git a/snapshot/linux/debug_rendezvous.cc b/snapshot/linux/debug_rendezvous.cc new file mode 100644 index 00000000..e47fc0c6 --- /dev/null +++ b/snapshot/linux/debug_rendezvous.cc @@ -0,0 +1,143 @@ +// 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 "snapshot/linux/debug_rendezvous.h" + +#include + +#include + +#include "base/logging.h" + +namespace crashpad { + +namespace { + +struct Traits32 { + using Integer = int32_t; + using Address = uint32_t; +}; + +struct Traits64 { + using Integer = int64_t; + using Address = uint64_t; +}; + +template +struct DebugRendezvousSpecific { + typename Traits::Integer r_version; + typename Traits::Address r_map; + typename Traits::Address r_brk; + typename Traits::Integer r_state; + typename Traits::Address r_ldbase; +}; + +template +struct LinkEntrySpecific { + typename Traits::Address l_addr; + typename Traits::Address l_name; + typename Traits::Address l_ld; + typename Traits::Address l_next; + typename Traits::Address l_prev; +}; + +template +bool ReadLinkEntry(const ProcessMemoryRange& memory, + LinuxVMAddress* address, + DebugRendezvous::LinkEntry* entry_out) { + LinkEntrySpecific entry; + if (!memory.Read(*address, sizeof(entry), &entry)) { + return false; + } + + std::string name; + if (!memory.ReadCStringSizeLimited(entry.l_name, 4096, &name)) { + return false; + } + + entry_out->load_bias = entry.l_addr; + entry_out->dynamic_array = entry.l_ld; + entry_out->name.swap(name); + + *address = entry.l_next; + return true; +} + +} // namespace + +DebugRendezvous::LinkEntry::LinkEntry() + : name(), load_bias(0), dynamic_array(0) {} + +DebugRendezvous::DebugRendezvous() + : modules_(), executable_(), initialized_() {} + +DebugRendezvous::~DebugRendezvous() {} + +bool DebugRendezvous::Initialize(const ProcessMemoryRange& memory, + LinuxVMAddress address) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + if (!(memory.Is64Bit() ? InitializeSpecific(memory, address) + : InitializeSpecific(memory, address))) { + return false; + } + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +const DebugRendezvous::LinkEntry* DebugRendezvous::Executable() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return &executable_; +} + +const std::vector& DebugRendezvous::Modules() + const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return modules_; +} + +template +bool DebugRendezvous::InitializeSpecific(const ProcessMemoryRange& memory, + LinuxVMAddress address) { + DebugRendezvousSpecific debug; + if (!memory.Read(address, sizeof(debug), &debug)) { + return false; + } + if (debug.r_version != 1) { + LOG(ERROR) << "unexpected version " << debug.r_version; + return false; + } + + LinuxVMAddress link_entry_address = debug.r_map; + if (!ReadLinkEntry(memory, &link_entry_address, &executable_)) { + return false; + } + + std::set visited; + while (link_entry_address) { + if (!visited.insert(link_entry_address).second) { + LOG(ERROR) << "cycle at address 0x" << std::hex << link_entry_address; + return false; + } + + LinkEntry entry; + if (!ReadLinkEntry(memory, &link_entry_address, &entry)) { + return false; + } + modules_.push_back(entry); + } + + return true; +} + +} // namespace crashpad diff --git a/snapshot/linux/debug_rendezvous.h b/snapshot/linux/debug_rendezvous.h new file mode 100644 index 00000000..d9b90f68 --- /dev/null +++ b/snapshot/linux/debug_rendezvous.h @@ -0,0 +1,88 @@ +// 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_SNAPSHOT_LINUX_DEBUG_RENDEZVOUS_H_ +#define CRASHPAD_SNAPSHOT_LINUX_DEBUG_RENDEZVOUS_H_ + +#include +#include + +#include "base/macros.h" +#include "util/linux/address_types.h" +#include "util/linux/process_memory_range.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +//! \brief Reads an `r_debug` struct defined in `` via +//! ProcessMemoryRange. +class DebugRendezvous { + public: + //! \brief An entry in the dynamic linker's list of loaded objects. + //! + //! All of these values should be checked before use. Whether and how they are + //! populated may vary by dynamic linker. + struct LinkEntry { + LinkEntry(); + + //! \brief A filename identifying the object. + std::string name; + + //! \brief The difference between the preferred load address in the ELF file + //! and the actual loaded address in memory. + LinuxVMOffset load_bias; + + //! \brief The address of the dynamic array for this object. + LinuxVMAddress dynamic_array; + }; + + DebugRendezvous(); + ~DebugRendezvous(); + + //! \brief Initializes this object by reading an `r_debug` struct from a + //! target process. + //! + //! This method must be called successfully prior to calling any other method + //! in this class. + //! + //! \param[in] memory A memory reader for the remote process. + //! \param[in] address The address of an `r_debug` struct in the remote + //! process. + //! \return `true` on success. `false` on failure with a message logged. + bool Initialize(const ProcessMemoryRange& memory, LinuxVMAddress address); + + //! \brief Returns the LinkEntry for the main executable. + const LinkEntry* Executable() const; + + //! \brief Returns a vector of modules found in the link map. + //! + //! This list excludes the entry for the executable and may include entries + //! for the VDSO and loader. + const std::vector& Modules() const; + + private: + template + bool InitializeSpecific(const ProcessMemoryRange& memory, + LinuxVMAddress address); + + std::vector modules_; + LinkEntry executable_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(DebugRendezvous); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_DEBUG_RENDEZVOUS_H_ diff --git a/snapshot/linux/debug_rendezvous_test.cc b/snapshot/linux/debug_rendezvous_test.cc new file mode 100644 index 00000000..5d50f8a4 --- /dev/null +++ b/snapshot/linux/debug_rendezvous_test.cc @@ -0,0 +1,220 @@ +// 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 "snapshot/linux/debug_rendezvous.h" + +#include +#include + +#include + +#include "base/format_macros.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "gtest/gtest.h" +#include "snapshot/linux/elf_image_reader.h" +#include "test/multiprocess.h" +#include "util/linux/address_types.h" +#include "util/linux/auxiliary_vector.h" +#include "util/linux/memory_map.h" +#include "util/linux/process_memory.h" +#include "util/linux/process_memory_range.h" + +#if defined(OS_ANDROID) +#include +#endif + +namespace crashpad { +namespace test { +namespace { + +#if defined(OS_ANDROID) +int AndroidRuntimeAPI() { + char api_string[PROP_VALUE_MAX]; + int length = __system_property_get("ro.build.version.sdk", api_string); + if (length <= 0) { + return -1; + } + + int api_level; + bool success = + base::StringToInt(base::StringPiece(api_string, length), &api_level); + return success ? api_level : -1; +} +#endif // OS_ANDROID + +void TestAgainstTarget(pid_t pid, bool is_64_bit) { + // Use ElfImageReader on the main executable which can tell us the debug + // address. glibc declares the symbol _r_debug in link.h which we can use to + // get the address, but Android does not. + AuxiliaryVector aux; + ASSERT_TRUE(aux.Initialize(pid, is_64_bit)); + + LinuxVMAddress phdrs; + ASSERT_TRUE(aux.GetValue(AT_PHDR, &phdrs)); + + MemoryMap mappings; + ASSERT_TRUE(mappings.Initialize(pid)); + + const MemoryMap::Mapping* phdr_mapping = mappings.FindMapping(phdrs); + ASSERT_TRUE(phdr_mapping); + const MemoryMap::Mapping* exe_mapping = + mappings.FindFileMmapStart(*phdr_mapping); + LinuxVMAddress elf_address = exe_mapping->range.Base(); + + ProcessMemory memory; + ASSERT_TRUE(memory.Initialize(pid)); + ProcessMemoryRange range; + ASSERT_TRUE(range.Initialize(&memory, is_64_bit)); + + ElfImageReader exe_reader; + ASSERT_TRUE(exe_reader.Initialize(range, elf_address)); + LinuxVMAddress debug_address; + ASSERT_TRUE(exe_reader.GetDebugAddress(&debug_address)); + + // start the actual tests + DebugRendezvous debug; + ASSERT_TRUE(debug.Initialize(range, debug_address)); + +#if defined(OS_ANDROID) + const int android_runtime_api = AndroidRuntimeAPI(); + ASSERT_GE(android_runtime_api, 1); + + EXPECT_NE(debug.Executable()->name.find("crashpad_snapshot_test"), + std::string::npos); + + // Android's loader never sets the dynamic array for the executable. + EXPECT_EQ(debug.Executable()->dynamic_array, 0u); +#else + // glibc's loader implements most of the tested features that Android's was + // missing but has since gained. + const int android_runtime_api = std::numeric_limits::max(); + + // glibc's loader does not set the name for the executable. + EXPECT_TRUE(debug.Executable()->name.empty()); + CheckedLinuxAddressRange exe_range( + is_64_bit, exe_reader.Address(), exe_reader.Size()); + EXPECT_TRUE(exe_range.ContainsValue(debug.Executable()->dynamic_array)); +#endif // OS_ANDROID + + // Android's loader doesn't set the load bias until Android 4.3 (API 18). + if (android_runtime_api >= 18) { + EXPECT_EQ(debug.Executable()->load_bias, exe_reader.GetLoadBias()); + } else { + EXPECT_EQ(debug.Executable()->load_bias, 0); + } + + for (const DebugRendezvous::LinkEntry& module : debug.Modules()) { + SCOPED_TRACE(base::StringPrintf("name %s, load_bias 0x%" PRIx64 + ", dynamic_array 0x%" PRIx64, + module.name.c_str(), + module.load_bias, + module.dynamic_array)); + const bool is_android_loader = (module.name == "/system/bin/linker" || + module.name == "/system/bin/linker64"); + + // Android's loader doesn't set its own dynamic array until Android 4.2 + // (API 17). + if (is_android_loader && android_runtime_api < 17) { + EXPECT_EQ(module.dynamic_array, 0u); + EXPECT_EQ(module.load_bias, 0); + continue; + } + + ASSERT_TRUE(module.dynamic_array); + const MemoryMap::Mapping* dyn_mapping = + mappings.FindMapping(module.dynamic_array); + ASSERT_TRUE(dyn_mapping); + + const MemoryMap::Mapping* module_mapping = + mappings.FindFileMmapStart(*dyn_mapping); + ASSERT_TRUE(module_mapping); + +#if defined(OS_ANDROID) + EXPECT_FALSE(module.name.empty()); +#else + // glibc's loader doesn't set the name in the link map for the vdso. + EXPECT_PRED4( + [](const std::string mapping_name, + int device, + int inode, + const std::string& module_name) { + return module_name.empty() == + (device == 0 && inode == 0 && mapping_name == "[vdso]"); + }, + module_mapping->name, + module_mapping->device, + module_mapping->inode, + module.name); +#endif // OS_ANDROID + + ElfImageReader module_reader; + ASSERT_TRUE(module_reader.Initialize(range, module_mapping->range.Base())); + + // Android's loader stops setting its own load bias after Android 4.4.4 + // (API 20) until Android 6.0 (API 23). + if (is_android_loader && android_runtime_api > 20 && + android_runtime_api < 23) { + EXPECT_EQ(module.load_bias, 0); + } else { + EXPECT_EQ(module.load_bias, module_reader.GetLoadBias()); + } + + CheckedLinuxAddressRange module_range( + is_64_bit, module_reader.Address(), module_reader.Size()); + EXPECT_TRUE(module_range.ContainsValue(module.dynamic_array)); + } +} + +TEST(DebugRendezvous, Self) { +#if defined(ARCH_CPU_64_BITS) + constexpr bool is_64_bit = true; +#else + constexpr bool is_64_bit = false; +#endif + + TestAgainstTarget(getpid(), is_64_bit); +} + +class ChildTest : public Multiprocess { + public: + ChildTest() {} + ~ChildTest() {} + + private: + void MultiprocessParent() { +#if defined(ARCH_CPU_64_BITS) + constexpr bool is_64_bit = true; +#else + constexpr bool is_64_bit = false; +#endif + + TestAgainstTarget(ChildPID(), is_64_bit); + } + + void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); } + + DISALLOW_COPY_AND_ASSIGN(ChildTest); +}; + +TEST(DebugRendezvous, Child) { + ChildTest test; + test.Run(); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/snapshot/linux/elf_image_reader.h b/snapshot/linux/elf_image_reader.h index 6c620095..8820e243 100644 --- a/snapshot/linux/elf_image_reader.h +++ b/snapshot/linux/elf_image_reader.h @@ -49,6 +49,19 @@ class ElfImageReader { //! the ELF image is loaded. bool Initialize(const ProcessMemoryRange& memory, LinuxVMAddress address); + //! \brief Returns the base address of the image's memory range. + //! + //! This may differ from the address passed to Initialize() if the ELF header + //! is not loaded at the start of the first `PT_LOAD` segment. + LinuxVMAddress Address() const { return memory_.Base(); } + + //! \brief Returns the size of the range containing all loaded segments for + //! this image. + //! + //! The size may include memory that is unmapped or mapped to other objects if + //! this image's `PT_LOAD` segments are not contiguous. + LinuxVMSize Size() const { return memory_.Size(); } + //! \brief Returns the file type for the image. //! //! Possible values include `ET_EXEC` or `ET_DYN` from ``. diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index b4efc2ce..81945f02 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -40,6 +40,8 @@ 'exception_snapshot.h', 'handle_snapshot.cc', 'handle_snapshot.h', + 'linux/debug_rendezvous.cc', + 'linux/debug_rendezvous.h', 'linux/elf_dynamic_array_reader.cc', 'linux/elf_dynamic_array_reader.h', 'linux/elf_image_reader.cc', diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index d8a2d143..dbc85d7b 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -70,6 +70,7 @@ 'cpu_context_test.cc', 'crashpad_info_client_options_test.cc', 'api/module_annotations_win_test.cc', + 'linux/debug_rendezvous_test.cc', 'linux/elf_image_reader_test.cc', 'mac/cpu_context_mac_test.cc', 'mac/mach_o_image_annotations_reader_test.cc', diff --git a/util/linux/process_memory_range.h b/util/linux/process_memory_range.h index eb08de86..f569ee84 100644 --- a/util/linux/process_memory_range.h +++ b/util/linux/process_memory_range.h @@ -70,6 +70,12 @@ class ProcessMemoryRange { //! \brief Returns whether the range is part of a 64-bit address space. bool Is64Bit() const { return range_.Is64Bit(); } + //! \brief Returns the base address of the range. + LinuxVMAddress Base() const { return range_.Base(); } + + //! \brief Returns the size of the range. + LinuxVMSize Size() const { return range_.Size(); } + //! \brief Shrinks the range to the new base and size. //! //! The new range must be contained within the existing range for this object. From 6ab73e0ad8ac9d72fee557bb021ba8e33864b905 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 14 Jul 2017 16:00:21 -0400 Subject: [PATCH 14/30] linux: #include appropriate headers for ElfImageReader Bug: crashpad:30 Change-Id: I749a3493ec6a76dac904b36676330c5e487f356d Reviewed-on: https://chromium-review.googlesource.com/571956 Reviewed-by: Joshua Peraza --- snapshot/linux/elf_image_reader.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/snapshot/linux/elf_image_reader.cc b/snapshot/linux/elf_image_reader.cc index 029746f7..07fdfcf5 100644 --- a/snapshot/linux/elf_image_reader.cc +++ b/snapshot/linux/elf_image_reader.cc @@ -14,8 +14,10 @@ #include "snapshot/linux/elf_image_reader.h" -#include +#include + #include +#include #include "base/logging.h" From 5536baff1392316eea68c6b2f94cdcdc890cbe9f Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Tue, 18 Jul 2017 16:42:58 -0700 Subject: [PATCH 15/30] linux: Use PTRACE_GET_THREAD_AREA for x86 ThreadInfo.GetThreadArea Linux supports TLS on x86 by allocating slots in the GDT, accessible via the system calls get/set_thread_area. This allows segment registers (%gs on x86) to be used to quickly access the TLS. Previously, we used PTRACE_GETREGSET with the NT_386_TLS regset. This "register set" provides access to the subarray of the GDT used for TLS. However, there are multiple slots provided and we don't know which one is being used by the threading library for the current thread's TLS. Previously, we were just using the first one, which worked for x86 on 64-bit kernels, but not 32-bit kernels. On 32-bit kernels, the first slot ended up pointing to the TLS of the main thread. The authoritative index of the current thread's TLS in the GDT is given by bits 3-15 of %gs. However, this index cannot be used with PTRACE_GETREGSET+NT386_TLS because we don't know the location of the TLS slots in the GDT. PTRACE_GET_THREAD_AREA, however, accepts an index from the start of the GDT similarly to get/set_thread_area. Bug: crashpad:30 Change-Id: Ie6dfbdd088c6816fad409812a1a97037d4b38fd7 Reviewed-on: https://chromium-review.googlesource.com/575318 Reviewed-by: Mark Mentovai --- compat/compat.gyp | 10 ++++++++++ compat/linux/sys/ptrace.h | 27 +++++++++++++++++++++++++++ util/linux/thread_info.cc | 13 ++++++------- 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 compat/linux/sys/ptrace.h diff --git a/compat/compat.gyp b/compat/compat.gyp index e2b2df6d..e14bb498 100644 --- a/compat/compat.gyp +++ b/compat/compat.gyp @@ -94,6 +94,16 @@ ], }, }], + ['OS=="linux"', { + 'include_dirs': [ + 'linux', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'linux', + ], + }, + }], ], }, ], diff --git a/compat/linux/sys/ptrace.h b/compat/linux/sys/ptrace.h new file mode 100644 index 00000000..57c5c5ba --- /dev/null +++ b/compat/linux/sys/ptrace.h @@ -0,0 +1,27 @@ +// 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_COMPAT_LINUX_SYS_PTRACE_H_ +#define CRASHPAD_COMPAT_LINUX_SYS_PTRACE_H_ + +#include_next + +#include + +#if defined(__GLIBC__) && defined(__x86_64__) +static constexpr __ptrace_request PTRACE_GET_THREAD_AREA = + static_cast<__ptrace_request>(25); +#endif // __GLIBC__ && __x86_64__ + +#endif // CRASHPAD_COMPAT_LINUX_SYS_PTRACE_H_ diff --git a/util/linux/thread_info.cc b/util/linux/thread_info.cc index 300ae7d3..f63106a6 100644 --- a/util/linux/thread_info.cc +++ b/util/linux/thread_info.cc @@ -283,17 +283,16 @@ bool ThreadInfo::GetThreadArea(LinuxVMAddress* address) { return true; } + size_t index = (context_.t32.xgs & 0xffff) >> 3; user_desc desc; - iovec iov; - iov.iov_base = &desc; - iov.iov_len = sizeof(desc); - *address = 0; - if (ptrace( - PTRACE_GETREGSET, tid_, reinterpret_cast(NT_386_TLS), &iov) != - 0) { + if (ptrace(PTRACE_GET_THREAD_AREA, + tid_, + reinterpret_cast(index), + &desc) != 0) { PLOG(ERROR) << "ptrace"; return false; } + *address = desc.base_addr; return true; From 6b5f139d88ce962b18d9de167d53b767744b27a4 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 19 Jul 2017 10:56:20 -0700 Subject: [PATCH 16/30] linux: Add ProcessReader ProcessReader is responsible for collecting information needed to build a snapshot of the target process, independent of the Snapshot interface. This CL includes implementation and tests for collecting thread information, but does not yet collect module information. Bug: crashpad:30 Change-Id: I911f155c953129a5fa8c031e923c0de2bd740ce0 Reviewed-on: https://chromium-review.googlesource.com/488162 Reviewed-by: Mark Mentovai --- compat/android/sys/syscall.h | 25 ++ snapshot/linux/process_reader.cc | 281 ++++++++++++++++ snapshot/linux/process_reader.h | 107 ++++++ snapshot/linux/process_reader_test.cc | 450 ++++++++++++++++++++++++++ snapshot/snapshot.gyp | 2 + snapshot/snapshot_test.gyp | 1 + 6 files changed, 866 insertions(+) create mode 100644 compat/android/sys/syscall.h create mode 100644 snapshot/linux/process_reader.cc create mode 100644 snapshot/linux/process_reader.h create mode 100644 snapshot/linux/process_reader_test.cc diff --git a/compat/android/sys/syscall.h b/compat/android/sys/syscall.h new file mode 100644 index 00000000..4d1253dc --- /dev/null +++ b/compat/android/sys/syscall.h @@ -0,0 +1,25 @@ +// 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_COMPAT_ANDROID_SYS_SYSCALL_H_ +#define CRASHPAD_COMPAT_ANDROID_SYS_SYSCALL_H_ + +#include_next + +// Android 5.0.0 (API 21) NDK +#if !defined(SYS_gettid) +#define SYS_gettid __NR_gettid +#endif + +#endif // CRASHPAD_COMPAT_ANDROID_SYS_SYSCALL_H_ diff --git a/snapshot/linux/process_reader.cc b/snapshot/linux/process_reader.cc new file mode 100644 index 00000000..91d2bb46 --- /dev/null +++ b/snapshot/linux/process_reader.cc @@ -0,0 +1,281 @@ +// 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 "snapshot/linux/process_reader.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "build/build_config.h" +#include "util/posix/scoped_dir.h" + +namespace crashpad { + +namespace { + +bool ShouldMergeStackMappings(const MemoryMap::Mapping& stack_mapping, + const MemoryMap::Mapping& adj_mapping) { + DCHECK(stack_mapping.readable); + return adj_mapping.readable && stack_mapping.device == adj_mapping.device && + stack_mapping.inode == adj_mapping.inode; +} + +} // namespace + +ProcessReader::Thread::Thread() + : thread_context(), + float_context(), + thread_specific_data_address(0), + stack_region_address(0), + stack_region_size(0), + tid(-1), + static_priority(-1), + nice_value(-1) {} + +ProcessReader::Thread::~Thread() {} + +bool ProcessReader::Thread::InitializePtrace() { + ThreadInfo thread_info; + if (!thread_info.Initialize(tid)) { + return false; + } + + thread_info.GetGeneralPurposeRegisters(&thread_context); + + if (!thread_info.GetFloatingPointRegisters(&float_context)) { + return false; + } + + if (!thread_info.GetThreadArea(&thread_specific_data_address)) { + return false; + } + + // TODO(jperaza): Starting with Linux 3.14, scheduling policy, static + // priority, and nice value can be collected all in one call with + // sched_getattr(). + int res = sched_getscheduler(tid); + if (res < 0) { + PLOG(ERROR) << "sched_getscheduler"; + return false; + } + sched_policy = res; + + sched_param param; + if (sched_getparam(tid, ¶m) != 0) { + PLOG(ERROR) << "sched_getparam"; + return false; + } + static_priority = param.sched_priority; + + errno = 0; + res = getpriority(PRIO_PROCESS, tid); + if (res == -1 && errno) { + PLOG(ERROR) << "getpriority"; + return false; + } + nice_value = res; + + return true; +} + +void ProcessReader::Thread::InitializeStack(ProcessReader* reader) { + LinuxVMAddress stack_pointer; +#if defined(ARCH_CPU_X86_FAMILY) + stack_pointer = + reader->Is64Bit() ? thread_context.t64.rsp : thread_context.t32.esp; +#elif defined(ARCH_CPU_ARM_FAMILY) + stack_pointer = + reader->Is64Bit() ? thread_context.t64.sp : thread_context.t32.sp; +#else +#error Port. +#endif + + const MemoryMap* memory_map = reader->GetMemoryMap(); + + // If we can't find the mapping, it's probably a bad stack pointer + const MemoryMap::Mapping* mapping = memory_map->FindMapping(stack_pointer); + if (!mapping) { + LOG(WARNING) << "no stack mapping"; + return; + } + LinuxVMAddress stack_region_start = stack_pointer; + + // We've hit what looks like a guard page; skip to the end and check for a + // mapped stack region. + if (!mapping->readable) { + stack_region_start = mapping->range.End(); + mapping = memory_map->FindMapping(stack_region_start); + if (!mapping) { + LOG(WARNING) << "no stack mapping"; + return; + } + } else { +#if defined(ARCH_CPU_X86_FAMILY) + // Adjust start address to include the red zone + if (reader->Is64Bit()) { + const LinuxVMSize kRedZoneSize = 128; + LinuxVMAddress red_zone_base = + stack_region_start - std::min(kRedZoneSize, stack_region_start); + + // Only include the red zone if it is part of a valid mapping + if (red_zone_base >= mapping->range.Base()) { + stack_region_start = red_zone_base; + } else { + const MemoryMap::Mapping* rz_mapping = + memory_map->FindMapping(red_zone_base); + if (rz_mapping && ShouldMergeStackMappings(*mapping, *rz_mapping)) { + stack_region_start = red_zone_base; + } else { + stack_region_start = mapping->range.Base(); + } + } + } +#endif + } + stack_region_address = stack_region_start; + + // If there are more mappings at the end of this one, they may be a + // continuation of the stack. + LinuxVMAddress stack_end = mapping->range.End(); + const MemoryMap::Mapping* next_mapping; + while ((next_mapping = memory_map->FindMapping(stack_end)) && + ShouldMergeStackMappings(*mapping, *next_mapping)) { + stack_end = next_mapping->range.End(); + } + + // The main thread should have an entry in the maps file just for its stack, + // so we'll assume the base of the stack is at the end of the region. Other + // threads' stacks may not have their own entries in the maps file if they + // were user-allocated within a larger mapping, but pthreads places the TLS + // at the high-address end of the stack so we can try using that to shrink + // the stack region. + stack_region_size = stack_end - stack_region_address; + if (tid != reader->ProcessID() && + thread_specific_data_address > stack_region_address && + thread_specific_data_address < stack_end) { + stack_region_size = thread_specific_data_address - stack_region_address; + } +} + +ProcessReader::ProcessReader() + : process_info_(), + memory_map_(), + threads_(), + process_memory_(), + is_64_bit_(false), + initialized_threads_(false), + initialized_() {} + +ProcessReader::~ProcessReader() {} + +bool ProcessReader::Initialize(pid_t pid) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + if (!process_info_.Initialize(pid)) { + return false; + } + + if (!memory_map_.Initialize(pid)) { + return false; + } + + process_memory_.reset(new ProcessMemory()); + if (!process_memory_->Initialize(pid)) { + return false; + } + + if (!process_info_.Is64Bit(&is_64_bit_)) { + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +const std::vector& ProcessReader::Threads() { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!initialized_threads_) { + InitializeThreads(); + } + return threads_; +} + +void ProcessReader::InitializeThreads() { + DCHECK(threads_.empty()); + + pid_t pid = ProcessID(); + if (pid == getpid()) { + // TODO(jperaza): ptrace can't be used on threads in the same thread group. + // Using clone to create a new thread in it's own thread group doesn't work + // because glibc doesn't support threads it didn't create via pthreads. + // Fork a new process to snapshot us and copy the data back? + LOG(ERROR) << "not implemented"; + return; + } + + char path[32]; + snprintf(path, arraysize(path), "/proc/%d/task", pid); + DIR* dir = opendir(path); + if (!dir) { + PLOG(ERROR) << "opendir"; + return; + } + ScopedDIR scoped_dir(dir); + + Thread main_thread; + main_thread.tid = pid; + if (main_thread.InitializePtrace()) { + main_thread.InitializeStack(this); + threads_.push_back(main_thread); + } else { + LOG(WARNING) << "Couldn't initialize main thread."; + } + + bool main_thread_found = false; + dirent* dir_entry; + while ((dir_entry = readdir(scoped_dir.get()))) { + if (strncmp(dir_entry->d_name, ".", arraysize(dir_entry->d_name)) == 0 || + strncmp(dir_entry->d_name, "..", arraysize(dir_entry->d_name)) == 0) { + continue; + } + pid_t tid; + if (!base::StringToInt(dir_entry->d_name, &tid)) { + LOG(ERROR) << "format error"; + continue; + } + + if (tid == pid) { + DCHECK(!main_thread_found); + main_thread_found = true; + continue; + } + + Thread thread; + thread.tid = tid; + if (thread.InitializePtrace()) { + thread.InitializeStack(this); + threads_.push_back(thread); + } + } + DCHECK(main_thread_found); +} + +} // namespace crashpad diff --git a/snapshot/linux/process_reader.h b/snapshot/linux/process_reader.h new file mode 100644 index 00000000..64adac5c --- /dev/null +++ b/snapshot/linux/process_reader.h @@ -0,0 +1,107 @@ +// 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_SNAPSHOT_LINUX_PROCESS_READER_H_ +#define CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_H_ + +#include + +#include +#include + +#include "base/macros.h" +#include "util/linux/address_types.h" +#include "util/linux/memory_map.h" +#include "util/linux/process_memory.h" +#include "util/linux/thread_info.h" +#include "util/posix/process_info.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +//! \brief Accesses information about another process, identified by a process +//! ID. +class ProcessReader { + public: + //! \brief Contains information about a thread that belongs to a process. + struct Thread { + Thread(); + ~Thread(); + + ThreadContext thread_context; + FloatContext float_context; + LinuxVMAddress thread_specific_data_address; + LinuxVMAddress stack_region_address; + LinuxVMSize stack_region_size; + pid_t tid; + int sched_policy; + int static_priority; + int nice_value; + + private: + friend class ProcessReader; + + bool InitializePtrace(); + void InitializeStack(ProcessReader* reader); + }; + + ProcessReader(); + ~ProcessReader(); + + //! \brief Initializes this object. + //! + //! This method must be successfully called before calling any other method in + //! this class. + //! + //! \param[in] pid The process ID of the target process. + //! \return `true` on success. `false` on failure with a message logged. + bool Initialize(pid_t pid); + + //! \brief Return `true` if the target task is a 64-bit process. + bool Is64Bit() const { return is_64_bit_; } + + //! \brief Return the target process' process ID. + pid_t ProcessID() const { return process_info_.ProcessID(); } + + //! \brief Return the target process' parent process ID. + pid_t ParentProcessID() const { return process_info_.ParentProcessID(); } + + //! \brief Return a memory reader for the target process. + ProcessMemory* Memory() { return process_memory_.get(); } + + //! \brief Return a memory map of the target process. + MemoryMap* GetMemoryMap() { return &memory_map_; } + + //! \brief Return a vector of threads that are in the task process. If the + //! main thread is able to be identified and traced, it will be placed at + //! index `0`. + const std::vector& Threads(); + + private: + void InitializeThreads(); + + ProcessInfo process_info_; + class MemoryMap memory_map_; + std::vector threads_; + std::unique_ptr process_memory_; + bool is_64_bit_; + bool initialized_threads_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProcessReader); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_H_ diff --git a/snapshot/linux/process_reader_test.cc b/snapshot/linux/process_reader_test.cc new file mode 100644 index 00000000..4acbb489 --- /dev/null +++ b/snapshot/linux/process_reader_test.cc @@ -0,0 +1,450 @@ +// 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 "snapshot/linux/process_reader.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "base/format_macros.h" +#include "base/memory/free_deleter.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "gtest/gtest.h" +#include "test/errors.h" +#include "test/multiprocess.h" +#include "util/file/file_io.h" +#include "util/misc/from_pointer_cast.h" +#include "util/stdlib/pointer_container.h" +#include "util/synchronization/semaphore.h" + +namespace crashpad { +namespace test { +namespace { + +pid_t gettid() { + return syscall(SYS_gettid); +} + +LinuxVMAddress GetTLS() { + LinuxVMAddress tls; +#if defined(ARCH_CPU_ARMEL) + // 0xffff0fe0 is the address of the kernel user helper __kuser_get_tls(). + auto kuser_get_tls = reinterpret_cast(0xffff0fe0); + tls = FromPointerCast(kuser_get_tls()); +#elif defined(ARCH_CPU_ARM64) + // Linux/aarch64 places the tls address in system register tpidr_el0. + asm("mrs %0, tpidr_el0" : "=r"(tls)); +#elif defined(ARCH_CPU_X86) + uint32_t tls_32; + asm("movl %%gs:0x0, %0" : "=r"(tls_32)); + tls = tls_32; +#elif defined(ARCH_CPU_X86_64) + asm("movq %%fs:0x0, %0" : "=r"(tls)); +#else +#error Port. +#endif // ARCH_CPU_ARMEL + + return tls; +} + +TEST(ProcessReader, SelfBasic) { + ProcessReader process_reader; + ASSERT_TRUE(process_reader.Initialize(getpid())); + +#if !defined(ARCH_CPU_64_BITS) + EXPECT_FALSE(process_reader.Is64Bit()); +#else + EXPECT_TRUE(process_reader.Is64Bit()); +#endif + + EXPECT_EQ(process_reader.ProcessID(), getpid()); + EXPECT_EQ(process_reader.ParentProcessID(), getppid()); + + const char kTestMemory[] = "Some test memory"; + char buffer[arraysize(kTestMemory)]; + ASSERT_TRUE(process_reader.Memory()->Read( + reinterpret_cast(kTestMemory), + sizeof(kTestMemory), + &buffer)); + EXPECT_STREQ(kTestMemory, buffer); +} + +const char kTestMemory[] = "Read me from another process"; + +class BasicChildTest : public Multiprocess { + public: + BasicChildTest() : Multiprocess() {} + ~BasicChildTest() {} + + private: + void MultiprocessParent() override { + ProcessReader process_reader; + ASSERT_TRUE(process_reader.Initialize(ChildPID())); + +#if !defined(ARCH_CPU_64_BITS) + EXPECT_FALSE(process_reader.Is64Bit()); +#else + EXPECT_TRUE(process_reader.Is64Bit()); +#endif + + EXPECT_EQ(process_reader.ParentProcessID(), getpid()); + EXPECT_EQ(process_reader.ProcessID(), ChildPID()); + + std::string read_string; + ASSERT_TRUE(process_reader.Memory()->ReadCString( + reinterpret_cast(kTestMemory), &read_string)); + EXPECT_EQ(read_string, kTestMemory); + } + + void MultiprocessChild() override { CheckedReadFileAtEOF(ReadPipeHandle()); } + + DISALLOW_COPY_AND_ASSIGN(BasicChildTest); +}; + +TEST(ProcessReader, ChildBasic) { + BasicChildTest test; + test.Run(); +} + +class TestThreadPool { + public: + struct ThreadExpectation { + LinuxVMAddress tls = 0; + LinuxVMAddress stack_address = 0; + LinuxVMSize max_stack_size = 0; + int sched_policy = 0; + int static_priority = 0; + int nice_value = 0; + }; + + TestThreadPool() : threads_() {} + + ~TestThreadPool() { + for (Thread* thread : threads_) { + thread->exit_semaphore.Signal(); + } + + for (const Thread* thread : threads_) { + EXPECT_EQ(pthread_join(thread->pthread, nullptr), 0) + << ErrnoMessage("pthread_join"); + } + } + + void StartThreads(size_t thread_count, size_t stack_size = 0) { + for (size_t thread_index = 0; thread_index < thread_count; ++thread_index) { + Thread* thread = new Thread(); + threads_.push_back(thread); + + pthread_attr_t attr; + ASSERT_EQ(pthread_attr_init(&attr), 0) + << ErrnoMessage("pthread_attr_init"); + + if (stack_size > 0) { + void* stack_ptr; + errno = posix_memalign(&stack_ptr, getpagesize(), stack_size); + ASSERT_EQ(errno, 0) << ErrnoMessage("posix_memalign"); + + thread->stack.reset(reinterpret_cast(stack_ptr)); + + ASSERT_EQ(pthread_attr_setstack(&attr, thread->stack.get(), stack_size), + 0) + << ErrnoMessage("pthread_attr_setstack"); + thread->expectation.max_stack_size = stack_size; + } + + ASSERT_EQ(pthread_attr_setschedpolicy(&attr, SCHED_OTHER), 0) + << ErrnoMessage("pthread_attr_setschedpolicy"); + thread->expectation.sched_policy = SCHED_OTHER; + + sched_param param; + param.sched_priority = 0; + ASSERT_EQ(pthread_attr_setschedparam(&attr, ¶m), 0) + << ErrnoMessage("pthread_attr_setschedparam"); + thread->expectation.static_priority = 0; + + thread->expectation.nice_value = thread_index % 20; + + ASSERT_EQ(pthread_create(&thread->pthread, &attr, ThreadMain, thread), 0) + << ErrnoMessage("pthread_create"); + } + + for (Thread* thread : threads_) { + thread->ready_semaphore.Wait(); + } + } + + pid_t GetThreadExpectation(size_t thread_index, + ThreadExpectation* expectation) { + CHECK_LT(thread_index, threads_.size()); + + const Thread* thread = threads_[thread_index]; + *expectation = thread->expectation; + return thread->tid; + } + + private: + struct Thread { + Thread() + : pthread(), + expectation(), + ready_semaphore(0), + exit_semaphore(0), + tid(-1) {} + ~Thread() {} + + pthread_t pthread; + ThreadExpectation expectation; + std::unique_ptr stack; + Semaphore ready_semaphore; + Semaphore exit_semaphore; + pid_t tid; + }; + + static void* ThreadMain(void* argument) { + Thread* thread = static_cast(argument); + + CHECK_EQ(setpriority(PRIO_PROCESS, 0, thread->expectation.nice_value), 0) + << ErrnoMessage("setpriority"); + + thread->expectation.tls = GetTLS(); + thread->expectation.stack_address = + reinterpret_cast(&thread); + thread->tid = gettid(); + + thread->ready_semaphore.Signal(); + thread->exit_semaphore.Wait(); + + CHECK_EQ(pthread_self(), thread->pthread); + + return nullptr; + } + + PointerVector threads_; + + DISALLOW_COPY_AND_ASSIGN(TestThreadPool); +}; + +using ThreadMap = std::map; + +void ExpectThreads(const ThreadMap& thread_map, + const std::vector& threads, + const pid_t pid) { + ASSERT_EQ(threads.size(), thread_map.size()); + MemoryMap memory_map; + ASSERT_TRUE(memory_map.Initialize(pid)); + + for (const auto& thread : threads) { + SCOPED_TRACE(base::StringPrintf("Thread id %d, tls 0x%" PRIx64 + ", stack addr 0x%" PRIx64 + ", stack size 0x%" PRIx64, + thread.tid, + thread.thread_specific_data_address, + thread.stack_region_address, + thread.stack_region_size)); + + const auto& iterator = thread_map.find(thread.tid); + ASSERT_NE(iterator, thread_map.end()); + + EXPECT_EQ(thread.thread_specific_data_address, iterator->second.tls); + + ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address)); + EXPECT_LE(thread.stack_region_address, iterator->second.stack_address); + + ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address + + thread.stack_region_size - 1)); + EXPECT_GE(thread.stack_region_address + thread.stack_region_size, + iterator->second.stack_address); + if (iterator->second.max_stack_size) { + EXPECT_LT(thread.stack_region_size, iterator->second.max_stack_size); + } + + EXPECT_EQ(thread.sched_policy, iterator->second.sched_policy); + EXPECT_EQ(thread.static_priority, iterator->second.static_priority); + EXPECT_EQ(thread.nice_value, iterator->second.nice_value); + } +} + +class ChildThreadTest : public Multiprocess { + public: + ChildThreadTest(size_t stack_size = 0) + : Multiprocess(), stack_size_(stack_size) {} + ~ChildThreadTest() {} + + private: + void MultiprocessParent() override { + ThreadMap thread_map; + for (size_t thread_index = 0; thread_index < kThreadCount + 1; + ++thread_index) { + pid_t tid; + TestThreadPool::ThreadExpectation expectation; + + CheckedReadFileExactly(ReadPipeHandle(), &tid, sizeof(tid)); + CheckedReadFileExactly( + ReadPipeHandle(), &expectation, sizeof(expectation)); + thread_map[tid] = expectation; + } + + ProcessReader process_reader; + ASSERT_TRUE(process_reader.Initialize(ChildPID())); + const std::vector& threads = + process_reader.Threads(); + ExpectThreads(thread_map, threads, ChildPID()); + } + + void MultiprocessChild() override { + TestThreadPool thread_pool; + thread_pool.StartThreads(kThreadCount, stack_size_); + + TestThreadPool::ThreadExpectation expectation; + expectation.tls = GetTLS(); + expectation.stack_address = reinterpret_cast(&thread_pool); + + int res = sched_getscheduler(0); + ASSERT_GE(res, 0) << ErrnoMessage("sched_getscheduler"); + expectation.sched_policy = res; + + sched_param param; + ASSERT_EQ(sched_getparam(0, ¶m), 0) << ErrnoMessage("sched_getparam"); + expectation.static_priority = param.sched_priority; + + errno = 0; + res = getpriority(PRIO_PROCESS, 0); + ASSERT_FALSE(res == -1 && errno) << ErrnoMessage("getpriority"); + expectation.nice_value = res; + + pid_t tid = gettid(); + + CheckedWriteFile(WritePipeHandle(), &tid, sizeof(tid)); + CheckedWriteFile(WritePipeHandle(), &expectation, sizeof(expectation)); + + for (size_t thread_index = 0; thread_index < kThreadCount; ++thread_index) { + tid = thread_pool.GetThreadExpectation(thread_index, &expectation); + CheckedWriteFile(WritePipeHandle(), &tid, sizeof(tid)); + CheckedWriteFile(WritePipeHandle(), &expectation, sizeof(expectation)); + } + + CheckedReadFileAtEOF(ReadPipeHandle()); + } + + static constexpr size_t kThreadCount = 3; + const size_t stack_size_; + + DISALLOW_COPY_AND_ASSIGN(ChildThreadTest); +}; + +TEST(ProcessReader, ChildWithThreads) { + ChildThreadTest test; + test.Run(); +} + +TEST(ProcessReader, ChildThreadsWithSmallUserStacks) { + ChildThreadTest test(PTHREAD_STACK_MIN); + test.Run(); +} + +// Tests a thread with a stack that spans multiple mappings. +class ChildWithSplitStackTest : public Multiprocess { + public: + ChildWithSplitStackTest() : Multiprocess(), page_size_(getpagesize()) {} + ~ChildWithSplitStackTest() {} + + private: + void MultiprocessParent() override { + LinuxVMAddress stack_addr1; + LinuxVMAddress stack_addr2; + LinuxVMAddress stack_addr3; + + CheckedReadFileExactly(ReadPipeHandle(), &stack_addr1, sizeof(stack_addr1)); + CheckedReadFileExactly(ReadPipeHandle(), &stack_addr2, sizeof(stack_addr2)); + CheckedReadFileExactly(ReadPipeHandle(), &stack_addr3, sizeof(stack_addr3)); + + ProcessReader process_reader; + ASSERT_TRUE(process_reader.Initialize(ChildPID())); + + const std::vector& threads = + process_reader.Threads(); + ASSERT_EQ(threads.size(), 1u); + + LinuxVMAddress thread_stack_start = threads[0].stack_region_address; + EXPECT_LE(thread_stack_start, stack_addr1); + EXPECT_LE(thread_stack_start, stack_addr2); + EXPECT_LE(thread_stack_start, stack_addr3); + + LinuxVMAddress thread_stack_end = + thread_stack_start + threads[0].stack_region_size; + EXPECT_GE(thread_stack_end, stack_addr1); + EXPECT_GE(thread_stack_end, stack_addr2); + EXPECT_GE(thread_stack_end, stack_addr3); + } + + void MultiprocessChild() override { + const LinuxVMSize stack_size = page_size_ * 3; + GrowStack(stack_size, reinterpret_cast(&stack_size)); + } + + void GrowStack(LinuxVMSize stack_size, LinuxVMAddress bottom_of_stack) { + char stack_contents[4096]; + auto stack_address = reinterpret_cast(&stack_contents); + + if (bottom_of_stack - stack_address < stack_size) { + GrowStack(stack_size, bottom_of_stack); + } else { + // Write-protect a page on our stack to split up the mapping + LinuxVMAddress page_addr = + stack_address - (stack_address % page_size_) + page_size_; + ASSERT_EQ( + mprotect(reinterpret_cast(page_addr), page_size_, PROT_READ), + 0) + << ErrnoMessage("mprotect"); + + CheckedWriteFile( + WritePipeHandle(), &bottom_of_stack, sizeof(bottom_of_stack)); + CheckedWriteFile(WritePipeHandle(), &page_addr, sizeof(page_addr)); + CheckedWriteFile( + WritePipeHandle(), &stack_address, sizeof(stack_address)); + + // Wait for parent to read us + CheckedReadFileAtEOF(ReadPipeHandle()); + + ASSERT_EQ(mprotect(reinterpret_cast(page_addr), + page_size_, + PROT_READ | PROT_WRITE), + 0) + << ErrnoMessage("mprotect"); + } + } + + const size_t page_size_; + + DISALLOW_COPY_AND_ASSIGN(ChildWithSplitStackTest); +}; + +TEST(ProcessReader, ChildWithSplitStack) { + ChildWithSplitStackTest test; + test.Run(); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 81945f02..d816c075 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -48,6 +48,8 @@ 'linux/elf_image_reader.h', 'linux/elf_symbol_table_reader.cc', 'linux/elf_symbol_table_reader.h', + 'linux/process_reader.cc', + 'linux/process_reader.h', 'mac/cpu_context_mac.cc', 'mac/cpu_context_mac.h', 'mac/exception_snapshot_mac.cc', diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index dbc85d7b..d1f1935b 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -72,6 +72,7 @@ 'api/module_annotations_win_test.cc', 'linux/debug_rendezvous_test.cc', 'linux/elf_image_reader_test.cc', + 'linux/process_reader_test.cc', 'mac/cpu_context_mac_test.cc', 'mac/mach_o_image_annotations_reader_test.cc', 'mac/mach_o_image_reader_test.cc', From 7be6b8ea1dede429e0f160ee39fa2ba34078b67e Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Thu, 20 Jul 2017 10:51:08 -0700 Subject: [PATCH 17/30] Add functions to convert native x86 contexts to Crashpad CPUContexts Debug registers are currently initialized to 0 until methods are added to ThreadInfo to collect them. Bug: crashpad:30 Change-Id: Ic1aab1151dcd4bed48eca8a60b76fb0d8d613418 Reviewed-on: https://chromium-review.googlesource.com/579889 Reviewed-by: Mark Mentovai --- snapshot/linux/cpu_context_linux.cc | 108 ++++++++++++++++++++++++++++ snapshot/linux/cpu_context_linux.h | 53 ++++++++++++++ snapshot/snapshot.gyp | 2 + util/linux/thread_info.h | 21 +++--- 4 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 snapshot/linux/cpu_context_linux.cc create mode 100644 snapshot/linux/cpu_context_linux.h diff --git a/snapshot/linux/cpu_context_linux.cc b/snapshot/linux/cpu_context_linux.cc new file mode 100644 index 00000000..d4b09a70 --- /dev/null +++ b/snapshot/linux/cpu_context_linux.cc @@ -0,0 +1,108 @@ +// 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 "snapshot/linux/cpu_context_linux.h" + +#include +#include + +#include "base/logging.h" + +namespace crashpad { +namespace internal { + +#if defined(ARCH_CPU_X86_FAMILY) + +void InitializeCPUContextX86(const ThreadContext::t32_t& thread_context, + const FloatContext::f32_t& float_context, + CPUContextX86* context) { + context->eax = thread_context.eax; + context->ebx = thread_context.ebx; + context->ecx = thread_context.ecx; + context->edx = thread_context.edx; + context->edi = thread_context.edi; + context->esi = thread_context.esi; + context->ebp = thread_context.ebp; + context->esp = thread_context.esp; + context->eip = thread_context.eip; + context->eflags = thread_context.eflags; + context->cs = thread_context.xcs; + context->ds = thread_context.xds; + context->es = thread_context.xes; + context->fs = thread_context.xfs; + context->gs = thread_context.xgs; + context->ss = thread_context.xss; + + static_assert(sizeof(context->fxsave) == sizeof(float_context.fxsave), + "fxsave size mismatch"); + memcpy(&context->fxsave, &float_context.fxsave, sizeof(context->fxsave)); + + // TODO(jperaza): debug registers + context->dr0 = 0; + context->dr1 = 0; + context->dr2 = 0; + context->dr3 = 0; + context->dr4 = 0; + context->dr5 = 0; + context->dr6 = 0; + context->dr7 = 0; + +} + +void InitializeCPUContextX86_64(const ThreadContext::t64_t& thread_context, + const FloatContext::f64_t& float_context, + CPUContextX86_64* context) { + context->rax = thread_context.rax; + context->rbx = thread_context.rbx; + context->rcx = thread_context.rcx; + context->rdx = thread_context.rdx; + context->rdi = thread_context.rdi; + context->rsi = thread_context.rsi; + context->rbp = thread_context.rbp; + context->rsp = thread_context.rsp; + context->r8 = thread_context.r8; + context->r9 = thread_context.r9; + context->r10 = thread_context.r10; + context->r11 = thread_context.r11; + context->r12 = thread_context.r12; + context->r13 = thread_context.r13; + context->r14 = thread_context.r14; + context->r15 = thread_context.r15; + context->rip = thread_context.rip; + context->rflags = thread_context.eflags; + context->cs = thread_context.cs; + context->fs = thread_context.fs; + context->gs = thread_context.gs; + + static_assert(sizeof(context->fxsave) == sizeof(float_context.fxsave), + "fxsave size mismatch"); + memcpy(&context->fxsave, &float_context.fxsave, sizeof(context->fxsave)); + + // TODO(jperaza): debug registers. + context->dr0 = 0; + context->dr1 = 0; + context->dr2 = 0; + context->dr3 = 0; + context->dr4 = 0; + context->dr5 = 0; + context->dr6 = 0; + context->dr7 = 0; +} + +#else +#error Port. +#endif // ARCH_CPU_X86_FAMILY || DOXYGEN + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/linux/cpu_context_linux.h b/snapshot/linux/cpu_context_linux.h new file mode 100644 index 00000000..0ce5d5f4 --- /dev/null +++ b/snapshot/linux/cpu_context_linux.h @@ -0,0 +1,53 @@ +// 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_SNAPSHOT_LINUX_SNAPSHOT_CPU_CONTEXT_LINUX_H_ +#define CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_CPU_CONTEXT_LINUX_H_ + +#include "build/build_config.h" +#include "snapshot/cpu_context.h" +#include "util/linux/thread_info.h" + +namespace crashpad { +namespace internal { + +#if defined(ARCH_CPU_X86_FAMILY) || DOXYGEN + +//! \brief Initializes a CPUContextX86 structure from native context structures +//! on Linux. +//! +//! \param[in] thread_context The native thread context. +//! \param[in] float_context The native float context. +//! \param[out] context The CPUContextX86 structure to initialize. +void InitializeCPUContextX86(const ThreadContext::t32_t& thread_context, + const FloatContext::f32_t& float_context, + CPUContextX86* context); + +//! \brief Initializes a CPUContextX86_64 structure from native context +//! structures on Linux. +//! +//! \param[in] thread_context The native thread context. +//! \param[in] float_context The native float context. +//! \param[out] context The CPUContextX86_64 structure to initialize. +void InitializeCPUContextX86_64(const ThreadContext::t64_t& thread_context, + const FloatContext::f64_t& float_context, + CPUContextX86_64* context); +#else +#error Port. // TODO(jperaza): ARM +#endif // ARCH_CPU_X86_FAMILY || DOXYGEN + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_CPU_CONTEXT_LINUX_H_ diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index d816c075..a85f6a27 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -40,6 +40,8 @@ 'exception_snapshot.h', 'handle_snapshot.cc', 'handle_snapshot.h', + 'linux/cpu_context_linux.cc', + 'linux/cpu_context_linux.h', 'linux/debug_rendezvous.cc', 'linux/debug_rendezvous.h', 'linux/elf_dynamic_array_reader.cc', diff --git a/util/linux/thread_info.h b/util/linux/thread_info.h index 9cb77d06..f8b97514 100644 --- a/util/linux/thread_info.h +++ b/util/linux/thread_info.h @@ -40,7 +40,7 @@ union ThreadContext { //! \brief The general purpose registers used by the 32-bit variant of the //! architecture. - struct t32 { + struct t32_t { #if defined(ARCH_CPU_X86_FAMILY) // Reflects user_regs_struct in sys/user.h. uint32_t ebx; @@ -77,7 +77,7 @@ union ThreadContext { //! \brief The general purpose registers used by the 64-bit variant of the //! architecture. - struct t64 { + struct t64_t { #if defined(ARCH_CPU_X86_FAMILY) // Reflects user_regs_struct in sys/user.h. uint64_t r15; @@ -127,9 +127,9 @@ union ThreadContext { #endif // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64 #if defined(ARCH_CPU_32_BITS) - static_assert(sizeof(t32) == sizeof(NativeThreadContext), "Size mismatch"); + static_assert(sizeof(t32_t) == sizeof(NativeThreadContext), "Size mismatch"); #else // ARCH_CPU_64_BITS - static_assert(sizeof(t64) == sizeof(NativeThreadContext), "Size mismatch"); + static_assert(sizeof(t64_t) == sizeof(NativeThreadContext), "Size mismatch"); #endif // ARCH_CPU_32_BITS }; static_assert(std::is_standard_layout::value, @@ -142,7 +142,7 @@ union FloatContext { //! \brief The floating point registers used by the 32-bit variant of the //! architecture. - struct f32 { + struct f32_t { #if defined(ARCH_CPU_X86_FAMILY) // Reflects user_fpxregs_struct in sys/user.h struct fxsave { @@ -193,7 +193,7 @@ union FloatContext { //! \brief The floating point registers used by the 64-bit variant of the //! architecture. - struct f64 { + struct f64_t { #if defined(ARCH_CPU_X86_FAMILY) // Refelects user_fpregs_struct in sys/user.h struct fxsave { @@ -228,13 +228,14 @@ union FloatContext { #else using NativeFpxregs = user_fpxregs_struct; #endif // OS_ANDROID - static_assert(sizeof(f32::fxsave) == sizeof(NativeFpxregs), "Size mismatch"); + static_assert(sizeof(f32_t::fxsave) == sizeof(NativeFpxregs), + "Size mismatch"); #elif defined(ARCH_CPU_X86_64) - static_assert(sizeof(f64::fxsave) == sizeof(user_fpregs_struct), + static_assert(sizeof(f64_t::fxsave) == sizeof(user_fpregs_struct), "Size mismatch"); #elif defined(ARCH_CPU_ARMEL) - static_assert(sizeof(f32::fpregs) == sizeof(user_fpregs), "Size mismatch"); - static_assert(sizeof(f32::vfp) == sizeof(user_vfp), "Size mismatch"); + static_assert(sizeof(f32_t::fpregs) == sizeof(user_fpregs), "Size mismatch"); + static_assert(sizeof(f32_t::vfp) == sizeof(user_vfp), "Size mismatch"); #elif defined(ARCH_CPU_ARM64) static_assert(sizeof(f64) == sizeof(user_fpsimd_struct), "Size mismatch"); #else From bde35ca918ba8598b691391fedf650287d1af6dc Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Wed, 19 Jul 2017 14:31:15 -0700 Subject: [PATCH 18/30] Add MemorySnapshotLinux Bug: crashpad:30 Change-Id: Iddd100c3806178f6d20dd903e3f41926904696d4 Reviewed-on: https://chromium-review.googlesource.com/577977 Reviewed-by: Mark Mentovai --- snapshot/linux/memory_snapshot_linux.cc | 68 ++++++++++++++++++++++++ snapshot/linux/memory_snapshot_linux.h | 69 +++++++++++++++++++++++++ snapshot/snapshot.gyp | 2 + 3 files changed, 139 insertions(+) create mode 100644 snapshot/linux/memory_snapshot_linux.cc create mode 100644 snapshot/linux/memory_snapshot_linux.h diff --git a/snapshot/linux/memory_snapshot_linux.cc b/snapshot/linux/memory_snapshot_linux.cc new file mode 100644 index 00000000..f328fefc --- /dev/null +++ b/snapshot/linux/memory_snapshot_linux.cc @@ -0,0 +1,68 @@ +// 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 "snapshot/linux/memory_snapshot_linux.h" + +#include + +namespace crashpad { +namespace internal { + +MemorySnapshotLinux::MemorySnapshotLinux() + : MemorySnapshot(), + process_reader_(nullptr), + address_(0), + size_(0), + initialized_() { +} + +MemorySnapshotLinux::~MemorySnapshotLinux() { +} + +void MemorySnapshotLinux::Initialize(ProcessReader* process_reader, + LinuxVMAddress address, + size_t size) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + process_reader_ = process_reader; + address_ = address; + size_ = size; + INITIALIZATION_STATE_SET_VALID(initialized_); +} + +uint64_t MemorySnapshotLinux::Address() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return address_; +} + +size_t MemorySnapshotLinux::Size() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return size_; +} + +bool MemorySnapshotLinux::Read(Delegate* delegate) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + if (size_ == 0) { + return delegate->MemorySnapshotDelegateRead(nullptr, size_); + } + + std::unique_ptr buffer(new uint8_t[size_]); + if (!process_reader_->Memory()->Read(address_, size_, buffer.get())) { + return false; + } + return delegate->MemorySnapshotDelegateRead(buffer.get(), size_); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/linux/memory_snapshot_linux.h b/snapshot/linux/memory_snapshot_linux.h new file mode 100644 index 00000000..3c7c8391 --- /dev/null +++ b/snapshot/linux/memory_snapshot_linux.h @@ -0,0 +1,69 @@ +// 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_SNAPSHOT_LINUX_MEMORY_SNAPSHOT_LINUX_H_ +#define CRASHPAD_SNAPSHOT_LINUX_MEMORY_SNAPSHOT_LINUX_H_ + +#include +#include + +#include "base/macros.h" +#include "snapshot/linux/process_reader.h" +#include "snapshot/memory_snapshot.h" +#include "util/linux/address_types.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A MemorySnapshot of a memory region in a process on the running +//! system, when the system runs Linux. +class MemorySnapshotLinux final : public MemorySnapshot { + public: + MemorySnapshotLinux(); + ~MemorySnapshotLinux() override; + + //! \brief Initializes the object. + //! + //! Memory is read lazily. No attempt is made to read the memory snapshot data + //! until Read() is called, and the memory snapshot data is discared when + //! Read() returns. + //! + //! \param[in] process_reader A reader for the process being snapshotted. + //! \param[in] address The base address of the memory region to snapshot, in + //! the snapshot process’ address space. + //! \param[in] size The size of the memory region to snapshot. + void Initialize(ProcessReader* process_reader, + LinuxVMAddress address, + size_t size); + + // MemorySnapshot: + + uint64_t Address() const override; + size_t Size() const override; + bool Read(Delegate* delegate) const override; + + private: + ProcessReader* process_reader_; // weak + uint64_t address_; + size_t size_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(MemorySnapshotLinux); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_MEMORY_SNAPSHOT_LINUX_H_ diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index a85f6a27..3d872d93 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -50,6 +50,8 @@ 'linux/elf_image_reader.h', 'linux/elf_symbol_table_reader.cc', 'linux/elf_symbol_table_reader.h', + 'linux/memory_snapshot_linux.cc', + 'linux/memory_snapshot_linux.h', 'linux/process_reader.cc', 'linux/process_reader.h', 'mac/cpu_context_mac.cc', From 37f20f7b14003bc905e33664d7a4ba99f3e3a58d Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Thu, 20 Jul 2017 12:08:56 -0700 Subject: [PATCH 19/30] Add ThreadSnapshotLinux Bug: crashpad:30 Change-Id: Iee8eaecadc4b8d61d3975a79fbc7f80dbb39a134 Reviewed-on: https://chromium-review.googlesource.com/580207 Reviewed-by: Mark Mentovai --- compat/android/sched.h | 30 ++++ snapshot/linux/thread_snapshot_linux.cc | 204 ++++++++++++++++++++++++ snapshot/linux/thread_snapshot_linux.h | 82 ++++++++++ snapshot/snapshot.gyp | 2 + 4 files changed, 318 insertions(+) create mode 100644 compat/android/sched.h create mode 100644 snapshot/linux/thread_snapshot_linux.cc create mode 100644 snapshot/linux/thread_snapshot_linux.h diff --git a/compat/android/sched.h b/compat/android/sched.h new file mode 100644 index 00000000..c4a027ae --- /dev/null +++ b/compat/android/sched.h @@ -0,0 +1,30 @@ +// 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_COMPAT_ANDROID_SCHED_H_ +#define CRASHPAD_COMPAT_ANDROID_SCHED_H_ + +#include_next + +// Android 5.0.0 (API 21) NDK + +#if !defined(SCHED_BATCH) +#define SCHED_BATCH 3 +#endif + +#if !defined(SCHED_IDLE) +#define SCHED_IDLE 5 +#endif + +#endif // CRASHPAD_COMPAT_ANDROID_SCHED_H_ diff --git a/snapshot/linux/thread_snapshot_linux.cc b/snapshot/linux/thread_snapshot_linux.cc new file mode 100644 index 00000000..dd902905 --- /dev/null +++ b/snapshot/linux/thread_snapshot_linux.cc @@ -0,0 +1,204 @@ +// 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 "snapshot/linux/thread_snapshot_linux.h" + +#include + +#include "base/logging.h" +#include "snapshot/linux/cpu_context_linux.h" +#include "util/misc/reinterpret_bytes.h" + +namespace crashpad { +namespace internal { + +ThreadSnapshotLinux::ThreadSnapshotLinux() + : ThreadSnapshot(), + context_union_(), + context_(), + stack_(), + thread_specific_data_address_(0), + thread_id_(-1), + priority_(-1), + initialized_() { +} + +ThreadSnapshotLinux::~ThreadSnapshotLinux() { +} + +bool ThreadSnapshotLinux::Initialize( + ProcessReader* process_reader, + const ProcessReader::Thread& thread) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + +#if defined(ARCH_CPU_X86_FAMILY) + if (process_reader->Is64Bit()) { + context_.architecture = kCPUArchitectureX86_64; + context_.x86_64 = &context_union_.x86_64; + InitializeCPUContextX86_64(thread.thread_context.t64, + thread.float_context.f64, + context_.x86_64); + } else { + context_.architecture = kCPUArchitectureX86; + context_.x86 = &context_union_.x86; + InitializeCPUContextX86(thread.thread_context.t32, + thread.float_context.f32, + context_.x86); + } +#else +#error Port. +#endif + + stack_.Initialize(process_reader, + thread.stack_region_address, + thread.stack_region_size); + + thread_specific_data_address_ = + thread.thread_specific_data_address; + + thread_id_ = thread.tid; + + // Map Linux scheduling policy, static priority, and nice value into a single + // int value. + // + // The possible policies in order of approximate priority (low to high) are + // SCHED_IDLE + // SCHED_BATCH + // SCHED_OTHER + // SCHED_RR + // SCHED_FIFO + // + // static_priority is not used for OTHER, BATCH, or IDLE and should be 0. + // For FIFO and RR, static_priority should range from 1 to 99 with 99 being + // the highest priority. + // + // nice value ranges from -20 to 19, with -20 being highest priority + + enum class Policy : uint8_t { + kUnknown = 0, + kIdle, + kBatch, + kOther, + kRR, + kFIFO + }; + + struct LinuxPriority { +#if defined(ARCH_CPU_LITTLE_ENDIAN) + // nice values affect how dynamic priorities are updated, which only matters + // for threads with the same static priority. + uint8_t nice_value = 0; + + // The scheduling policy also affects how threads with the same static + // priority are ordered, but has greater impact than nice value. + Policy policy = Policy::kUnknown; + + // The static priority is the most significant in determining overall + // priority. + uint8_t static_priority = 0; + + // Put this in the most significant byte position to prevent negative + // priorities. + uint8_t unused = 0; +#elif defined(ARCH_CPU_BIG_ENDIAN) + uint8_t unused = 0; + uint8_t static_priority = 0; + Policy policy = Policy::kUnknown; + uint8_t nice_value = 0; +#endif // ARCH_CPU_LITTLE_ENDIAN + }; + static_assert(sizeof(LinuxPriority) <= sizeof(int), "priority is too large"); + + LinuxPriority prio; + + // Lower nice values have higher priority, so negate them and add 20 to put + // them in the range 1-40 with 40 being highest priority. + if (thread.nice_value < -20 || thread.nice_value > 19) { + LOG(WARNING) << "invalid nice value " << thread.nice_value; + prio.nice_value = 0; + } else { + prio.nice_value = -1 * thread.nice_value + 20; + } + + switch (thread.sched_policy) { + case SCHED_IDLE: + prio.policy = Policy::kIdle; + break; + case SCHED_BATCH: + prio.policy = Policy::kBatch; + break; + case SCHED_OTHER: + prio.policy = Policy::kOther; + break; + case SCHED_RR: + prio.policy = Policy::kRR; + break; + case SCHED_FIFO: + prio.policy = Policy::kFIFO; + break; + default: + prio.policy = Policy::kUnknown; + LOG(WARNING) << "Unknown scheduling policy " << thread.sched_policy; + } + + if (thread.static_priority < 0 || thread.static_priority > 99) { + LOG(WARNING) << "invalid static priority " << thread.static_priority; + } + prio.static_priority = thread.static_priority; + + if (!ReinterpretBytes(prio, &priority_)) { + LOG(ERROR) << "Couldn't set priority"; + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +const CPUContext* ThreadSnapshotLinux::Context() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return &context_; +} + +const MemorySnapshot* ThreadSnapshotLinux::Stack() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return &stack_; +} + +uint64_t ThreadSnapshotLinux::ThreadID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_id_; +} + +int ThreadSnapshotLinux::SuspendCount() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return 0; +} + +int ThreadSnapshotLinux::Priority() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return priority_; +} + +uint64_t ThreadSnapshotLinux::ThreadSpecificDataAddress() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_specific_data_address_; +} + +std::vector ThreadSnapshotLinux::ExtraMemory() const { + return std::vector(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/linux/thread_snapshot_linux.h b/snapshot/linux/thread_snapshot_linux.h new file mode 100644 index 00000000..e0ce7adb --- /dev/null +++ b/snapshot/linux/thread_snapshot_linux.h @@ -0,0 +1,82 @@ +// 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_SNAPSHOT_LINUX_THREAD_SNAPSHOT_LINUX_H_ +#define CRASHPAD_SNAPSHOT_LINUX_THREAD_SNAPSHOT_LINUX_H_ + +#include + +#include "base/macros.h" +#include "build/build_config.h" +#include "snapshot/cpu_context.h" +#include "snapshot/linux/memory_snapshot_linux.h" +#include "snapshot/linux/process_reader.h" +#include "snapshot/memory_snapshot.h" +#include "snapshot/thread_snapshot.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A ThreadSnapshot of a thread on a Linux system. +class ThreadSnapshotLinux final : public ThreadSnapshot { + public: + ThreadSnapshotLinux(); + ~ThreadSnapshotLinux() override; + + //! \brief Initializes the object. + //! + //! \param[in] process_reader A ProcessReader for the process containing the + //! thread. + //! \param[in] thread The thread within the ProcessReader for + //! which the snapshot should be created. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! a message logged. + bool Initialize(ProcessReader* process_reader, + const ProcessReader::Thread& thread); + + // ThreadSnapshot: + + const CPUContext* Context() const override; + const MemorySnapshot* Stack() const override; + uint64_t ThreadID() const override; + int SuspendCount() const override; + int Priority() const override; + uint64_t ThreadSpecificDataAddress() const override; + std::vector ExtraMemory() const override; + + private: +#if defined(ARCH_CPU_X86_FAMILY) + union { + CPUContextX86 x86; + CPUContextX86_64 x86_64; + } context_union_; +#else +#error Port. +#endif // ARCH_CPU_X86_FAMILY + CPUContext context_; + MemorySnapshotLinux stack_; + LinuxVMAddress thread_specific_data_address_; + pid_t thread_id_; + int priority_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotLinux); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_LINUX_THREAD_SNAPSHOT_LINUX_H_ diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 3d872d93..bd6c3d57 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -54,6 +54,8 @@ 'linux/memory_snapshot_linux.h', 'linux/process_reader.cc', 'linux/process_reader.h', + 'linux/thread_snapshot_linux.cc', + 'linux/thread_snapshot_linux.h', 'mac/cpu_context_mac.cc', 'mac/cpu_context_mac.h', 'mac/exception_snapshot_mac.cc', From 9299d409ab0a9fe5e55e49299800d85d02def192 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Mon, 24 Jul 2017 10:55:02 -0700 Subject: [PATCH 20/30] linux: Refactor reading start time from the stat file Bug: crashpad:30 Change-Id: Ie8137db2a5b6f2d4947df108d1fb5bdd9f8ab391 Reviewed-on: https://chromium-review.googlesource.com/580448 Commit-Queue: Joshua Peraza Reviewed-by: Mark Mentovai --- util/linux/proc_stat_reader.cc | 138 +++++++++++++++++++++++++++ util/linux/proc_stat_reader.h | 60 ++++++++++++ util/linux/proc_stat_reader_test.cc | 85 +++++++++++++++++ util/misc/lexing.cc | 75 +++++++++++++++ util/misc/lexing.h | 44 +++++++++ util/posix/process_info_linux.cc | 139 ++-------------------------- util/util.gyp | 4 + util/util_test.gyp | 1 + 8 files changed, 413 insertions(+), 133 deletions(-) create mode 100644 util/linux/proc_stat_reader.cc create mode 100644 util/linux/proc_stat_reader.h create mode 100644 util/linux/proc_stat_reader_test.cc create mode 100644 util/misc/lexing.cc create mode 100644 util/misc/lexing.h diff --git a/util/linux/proc_stat_reader.cc b/util/linux/proc_stat_reader.cc new file mode 100644 index 00000000..5a369a70 --- /dev/null +++ b/util/linux/proc_stat_reader.cc @@ -0,0 +1,138 @@ +// 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/proc_stat_reader.h" + +#include +#include +#include + +#include "base/files/file_path.h" +#include "base/logging.h" +#include "util/file/file_io.h" +#include "util/misc/lexing.h" + +namespace crashpad { + +namespace { + +void SubtractTimespec(const timespec& t1, + const timespec& t2, + timespec* result) { + result->tv_sec = t1.tv_sec - t2.tv_sec; + result->tv_nsec = t1.tv_nsec - t2.tv_nsec; + if (result->tv_nsec < 0) { + result->tv_sec -= 1; + result->tv_nsec += static_cast(1E9); + } +} + +void TimespecToTimeval(const timespec& ts, timeval* tv) { + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; +} + +} // namespace + +ProcStatReader::ProcStatReader() : tid_(-1) {} + +ProcStatReader::~ProcStatReader() {} + +bool ProcStatReader::Initialize(pid_t tid) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + // This might do more in the future. + tid_ = tid; + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +bool ProcStatReader::StartTime(timeval* start_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + std::string stat_contents; + if (!ReadFile(&stat_contents)) { + return false; + } + + // The process start time is the 22nd column. + // The second column is the executable name in parentheses. + // The executable name may have parentheses itself, so find the end of the + // second column by working backwards to find the last closing parens and + // then count forward to the 22nd column. + size_t stat_pos = stat_contents.rfind(')'); + if (stat_pos == std::string::npos) { + LOG(ERROR) << "format error"; + return false; + } + + for (int index = 1; index < 21; ++index) { + stat_pos = stat_contents.find(' ', stat_pos); + if (stat_pos == std::string::npos) { + break; + } + ++stat_pos; + } + if (stat_pos >= stat_contents.size()) { + LOG(ERROR) << "format error"; + return false; + } + + const char* ticks_ptr = &stat_contents[stat_pos]; + + // start time is in jiffies instead of clock ticks pre 2.6. + uint64_t ticks_after_boot; + if (!AdvancePastNumber(&ticks_ptr, &ticks_after_boot)) { + LOG(ERROR) << "format error"; + return false; + } + long clock_ticks_per_s = sysconf(_SC_CLK_TCK); + if (clock_ticks_per_s <= 0) { + PLOG(ERROR) << "sysconf"; + return false; + } + timeval time_after_boot; + time_after_boot.tv_sec = ticks_after_boot / clock_ticks_per_s; + time_after_boot.tv_usec = (ticks_after_boot % clock_ticks_per_s) * + (static_cast(1E6) / clock_ticks_per_s); + + timespec uptime; + if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) { + PLOG(ERROR) << "clock_gettime"; + return false; + } + + timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) { + PLOG(ERROR) << "clock_gettime"; + return false; + } + + timespec boot_time_ts; + SubtractTimespec(current_time, uptime, &boot_time_ts); + timeval boot_time_tv; + TimespecToTimeval(boot_time_ts, &boot_time_tv); + timeradd(&boot_time_tv, &time_after_boot, start_time); + + return true; +} + +bool ProcStatReader::ReadFile(std::string* contents) const { + char path[32]; + snprintf(path, arraysize(path), "/proc/%d/stat", tid_); + if (!LoggingReadEntireFile(base::FilePath(path), contents)) { + return false; + } + return true; +} + +} // namespace crashpad diff --git a/util/linux/proc_stat_reader.h b/util/linux/proc_stat_reader.h new file mode 100644 index 00000000..8bbc30e8 --- /dev/null +++ b/util/linux/proc_stat_reader.h @@ -0,0 +1,60 @@ +// 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_LINUX_PROC_STAT_READER_H_ +#define CRASHPAD_UTIL_LINUX_PROC_STAT_READER_H_ + +#include +#include + +#include + +#include "base/macros.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +//! \brief Reads the /proc/[pid]/stat file for a thread. +class ProcStatReader { + public: + ProcStatReader(); + ~ProcStatReader(); + + //! \brief Initializes the reader. + //! + //! This method must be successfully called before calling any other. + //! + //! \param[in] tid The thread ID to read the stat file for. + bool Initialize(pid_t tid); + + //! \brief Determines the target thread’s start time. + //! + //! \param[out] start_time The time that the thread started. + //! + //! \return `true` on success, with \a start_time set. Otherwise, `false` with + //! a message logged. + bool StartTime(timeval* start_time) const; + + private: + bool ReadFile(std::string* contents) const; + + pid_t tid_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProcStatReader); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_LINUX_PROC_STAT_READER_H_ diff --git a/util/linux/proc_stat_reader_test.cc b/util/linux/proc_stat_reader_test.cc new file mode 100644 index 00000000..4df17e2e --- /dev/null +++ b/util/linux/proc_stat_reader_test.cc @@ -0,0 +1,85 @@ +// 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/proc_stat_reader.h" + +#include +#include +#include + +#include "base/logging.h" +#include "gtest/gtest.h" +#include "util/thread/thread.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(ProcStatReader, Basic) { + ProcStatReader stat; + ASSERT_TRUE(stat.Initialize(getpid())); + + timeval start_time; + ASSERT_TRUE(stat.StartTime(&start_time)); + + time_t now; + time(&now); + EXPECT_LE(start_time.tv_sec, now); +} + +pid_t gettid() { + return syscall(SYS_gettid); +} + +void GetStartTime(timeval* start_time) { + ProcStatReader stat; + ASSERT_TRUE(stat.Initialize(gettid())); + ASSERT_TRUE(stat.StartTime(start_time)); +} + +class StatTimeThread : public Thread { + public: + StatTimeThread(timeval* start_time) : start_time_(start_time) {} + + private: + void ThreadMain() override { GetStartTime(start_time_); } + timeval* start_time_; +}; + +TEST(ProcStatReader, Threads) { + timeval main_time; + ASSERT_NO_FATAL_FAILURE(GetStartTime(&main_time)); + + timeval thread_time; + StatTimeThread thread(&thread_time); + thread.Start(); + ASSERT_NO_FATAL_FAILURE(thread.Join()); + + EXPECT_PRED4( + [](time_t main_sec, + suseconds_t main_usec, + time_t thread_sec, + suseconds_t thread_usec) { + return (thread_sec > main_sec) || + (thread_sec == main_sec && thread_usec > main_usec); + }, + main_time.tv_sec, + main_time.tv_usec, + thread_time.tv_sec, + thread_time.tv_usec); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/misc/lexing.cc b/util/misc/lexing.cc new file mode 100644 index 00000000..6c318654 --- /dev/null +++ b/util/misc/lexing.cc @@ -0,0 +1,75 @@ +// 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/misc/lexing.h" + +#include +#include +#include +#include + +#include + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" + +namespace crashpad { + +namespace { + +#define MAKE_ADAPTER(type, function) \ + bool ConvertStringToNumber(const base::StringPiece& input, type* value) { \ + return function(input, value); \ + } +MAKE_ADAPTER(int, base::StringToInt); +MAKE_ADAPTER(unsigned int, base::StringToUint); +MAKE_ADAPTER(int64_t, base::StringToInt64); +MAKE_ADAPTER(uint64_t, base::StringToUint64); +#undef MAKE_ADAPTER + +} // namespace + +bool AdvancePastPrefix(const char** input, const char* pattern) { + size_t length = strlen(pattern); + if (strncmp(*input, pattern, length) == 0) { + *input += length; + return true; + } + return false; +} + +template +bool AdvancePastNumber(const char** input, T* value) { + size_t length = 0; + if (std::numeric_limits::is_signed && **input == '-') { + ++length; + } + while (isdigit((*input)[length])) { + ++length; + } + bool success = + ConvertStringToNumber(base::StringPiece(*input, length), value); + if (success) { + *input += length; + return true; + } + return false; +} + +template bool AdvancePastNumber(const char** input, int* value); +template bool AdvancePastNumber(const char** input, unsigned int* value); +template bool AdvancePastNumber(const char** input, int64_t* value); +template bool AdvancePastNumber(const char** input, uint64_t* value); + +} // namespace crashpad diff --git a/util/misc/lexing.h b/util/misc/lexing.h new file mode 100644 index 00000000..d9829485 --- /dev/null +++ b/util/misc/lexing.h @@ -0,0 +1,44 @@ +// 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_MISC_LEXING_H_ +#define CRASHPAD_UTIL_MISC_LEXING_H_ + +namespace crashpad { + +//! \brief Match a pattern at the start of a char string. +//! +//! \param[in,out] input A pointer to the char string to match against. \a input +//! is advanced past the matched pattern if it is found. +//! \param[in] pattern The pattern to match at the start of \input. +//! \return `true` if the pattern is matched exactly and \input is advanced, +//! otherwise `false`. +bool AdvancePastPrefix(const char** input, const char* pattern); + +//! \brief Convert a prefix of a char string to a numeric value. +//! +//! Valid values are positive or negative decimal numbers, matching the regular +//! expression "-?\d+", and within the limits of T. +//! +//! \param[in,out] input A pointer to the char string to match against. \a input +//! is advanced past the number if one is found. +//! \param[out] value The converted number, if one is found. +//! \return `true` if a number is found at the start of \a input and \a input is +//! advanced, otherwise `false`. +template +bool AdvancePastNumber(const char** input, T* value); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_MISC_LEXING_H diff --git a/util/posix/process_info_linux.cc b/util/posix/process_info_linux.cc index ac3a2aea..f37e7411 100644 --- a/util/posix/process_info_linux.cc +++ b/util/posix/process_info_linux.cc @@ -14,84 +14,18 @@ #include "util/posix/process_info.h" -#include -#include -#include -#include -#include +#include #include "base/files/file_path.h" -#include "base/files/scoped_file.h" #include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" #include "util/file/delimited_file_reader.h" -#include "util/file/file_io.h" #include "util/file/file_reader.h" +#include "util/linux/proc_stat_reader.h" #include "util/linux/thread_info.h" +#include "util/misc/lexing.h" namespace crashpad { -namespace { - -// If the string |pattern| is matched exactly at the start of |input|, advance -// |input| past |pattern| and return true. -bool AdvancePastPrefix(const char** input, const char* pattern) { - size_t length = strlen(pattern); - if (strncmp(*input, pattern, length) == 0) { - *input += length; - return true; - } - return false; -} - -#define MAKE_ADAPTER(type, function) \ - bool ConvertStringToNumber(const base::StringPiece& input, type* value) { \ - return function(input, value); \ - } -MAKE_ADAPTER(int, base::StringToInt) -MAKE_ADAPTER(unsigned int, base::StringToUint) -MAKE_ADAPTER(uint64_t, base::StringToUint64) -#undef MAKE_ADAPTER - -// Attempt to convert a prefix of |input| to numeric type T. On success, set -// |value| to the number, advance |input| past the number, and return true. -template -bool AdvancePastNumber(const char** input, T* value) { - size_t length = 0; - if (std::numeric_limits::is_signed && **input == '-') { - ++length; - } - while (isdigit((*input)[length])) { - ++length; - } - bool success = ConvertStringToNumber(base::StringPiece(*input, length), - value); - if (success) { - *input += length; - return true; - } - return false; -} - -void SubtractTimespec(const timespec& t1, const timespec& t2, - timespec* result) { - result->tv_sec = t1.tv_sec - t2.tv_sec; - result->tv_nsec = t1.tv_nsec - t2.tv_nsec; - if (result->tv_nsec < 0) { - result->tv_sec -= 1; - result->tv_nsec += static_cast(1E9); - } -} - -void TimespecToTimeval(const timespec& ts, timeval* tv) { - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / 1000; -} - -} // namespace - ProcessInfo::ProcessInfo() : supplementary_groups_(), start_time_(), @@ -324,74 +258,13 @@ bool ProcessInfo::StartTime(timeval* start_time) const { if (start_time_initialized_.is_uninitialized()) { start_time_initialized_.set_invalid(); - - char path[32]; - snprintf(path, sizeof(path), "/proc/%d/stat", pid_); - std::string stat_contents; - if (!LoggingReadEntireFile(base::FilePath(path), &stat_contents)) { + ProcStatReader reader; + if (!reader.Initialize(pid_)) { return false; } - - // The process start time is the 22nd column. - // The second column is the executable name in parentheses. - // The executable name may have parentheses itself, so find the end of the - // second column by working backwards to find the last closing parens and - // then count forward to the 22nd column. - size_t stat_pos = stat_contents.rfind(')'); - if (stat_pos == std::string::npos) { - LOG(ERROR) << "format error"; + if (!reader.StartTime(&start_time_)) { return false; } - - for (int index = 1; index < 21; ++index) { - stat_pos = stat_contents.find(' ', stat_pos); - if (stat_pos == std::string::npos) { - break; - } - ++stat_pos; - } - if (stat_pos >= stat_contents.size()) { - LOG(ERROR) << "format error"; - return false; - } - - const char* ticks_ptr = &stat_contents[stat_pos]; - - // start time is in jiffies instead of clock ticks pre 2.6. - uint64_t ticks_after_boot; - if (!AdvancePastNumber(&ticks_ptr, &ticks_after_boot)) { - LOG(ERROR) << "format error"; - return false; - } - long clock_ticks_per_s = sysconf(_SC_CLK_TCK); - if (clock_ticks_per_s <= 0) { - PLOG(ERROR) << "sysconf"; - return false; - } - timeval time_after_boot; - time_after_boot.tv_sec = ticks_after_boot / clock_ticks_per_s; - time_after_boot.tv_usec = - (ticks_after_boot % clock_ticks_per_s) * - (static_cast(1E6) / clock_ticks_per_s); - - timespec uptime; - if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) { - PLOG(ERROR) << "clock_gettime"; - return false; - } - - timespec current_time; - if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) { - PLOG(ERROR) << "clock_gettime"; - return false; - } - - timespec boot_time_ts; - SubtractTimespec(current_time, uptime, &boot_time_ts); - timeval boot_time_tv; - TimespecToTimeval(boot_time_ts, &boot_time_tv); - timeradd(&boot_time_tv, &time_after_boot, &start_time_); - start_time_initialized_.set_valid(); } diff --git a/util/util.gyp b/util/util.gyp index 0d2364b5..984f1019 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -58,6 +58,8 @@ 'linux/thread_info.h', 'linux/scoped_ptrace_attach.cc', 'linux/scoped_ptrace_attach.h', + 'linux/proc_stat_reader.cc', + 'linux/proc_stat_reader.h', 'mac/checked_mach_address_range.h', 'mac/launchd.h', 'mac/launchd.mm', @@ -112,6 +114,8 @@ 'misc/initialization_state.h', 'misc/initialization_state_dcheck.cc', 'misc/initialization_state_dcheck.h', + 'misc/lexing.cc', + 'misc/lexing.h', 'misc/metrics.cc', 'misc/metrics.h', 'misc/paths.h', diff --git a/util/util_test.gyp b/util/util_test.gyp index 72f25533..0e74c0d1 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -43,6 +43,7 @@ 'linux/memory_map_test.cc', 'linux/process_memory_range_test.cc', 'linux/process_memory_test.cc', + 'linux/proc_stat_reader_test.cc', 'linux/thread_info_test.cc', 'linux/scoped_ptrace_attach_test.cc', 'mac/launchd_test.mm', From 90e4649f0dfaf3f84c242c770b3bfd8d1d915f58 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Mon, 24 Jul 2017 14:45:39 -0400 Subject: [PATCH 21/30] linux: Sort alphabetically in util .gyp files Bug: crashpad:30 Change-Id: Iea992cd9eef1029c046cb354f7c1c0173b6f0675 Reviewed-on: https://chromium-review.googlesource.com/583767 Reviewed-by: Joshua Peraza --- util/util.gyp | 8 ++++---- util/util_test.gyp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/util/util.gyp b/util/util.gyp index 984f1019..5facdaeb 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -50,16 +50,16 @@ 'linux/checked_address_range.h', 'linux/memory_map.cc', 'linux/memory_map.h', + 'linux/proc_stat_reader.cc', + 'linux/proc_stat_reader.h', 'linux/process_memory.cc', 'linux/process_memory.h', 'linux/process_memory_range.cc', 'linux/process_memory_range.h', - 'linux/thread_info.cc', - 'linux/thread_info.h', 'linux/scoped_ptrace_attach.cc', 'linux/scoped_ptrace_attach.h', - 'linux/proc_stat_reader.cc', - 'linux/proc_stat_reader.h', + 'linux/thread_info.cc', + 'linux/thread_info.h', 'mac/checked_mach_address_range.h', 'mac/launchd.h', 'mac/launchd.mm', diff --git a/util/util_test.gyp b/util/util_test.gyp index 0e74c0d1..23be3600 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -41,11 +41,11 @@ 'file/string_file_test.cc', 'linux/auxiliary_vector_test.cc', 'linux/memory_map_test.cc', + 'linux/proc_stat_reader_test.cc', 'linux/process_memory_range_test.cc', 'linux/process_memory_test.cc', - 'linux/proc_stat_reader_test.cc', - 'linux/thread_info_test.cc', 'linux/scoped_ptrace_attach_test.cc', + 'linux/thread_info_test.cc', 'mac/launchd_test.mm', 'mac/mac_util_test.mm', 'mac/service_management_test.mm', From 01b347732e0e49f6fa08b0aab3d8ab90f9a3fd5d Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Mon, 24 Jul 2017 18:21:22 -0700 Subject: [PATCH 22/30] linux: Collect CPU times in ProcStatReader and use in ProcessReader Bug: crashpad:30 Change-Id: I6d4020220031670937acad12d0b7878c1ae0fae7 Reviewed-on: https://chromium-review.googlesource.com/583952 Reviewed-by: Mark Mentovai --- snapshot/linux/process_reader.cc | 41 ++++++++++ snapshot/linux/process_reader.h | 20 +++++ util/linux/proc_stat_reader.cc | 123 ++++++++++++++++++---------- util/linux/proc_stat_reader.h | 24 +++++- util/linux/proc_stat_reader_test.cc | 10 +++ 5 files changed, 174 insertions(+), 44 deletions(-) diff --git a/snapshot/linux/process_reader.cc b/snapshot/linux/process_reader.cc index 91d2bb46..da46f243 100644 --- a/snapshot/linux/process_reader.cc +++ b/snapshot/linux/process_reader.cc @@ -26,6 +26,7 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "build/build_config.h" +#include "util/linux/proc_stat_reader.h" #include "util/posix/scoped_dir.h" namespace crashpad { @@ -210,6 +211,46 @@ bool ProcessReader::Initialize(pid_t pid) { return true; } +bool ProcessReader::StartTime(timeval* start_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return process_info_.StartTime(start_time); +} + +bool ProcessReader::CPUTimes(timeval* user_time, timeval* system_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + timerclear(user_time); + timerclear(system_time); + + timeval local_user_time; + timerclear(&local_user_time); + timeval local_system_time; + timerclear(&local_system_time); + + for (const Thread& thread : threads_) { + ProcStatReader stat; + if (!stat.Initialize(thread.tid)) { + return false; + } + + timeval thread_user_time; + if (!stat.UserCPUTime(&thread_user_time)) { + return false; + } + + timeval thread_system_time; + if (!stat.SystemCPUTime(&thread_system_time)) { + return false; + } + + timeradd(&local_user_time, &thread_user_time, &local_user_time); + timeradd(&local_system_time, &thread_system_time, &local_system_time); + } + + *user_time = local_user_time; + *system_time = local_system_time; + return true; +} + const std::vector& ProcessReader::Threads() { INITIALIZATION_STATE_DCHECK_VALID(initialized_); if (!initialized_threads_) { diff --git a/snapshot/linux/process_reader.h b/snapshot/linux/process_reader.h index 64adac5c..9f398f34 100644 --- a/snapshot/linux/process_reader.h +++ b/snapshot/linux/process_reader.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_H_ #define CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_H_ +#include #include #include @@ -83,6 +84,25 @@ class ProcessReader { //! \brief Return a memory map of the target process. MemoryMap* GetMemoryMap() { return &memory_map_; } + //! \brief Determines the target process’ start time. + //! + //! \param[out] start_time The time that the process started. + //! \return `true` on success with \a start_time set. Otherwise `false` with a + //! message logged. + bool StartTime(timeval* start_time) const; + + //! \brief Determines the target process’ execution time. + //! + //! \param[out] user_time The amount of time the process has executed code in + //! user mode. + //! \param[out] system_time The amount of time the process has executed code + //! in system mode. + //! + //! \return `true` on success, `false` on failure, with a warning logged. On + //! failure, \a user_time and \a system_time will be set to represent no + //! time spent executing code in user or system mode. + bool CPUTimes(timeval* user_time, timeval* system_time) const; + //! \brief Return a vector of threads that are in the task process. If the //! main thread is able to be identified and traced, it will be placed at //! index `0`. diff --git a/util/linux/proc_stat_reader.cc b/util/linux/proc_stat_reader.cc index 5a369a70..b4cc3ffd 100644 --- a/util/linux/proc_stat_reader.cc +++ b/util/linux/proc_stat_reader.cc @@ -43,67 +43,66 @@ void TimespecToTimeval(const timespec& ts, timeval* tv) { tv->tv_usec = ts.tv_nsec / 1000; } +long GetClockTicksPerSecond() { + long clock_ticks_per_s = sysconf(_SC_CLK_TCK); + if (clock_ticks_per_s <= 0) { + PLOG(ERROR) << "sysconf"; + } + return clock_ticks_per_s; +} + } // namespace -ProcStatReader::ProcStatReader() : tid_(-1) {} +ProcStatReader::ProcStatReader() + : contents_(), third_column_position_(0), initialized_() {} ProcStatReader::~ProcStatReader() {} bool ProcStatReader::Initialize(pid_t tid) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - // This might do more in the future. - tid_ = tid; - INITIALIZATION_STATE_SET_VALID(initialized_); - return true; -} - -bool ProcStatReader::StartTime(timeval* start_time) const { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - std::string stat_contents; - if (!ReadFile(&stat_contents)) { + if (!ReadFile(tid)) { return false; } - // The process start time is the 22nd column. - // The second column is the executable name in parentheses. + // The first column is process ID and the second column is the executable name + // in parentheses. This class only cares about columns after the second, so + // find the start of the third here and save it for later. // The executable name may have parentheses itself, so find the end of the - // second column by working backwards to find the last closing parens and - // then count forward to the 22nd column. - size_t stat_pos = stat_contents.rfind(')'); + // second column by working backwards to find the last closing parens. + size_t stat_pos = contents_.rfind(')'); if (stat_pos == std::string::npos) { LOG(ERROR) << "format error"; return false; } - for (int index = 1; index < 21; ++index) { - stat_pos = stat_contents.find(' ', stat_pos); - if (stat_pos == std::string::npos) { - break; - } - ++stat_pos; - } - if (stat_pos >= stat_contents.size()) { + third_column_position_ = contents_.find(' ', stat_pos); + if (third_column_position_ == std::string::npos || + ++third_column_position_ >= contents_.size()) { LOG(ERROR) << "format error"; return false; } - const char* ticks_ptr = &stat_contents[stat_pos]; + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +bool ProcStatReader::UserCPUTime(timeval* user_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return ReadTimeAtIndex(13, user_time); +} + +bool ProcStatReader::SystemCPUTime(timeval* system_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return ReadTimeAtIndex(14, system_time); +} + +bool ProcStatReader::StartTime(timeval* start_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); - // start time is in jiffies instead of clock ticks pre 2.6. - uint64_t ticks_after_boot; - if (!AdvancePastNumber(&ticks_ptr, &ticks_after_boot)) { - LOG(ERROR) << "format error"; - return false; - } - long clock_ticks_per_s = sysconf(_SC_CLK_TCK); - if (clock_ticks_per_s <= 0) { - PLOG(ERROR) << "sysconf"; - return false; - } timeval time_after_boot; - time_after_boot.tv_sec = ticks_after_boot / clock_ticks_per_s; - time_after_boot.tv_usec = (ticks_after_boot % clock_ticks_per_s) * - (static_cast(1E6) / clock_ticks_per_s); + if (!ReadTimeAtIndex(21, &time_after_boot)) { + return false; + } timespec uptime; if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) { @@ -126,13 +125,53 @@ bool ProcStatReader::StartTime(timeval* start_time) const { return true; } -bool ProcStatReader::ReadFile(std::string* contents) const { +bool ProcStatReader::ReadFile(pid_t tid) { char path[32]; - snprintf(path, arraysize(path), "/proc/%d/stat", tid_); - if (!LoggingReadEntireFile(base::FilePath(path), contents)) { + snprintf(path, arraysize(path), "/proc/%d/stat", tid); + if (!LoggingReadEntireFile(base::FilePath(path), &contents_)) { return false; } return true; } +bool ProcStatReader::FindColumn(int col_index, const char** column) const { + size_t position = third_column_position_; + for (int index = 2; index < col_index; ++index) { + position = contents_.find(' ', position); + if (position == std::string::npos) { + break; + } + ++position; + } + if (position >= contents_.size()) { + LOG(ERROR) << "format error"; + return false; + } + *column = &contents_[position]; + return true; +} + +bool ProcStatReader::ReadTimeAtIndex(int index, timeval* time_val) const { + const char* ticks_ptr; + if (!FindColumn(index, &ticks_ptr)) { + return false; + } + + uint64_t ticks; + if (!AdvancePastNumber(&ticks_ptr, &ticks)) { + LOG(ERROR) << "format error"; + return false; + } + + static long clock_ticks_per_s = GetClockTicksPerSecond(); + if (clock_ticks_per_s <= 0) { + return false; + } + + time_val->tv_sec = ticks / clock_ticks_per_s; + time_val->tv_usec = (ticks % clock_ticks_per_s) * + (static_cast(1E6) / clock_ticks_per_s); + return true; +} + } // namespace crashpad diff --git a/util/linux/proc_stat_reader.h b/util/linux/proc_stat_reader.h index 8bbc30e8..4cad97c5 100644 --- a/util/linux/proc_stat_reader.h +++ b/util/linux/proc_stat_reader.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_UTIL_LINUX_PROC_STAT_READER_H_ #define CRASHPAD_UTIL_LINUX_PROC_STAT_READER_H_ +#include #include #include @@ -38,6 +39,22 @@ class ProcStatReader { //! \param[in] tid The thread ID to read the stat file for. bool Initialize(pid_t tid); + //! \brief Determines the time the thread has spent executing in user mode. + //! + //! \param[out] user_time The time spent executing in user mode. + //! + //! \return `true` on success, with \a user_time set. Otherwise, `false` with + //! a message logged. + bool UserCPUTime(timeval* user_time) const; + + //! \brief Determines the time the thread has spent executing in system mode. + //! + //! \param[out] system_time The time spent executing in system mode. + //! + //! \return `true` on success, with \a system_time set. Otherwise, `false` + //! with a message logged. + bool SystemCPUTime(timeval* system_time) const; + //! \brief Determines the target thread’s start time. //! //! \param[out] start_time The time that the thread started. @@ -47,9 +64,12 @@ class ProcStatReader { bool StartTime(timeval* start_time) const; private: - bool ReadFile(std::string* contents) const; + bool ReadFile(pid_t tid); + bool FindColumn(int index, const char** column) const; + bool ReadTimeAtIndex(int index, timeval* time_val) const; - pid_t tid_; + std::string contents_; + size_t third_column_position_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ProcStatReader); diff --git a/util/linux/proc_stat_reader_test.cc b/util/linux/proc_stat_reader_test.cc index 4df17e2e..8189c2ea 100644 --- a/util/linux/proc_stat_reader_test.cc +++ b/util/linux/proc_stat_reader_test.cc @@ -36,6 +36,16 @@ TEST(ProcStatReader, Basic) { time_t now; time(&now); EXPECT_LE(start_time.tv_sec, now); + + time_t elapsed_sec = now - start_time.tv_sec; + + timeval user_time; + ASSERT_TRUE(stat.UserCPUTime(&user_time)); + EXPECT_LE(user_time.tv_sec, elapsed_sec); + + timeval system_time; + ASSERT_TRUE(stat.SystemCPUTime(&system_time)); + EXPECT_LE(system_time.tv_sec, elapsed_sec); } pid_t gettid() { From 281be63d0074c822a56382452e8c7259e4e301ad Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 25 Jul 2017 13:34:04 -0400 Subject: [PATCH 23/30] Standardize on static constexpr for arrays when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This uses “static” at function scope to avoid making local copies, even in cases where the compiler can’t see that the local copy is unnecessary. “constexpr” adds additional safety in that it prevents global state from being initialized from any runtime dependencies, which would be undesirable. At namespace scope, “constexpr” is also used where appropriate. For the most part, this was a mechanical transformation for things matching '(^| )const [^=]*\['. Similar transformations could be applied to non-arrays in some cases, but there’s limited practical impact in most non-array cases relative to arrays, there are far more use sites, and much more manual intervention would be required. Change-Id: I3513b739ee8b0be026f8285475cddc5f9cc81152 Reviewed-on: https://chromium-review.googlesource.com/583997 Commit-Queue: Mark Mentovai Reviewed-by: Leonard Mosescu --- client/crash_report_database_mac.mm | 29 ++--- client/crash_report_database_test.cc | 2 +- client/crash_report_database_win.cc | 8 +- client/crashpad_info.cc | 2 +- client/prune_crash_reports_test.cc | 2 +- client/settings_test.cc | 2 +- client/simulate_crash_mac.cc | 2 +- client/simulate_crash_mac_test.cc | 6 +- handler/crash_report_upload_thread.cc | 2 +- handler/crashpad_handler_test.cc | 2 +- .../crashpad_handler_test_extended_handler.cc | 2 +- handler/handler_main.cc | 4 +- handler/win/crashy_test_program.cc | 26 ++-- .../minidump_crashpad_info_writer_test.cc | 10 +- minidump/minidump_file_writer_test.cc | 4 +- minidump/minidump_misc_info_writer.cc | 16 +-- minidump/minidump_misc_info_writer_test.cc | 25 ++-- ...nidump_module_crashpad_info_writer_test.cc | 34 +++--- minidump/minidump_module_writer_test.cc | 34 +++--- minidump/minidump_rva_list_writer_test.cc | 2 +- minidump/minidump_string_writer_test.cc | 6 +- minidump/minidump_system_info_writer_test.cc | 16 +-- .../minidump_unloaded_module_writer_test.cc | 4 +- minidump/minidump_writable.cc | 2 +- snapshot/linux/process_reader_test.cc | 4 +- .../mach_o_image_annotations_reader_test.cc | 3 +- .../mac/mach_o_image_segment_reader_test.cc | 11 +- snapshot/mac/process_reader_test.cc | 6 +- snapshot/mac/process_types/custom.cc | 2 +- snapshot/mac/system_snapshot_mac.cc | 6 +- snapshot/mac/system_snapshot_mac_test.cc | 2 +- snapshot/win/pe_image_reader_test.cc | 2 +- snapshot/win/process_reader_win_test.cc | 4 +- snapshot/win/process_snapshot_win.cc | 2 +- snapshot/win/system_snapshot_win.cc | 2 +- test/file.cc | 8 +- test/hex_string_test.cc | 2 +- test/win/win_child_process.cc | 2 +- tools/crashpad_database_util.cc | 8 +- tools/crashpad_http_upload.cc | 2 +- tools/generate_dump.cc | 2 +- tools/mac/catch_exception_tool.cc | 2 +- tools/mac/exception_port_tool.cc | 16 +-- tools/mac/on_demand_service_tool.mm | 2 +- tools/mac/run_with_crashpad.cc | 2 +- util/file/delimited_file_reader_test.cc | 7 +- util/file/file_io_test.cc | 2 +- util/linux/process_memory_test.cc | 4 +- util/mac/checked_mach_address_range_test.cc | 12 +- util/mac/launchd_test.mm | 2 +- util/mac/service_management_test.mm | 3 +- util/mac/xattr_test.cc | 2 +- util/mach/child_port_server.cc | 3 +- .../composite_mach_message_server_test.cc | 6 +- util/mach/exc_client_variants_test.cc | 2 +- util/mach/exc_server_variants_test.cc | 18 ++- util/mach/exception_behaviors_test.cc | 7 +- util/mach/exception_types_test.cc | 16 ++- util/mach/mach_message_server_test.cc | 2 +- util/mach/notify_server.cc | 2 +- util/mach/symbolic_constants_mach.cc | 30 ++--- util/mach/symbolic_constants_mach_test.cc | 32 ++--- util/mach/task_memory_test.cc | 34 +++++- util/misc/clock_test.cc | 2 +- util/misc/implicit_cast.h | 4 +- util/misc/scoped_forbid_return_test.cc | 2 +- util/misc/uuid.cc | 2 +- util/misc/uuid_test.cc | 66 +++++------ util/net/http_multipart_builder.cc | 6 +- util/net/http_multipart_builder_test.cc | 22 ++-- util/net/http_transport_libcurl.cc | 30 ++--- util/net/http_transport_test.cc | 8 +- util/net/http_transport_win.cc | 3 +- util/numeric/checked_address_range_test.cc | 12 +- util/numeric/checked_range_test.cc | 20 ++-- util/numeric/int128_test.cc | 4 +- util/posix/close_multiple.cc | 8 +- util/posix/symbolic_constants_posix.cc | 4 +- util/posix/symbolic_constants_posix_test.cc | 8 +- util/stdlib/string_number_conversion_test.cc | 12 +- util/stdlib/strlcpy_test.cc | 3 +- util/stdlib/strnlen_test.cc | 4 +- util/thread/thread_log_messages_test.cc | 6 +- util/win/command_line_test.cc | 112 +++++++++--------- util/win/process_info_test.cc | 6 +- util/win/registration_protocol_win.cc | 2 +- util/win/registration_protocol_win_test.cc | 2 +- util/win/safe_terminate_process_test.cc | 2 +- 88 files changed, 445 insertions(+), 421 deletions(-) diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 3cc2d7fe..7a9154b8 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -42,29 +42,30 @@ namespace crashpad { namespace { -const char kWriteDirectory[] = "new"; -const char kUploadPendingDirectory[] = "pending"; -const char kCompletedDirectory[] = "completed"; +constexpr char kWriteDirectory[] = "new"; +constexpr char kUploadPendingDirectory[] = "pending"; +constexpr char kCompletedDirectory[] = "completed"; -const char kSettings[] = "settings.dat"; +constexpr char kSettings[] = "settings.dat"; -const char* const kReportDirectories[] = { +constexpr const char* kReportDirectories[] = { kWriteDirectory, kUploadPendingDirectory, kCompletedDirectory, }; -const char kCrashReportFileExtension[] = "dmp"; +constexpr char kCrashReportFileExtension[] = "dmp"; -const char kXattrUUID[] = "uuid"; -const char kXattrCollectorID[] = "id"; -const char kXattrCreationTime[] = "creation_time"; -const char kXattrIsUploaded[] = "uploaded"; -const char kXattrLastUploadTime[] = "last_upload_time"; -const char kXattrUploadAttemptCount[] = "upload_count"; -const char kXattrIsUploadExplicitlyRequested[] = "upload_explicitly_requested"; +constexpr char kXattrUUID[] = "uuid"; +constexpr char kXattrCollectorID[] = "id"; +constexpr char kXattrCreationTime[] = "creation_time"; +constexpr char kXattrIsUploaded[] = "uploaded"; +constexpr char kXattrLastUploadTime[] = "last_upload_time"; +constexpr char kXattrUploadAttemptCount[] = "upload_count"; +constexpr char kXattrIsUploadExplicitlyRequested[] = + "upload_explicitly_requested"; -const char kXattrDatabaseInitialized[] = "initialized"; +constexpr char kXattrDatabaseInitialized[] = "initialized"; // Ensures that the node at |path| is a directory. If the |path| refers to a // file, rather than a directory, returns false. Otherwise, returns true, diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index da44ebfb..c4266961 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -51,7 +51,7 @@ class CrashReportDatabaseTest : public testing::Test { CrashReportDatabase::NewReport* new_report = nullptr; ASSERT_EQ(db_->PrepareNewCrashReport(&new_report), CrashReportDatabase::kNoError); - const char kTest[] = "test"; + static constexpr char kTest[] = "test"; ASSERT_TRUE(LoggingWriteFile(new_report->handle, kTest, sizeof(kTest))); UUID uuid; diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index a97b1cf0..1e1b4d7a 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -36,12 +36,12 @@ namespace crashpad { namespace { -const wchar_t kReportsDirectory[] = L"reports"; -const wchar_t kMetadataFileName[] = L"metadata"; +constexpr wchar_t kReportsDirectory[] = L"reports"; +constexpr wchar_t kMetadataFileName[] = L"metadata"; -const wchar_t kSettings[] = L"settings.dat"; +constexpr wchar_t kSettings[] = L"settings.dat"; -const wchar_t kCrashReportFileExtension[] = L"dmp"; +constexpr wchar_t kCrashReportFileExtension[] = L"dmp"; const uint32_t kMetadataFileHeaderMagic = 'CPAD'; const uint32_t kMetadataFileVersion = 1; diff --git a/client/crashpad_info.cc b/client/crashpad_info.cc index b7ba5490..58d30ce8 100644 --- a/client/crashpad_info.cc +++ b/client/crashpad_info.cc @@ -28,7 +28,7 @@ namespace { -static const uint32_t kCrashpadInfoVersion = 1; +constexpr uint32_t kCrashpadInfoVersion = 1; } // namespace diff --git a/client/prune_crash_reports_test.cc b/client/prune_crash_reports_test.cc index 130ea72a..54d6941e 100644 --- a/client/prune_crash_reports_test.cc +++ b/client/prune_crash_reports_test.cc @@ -147,7 +147,7 @@ class StaticCondition final : public PruneCondition { }; TEST(PruneCrashReports, BinaryCondition) { - const struct { + static constexpr struct { const char* name; BinaryPruneCondition::Operator op; bool lhs_value; diff --git a/client/settings_test.cc b/client/settings_test.cc index 866e58d7..ca961a23 100644 --- a/client/settings_test.cc +++ b/client/settings_test.cc @@ -41,7 +41,7 @@ class SettingsTest : public testing::Test { FilePermissions::kWorldReadable)); ASSERT_TRUE(handle.is_valid()); - const char kBuf[] = "test bad file"; + static constexpr char kBuf[] = "test bad file"; ASSERT_TRUE(LoggingWriteFile(handle.get(), kBuf, sizeof(kBuf))); handle.reset(); } diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc index 27864388..1e2d8e42 100644 --- a/client/simulate_crash_mac.cc +++ b/client/simulate_crash_mac.cc @@ -196,7 +196,7 @@ void SimulateCrash(const NativeCPUContext& cpu_context) { // Look up the handler for EXC_CRASH exceptions in the same way that the // kernel would: try a thread handler, then a task handler, and finally a host // handler. 10.9.5 xnu-2422.115.4/osfmk/kern/exception.c exception_triage(). - const ExceptionPorts::TargetType kTargetTypes[] = { + static constexpr ExceptionPorts::TargetType kTargetTypes[] = { ExceptionPorts::kTargetTypeThread, ExceptionPorts::kTargetTypeTask, diff --git a/client/simulate_crash_mac_test.cc b/client/simulate_crash_mac_test.cc index c1953524..1d63ff65 100644 --- a/client/simulate_crash_mac_test.cc +++ b/client/simulate_crash_mac_test.cc @@ -307,14 +307,14 @@ class TestSimulateCrashMac final : public MachMultiprocess, }; TEST(SimulateCrash, SimulateCrash) { - const TestSimulateCrashMac::ExceptionPortsTarget kTargets[] = { + static constexpr TestSimulateCrashMac::ExceptionPortsTarget kTargets[] = { TestSimulateCrashMac::kExceptionPortsTargetNone, TestSimulateCrashMac::kExceptionPortsTargetTask, TestSimulateCrashMac::kExceptionPortsTargetThread, TestSimulateCrashMac::kExceptionPortsTargetBoth, }; - const exception_behavior_t kBehaviors[] = { + static constexpr exception_behavior_t kBehaviors[] = { EXCEPTION_DEFAULT, EXCEPTION_STATE, EXCEPTION_STATE_IDENTITY, @@ -323,7 +323,7 @@ TEST(SimulateCrash, SimulateCrash) { EXCEPTION_STATE_IDENTITY | kMachExceptionCodes, }; - const thread_state_flavor_t kFlavors[] = { + static constexpr thread_state_flavor_t kFlavors[] = { #if defined(ARCH_CPU_X86_FAMILY) x86_THREAD_STATE, x86_FLOAT_STATE, diff --git a/handler/crash_report_upload_thread.cc b/handler/crash_report_upload_thread.cc index d77cdbad..252e14fb 100644 --- a/handler/crash_report_upload_thread.cc +++ b/handler/crash_report_upload_thread.cc @@ -361,7 +361,7 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport( HTTPMultipartBuilder http_multipart_builder; http_multipart_builder.SetGzipEnabled(upload_gzip_); - const char kMinidumpKey[] = "upload_file_minidump"; + static constexpr char kMinidumpKey[] = "upload_file_minidump"; for (const auto& kv : parameters) { if (kv.first == kMinidumpKey) { diff --git a/handler/crashpad_handler_test.cc b/handler/crashpad_handler_test.cc index 7237e8c8..125157ff 100644 --- a/handler/crashpad_handler_test.cc +++ b/handler/crashpad_handler_test.cc @@ -115,7 +115,7 @@ void CrashWithExtendedHandler::ValidateGeneratedDump() { ASSERT_TRUE(reader.ReadExactly(data.data(), data.size())); - static const char kExpectedData[] = "Injected extension stream!"; + static constexpr char kExpectedData[] = "Injected extension stream!"; EXPECT_EQ(memcmp(kExpectedData, data.data(), sizeof(kExpectedData)), 0); } } diff --git a/handler/crashpad_handler_test_extended_handler.cc b/handler/crashpad_handler_test_extended_handler.cc index ede0f6e7..e2134e78 100644 --- a/handler/crashpad_handler_test_extended_handler.cc +++ b/handler/crashpad_handler_test_extended_handler.cc @@ -39,7 +39,7 @@ class TestUserStreamDataSource : public crashpad::UserStreamDataSource { std::unique_ptr TestUserStreamDataSource::ProduceStreamData( crashpad::ProcessSnapshot* process_snapshot) { - static const char kTestData[] = "Injected extension stream!"; + static constexpr char kTestData[] = "Injected extension stream!"; return base::WrapUnique(new crashpad::test::BufferExtensionStreamDataSource( 0xCAFEBABE, kTestData, sizeof(kTestData))); diff --git a/handler/handler_main.cc b/handler/handler_main.cc index e6d05e22..f1b08ff9 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -436,7 +436,7 @@ int HandlerMain(int argc, kOptionVersion = -3, }; - const option long_options[] = { + static constexpr option long_options[] = { {"annotation", required_argument, nullptr, kOptionAnnotation}, {"database", required_argument, nullptr, kOptionDatabase}, #if defined(OS_MACOSX) @@ -714,7 +714,7 @@ int HandlerMain(int argc, base::GlobalHistogramAllocator* histogram_allocator = nullptr; if (!options.metrics_dir.empty()) { - static const char kMetricsName[] = "CrashpadMetrics"; + static constexpr char kMetricsName[] = "CrashpadMetrics"; const size_t kMetricsFileSize = 1 << 20; if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( options.metrics_dir, kMetricsFileSize, 0, kMetricsName)) { diff --git a/handler/win/crashy_test_program.cc b/handler/win/crashy_test_program.cc index 58afa47f..0da56cb9 100644 --- a/handler/win/crashy_test_program.cc +++ b/handler/win/crashy_test_program.cc @@ -63,20 +63,20 @@ void AllocateMemoryOfVariousProtections() { const size_t kPageSize = system_info.dwPageSize; - const uint32_t kPageTypes[] = { - PAGE_NOACCESS, - PAGE_READONLY, - PAGE_READWRITE, - PAGE_EXECUTE, - PAGE_EXECUTE_READ, - PAGE_EXECUTE_READWRITE, + static constexpr uint32_t kPageTypes[] = { + PAGE_NOACCESS, + PAGE_READONLY, + PAGE_READWRITE, + PAGE_EXECUTE, + PAGE_EXECUTE_READ, + PAGE_EXECUTE_READWRITE, - // PAGE_NOACCESS is invalid with PAGE_GUARD. - PAGE_READONLY | PAGE_GUARD, - PAGE_READWRITE | PAGE_GUARD, - PAGE_EXECUTE | PAGE_GUARD, - PAGE_EXECUTE_READ | PAGE_GUARD, - PAGE_EXECUTE_READWRITE | PAGE_GUARD, + // PAGE_NOACCESS is invalid with PAGE_GUARD. + PAGE_READONLY | PAGE_GUARD, + PAGE_READWRITE | PAGE_GUARD, + PAGE_EXECUTE | PAGE_GUARD, + PAGE_EXECUTE_READ | PAGE_GUARD, + PAGE_EXECUTE_READWRITE | PAGE_GUARD, }; // All of these allocations are leaked, we want to view them in windbg via diff --git a/minidump/minidump_crashpad_info_writer_test.cc b/minidump/minidump_crashpad_info_writer_test.cc index e24a606c..7ae0980b 100644 --- a/minidump/minidump_crashpad_info_writer_test.cc +++ b/minidump/minidump_crashpad_info_writer_test.cc @@ -130,10 +130,10 @@ TEST(MinidumpCrashpadInfoWriter, SimpleAnnotations) { auto crashpad_info_writer = base::WrapUnique(new MinidumpCrashpadInfoWriter()); - const char kKey[] = + static constexpr char kKey[] = "a thing that provides a means of gaining access to or understanding " "something"; - const char kValue[] = + static constexpr char kValue[] = "the numerical amount denoted by an algebraic term; a magnitude, " "quantity, or number"; auto simple_string_dictionary_writer = @@ -230,9 +230,9 @@ TEST(MinidumpCrashpadInfoWriter, InitializeFromSnapshot) { ASSERT_TRUE( client_id.InitializeFromString("fedcba98-7654-3210-0123-456789abcdef")); - const char kKey[] = "version"; - const char kValue[] = "40.0.2214.111"; - const char kEntry[] = "This is a simple annotation in a list."; + static constexpr char kKey[] = "version"; + static constexpr char kValue[] = "40.0.2214.111"; + static constexpr char kEntry[] = "This is a simple annotation in a list."; // Test with a useless module, one that doesn’t carry anything that would // require MinidumpCrashpadInfo or any child object. diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index 63f2ade8..04ddd4d1 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -134,7 +134,7 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) { const time_t kTimestamp = 0x155d2fb8; minidump_file.SetTimestamp(kTimestamp); - static const uint8_t kStreamData[] = "Hello World!"; + static constexpr uint8_t kStreamData[] = "Hello World!"; const size_t kStreamSize = arraysize(kStreamData); const MinidumpStreamType kStreamType = static_cast(0x4d); @@ -270,7 +270,7 @@ TEST(MinidumpFileWriter, ThreeStreams) { std::string expected_stream0(kStream0Size, kStream0Value); EXPECT_EQ(memcmp(stream0_data, expected_stream0.c_str(), kStream0Size), 0); - const int kZeroes[16] = {}; + static constexpr int kZeroes[16] = {}; ASSERT_GE(sizeof(kZeroes), kStream1Padding); EXPECT_EQ(memcmp(stream0_data + kStream0Size, kZeroes, kStream1Padding), 0); diff --git a/minidump/minidump_misc_info_writer.cc b/minidump/minidump_misc_info_writer.cc index 2ea8fa90..1b775faa 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -101,25 +101,25 @@ std::string MinidumpMiscInfoDebugBuildString() { // plus a UTF-16 NUL terminator. Don’t let strings get longer than this, or // they will be truncated and a message will be logged. #if defined(OS_MACOSX) - const char kOS[] = "mac"; + static constexpr char kOS[] = "mac"; #elif defined(OS_ANDROID) - const char kOS[] = "android"; + static constexpr char kOS[] = "android"; #elif defined(OS_LINUX) - const char kOS[] = "linux"; + static constexpr char kOS[] = "linux"; #elif defined(OS_WIN) - const char kOS[] = "win"; + static constexpr char kOS[] = "win"; #else #error define kOS for this operating system #endif #if defined(ARCH_CPU_X86) - const char kCPU[] = "i386"; + static constexpr char kCPU[] = "i386"; #elif defined(ARCH_CPU_X86_64) - const char kCPU[] = "amd64"; + static constexpr char kCPU[] = "amd64"; #elif defined(ARCH_CPU_ARMEL) - const char kCPU[] = "arm"; + static constexpr char kCPU[] = "arm"; #elif defined(ARCH_CPU_ARM64) - const char kCPU[] = "arm64"; + static constexpr char kCPU[] = "arm64"; #else #error define kCPU for this CPU #endif diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc index 74a41701..ec404ff5 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -368,10 +368,10 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { const uint32_t kTimeZoneId = 2; const int32_t kBias = 300; - const char kStandardName[] = "EST"; + static constexpr char kStandardName[] = "EST"; const SYSTEMTIME kStandardDate = {0, 11, 1, 0, 2, 0, 0, 0}; const int32_t kStandardBias = 0; - const char kDaylightName[] = "EDT"; + static constexpr char kDaylightName[] = "EDT"; const SYSTEMTIME kDaylightDate = {0, 3, 2, 0, 2, 0, 0, 0}; const int32_t kDaylightBias = -60; @@ -482,8 +482,8 @@ TEST(MinidumpMiscInfoWriter, BuildStrings) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const char kBuildString[] = "build string"; - const char kDebugBuildString[] = "debug build string"; + static constexpr char kBuildString[] = "build string"; + static constexpr char kDebugBuildString[] = "debug build string"; misc_info_writer->SetBuildString(kBuildString, kDebugBuildString); @@ -622,13 +622,13 @@ TEST(MinidumpMiscInfoWriter, Everything) { const uint32_t kProtectedProcess = 1; const uint32_t kTimeZoneId = 2; const int32_t kBias = 300; - const char kStandardName[] = "EST"; + static constexpr char kStandardName[] = "EST"; const int32_t kStandardBias = 0; - const char kDaylightName[] = "EDT"; + static constexpr char kDaylightName[] = "EDT"; const int32_t kDaylightBias = -60; const SYSTEMTIME kSystemTimeZero = {}; - const char kBuildString[] = "build string"; - const char kDebugBuildString[] = "debug build string"; + static constexpr char kBuildString[] = "build string"; + static constexpr char kDebugBuildString[] = "debug build string"; misc_info_writer->SetProcessID(kProcessId); misc_info_writer->SetProcessTimes( @@ -711,14 +711,15 @@ TEST(MinidumpMiscInfoWriter, Everything) { TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { MINIDUMP_MISC_INFO_4 expect_misc_info = {}; - const char kStandardTimeName[] = "EST"; - const char kDaylightTimeName[] = "EDT"; - const char kOSVersionFull[] = + static constexpr char kStandardTimeName[] = "EST"; + static constexpr char kDaylightTimeName[] = "EDT"; + static constexpr char kOSVersionFull[] = "Mac OS X 10.9.5 (13F34); " "Darwin 13.4.0 Darwin Kernel Version 13.4.0: " "Sun Aug 17 19:50:11 PDT 2014; " "root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64"; - const char kMachineDescription[] = "MacBookPro11,3 (Mac-2BD1B31983FE1663)"; + static constexpr char kMachineDescription[] = + "MacBookPro11,3 (Mac-2BD1B31983FE1663)"; base::string16 standard_time_name_utf16 = base::UTF8ToUTF16(kStandardTimeName); base::string16 daylight_time_name_utf16 = diff --git a/minidump/minidump_module_crashpad_info_writer_test.cc b/minidump/minidump_module_crashpad_info_writer_test.cc index 74451843..39a92226 100644 --- a/minidump/minidump_module_crashpad_info_writer_test.cc +++ b/minidump/minidump_module_crashpad_info_writer_test.cc @@ -109,9 +109,9 @@ TEST(MinidumpModuleCrashpadInfoWriter, EmptyModule) { TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { const uint32_t kMinidumpModuleListIndex = 1; - const char kKey[] = "key"; - const char kValue[] = "value"; - const char kEntry[] = "entry"; + static constexpr char kKey[] = "key"; + static constexpr char kValue[] = "value"; + static constexpr char kEntry[] = "entry"; std::vector vector(1, std::string(kEntry)); StringFile string_file; @@ -195,14 +195,14 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) { const uint32_t kMinidumpModuleListIndex0 = 0; - const char kKey0[] = "key"; - const char kValue0[] = "value"; + static constexpr char kKey0[] = "key"; + static constexpr char kValue0[] = "value"; const uint32_t kMinidumpModuleListIndex1 = 2; const uint32_t kMinidumpModuleListIndex2 = 5; - const char kKey2A[] = "K"; - const char kValue2A[] = "VVV"; - const char kKey2B[] = "river"; - const char kValue2B[] = "hudson"; + static constexpr char kKey2A[] = "K"; + static constexpr char kValue2A[] = "VVV"; + static constexpr char kKey2B[] = "river"; + static constexpr char kValue2B[] = "hudson"; StringFile string_file; @@ -339,14 +339,14 @@ TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) { } TEST(MinidumpModuleCrashpadInfoWriter, InitializeFromSnapshot) { - const char kKey0A[] = "k"; - const char kValue0A[] = "value"; - const char kKey0B[] = "hudson"; - const char kValue0B[] = "estuary"; - const char kKey2[] = "k"; - const char kValue2[] = "different_value"; - const char kEntry3A[] = "list"; - const char kEntry3B[] = "erine"; + static constexpr char kKey0A[] = "k"; + static constexpr char kValue0A[] = "value"; + static constexpr char kKey0B[] = "hudson"; + static constexpr char kValue0B[] = "estuary"; + static constexpr char kKey2[] = "k"; + static constexpr char kValue2[] = "different_value"; + static constexpr char kEntry3A[] = "list"; + static constexpr char kEntry3B[] = "erine"; std::vector module_snapshots; diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index b2478d5a..2088b5cf 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -271,7 +271,7 @@ TEST(MinidumpModuleWriter, EmptyModule) { MinidumpFileWriter minidump_file_writer; auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter()); - const char kModuleName[] = "test_executable"; + static constexpr char kModuleName[] = "test_executable"; auto module_writer = base::WrapUnique(new MinidumpModuleWriter()); module_writer->SetName(kModuleName); @@ -310,7 +310,7 @@ TEST(MinidumpModuleWriter, OneModule) { MinidumpFileWriter minidump_file_writer; auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter()); - const char kModuleName[] = "statically_linked"; + static constexpr char kModuleName[] = "statically_linked"; const uint64_t kModuleBase = 0x10da69000; const uint32_t kModuleSize = 0x1000; const uint32_t kChecksum = 0x76543210; @@ -326,15 +326,15 @@ TEST(MinidumpModuleWriter, OneModule) { const uint32_t kFileOS = VOS_DOS; const uint32_t kFileType = VFT_DRV; const uint32_t kFileSubtype = VFT2_DRV_KEYBOARD; - const char kPDBName[] = "statical.pdb"; - const uint8_t kPDBUUIDBytes[16] = + static constexpr char kPDBName[] = "statical.pdb"; + static constexpr uint8_t kPDBUUIDBytes[16] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f}; UUID pdb_uuid; pdb_uuid.InitializeFromBytes(kPDBUUIDBytes); const uint32_t kPDBAge = 1; const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; - const char kDebugName[] = "statical.dbg"; + static constexpr char kDebugName[] = "statical.dbg"; const bool kDebugUTF16 = false; auto module_writer = base::WrapUnique(new MinidumpModuleWriter()); @@ -419,12 +419,12 @@ TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) { MinidumpFileWriter minidump_file_writer; auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter()); - const char kModuleName[] = "dinosaur"; - const char kPDBName[] = "d1n05.pdb"; + static constexpr char kModuleName[] = "dinosaur"; + static constexpr char kPDBName[] = "d1n05.pdb"; const time_t kPDBTimestamp = 0x386d4380; const uint32_t kPDBAge = 1; const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; - const char kDebugName[] = "d1n05.dbg"; + static constexpr char kDebugName[] = "d1n05.dbg"; const bool kDebugUTF16 = true; auto module_writer = base::WrapUnique(new MinidumpModuleWriter()); @@ -480,25 +480,25 @@ TEST(MinidumpModuleWriter, ThreeModules) { MinidumpFileWriter minidump_file_writer; auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter()); - const char kModuleName0[] = "main"; + static constexpr char kModuleName0[] = "main"; const uint64_t kModuleBase0 = 0x100101000; const uint32_t kModuleSize0 = 0xf000; - const char kPDBName0[] = "main"; - const uint8_t kPDBUUIDBytes0[16] = + static constexpr char kPDBName0[] = "main"; + static constexpr uint8_t kPDBUUIDBytes0[16] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; UUID pdb_uuid_0; pdb_uuid_0.InitializeFromBytes(kPDBUUIDBytes0); const uint32_t kPDBAge0 = 0; - const char kModuleName1[] = "ld.so"; + static constexpr char kModuleName1[] = "ld.so"; const uint64_t kModuleBase1 = 0x200202000; const uint32_t kModuleSize1 = 0x1e000; - const char kModuleName2[] = "libc.so"; + static constexpr char kModuleName2[] = "libc.so"; const uint64_t kModuleBase2 = 0x300303000; const uint32_t kModuleSize2 = 0x2d000; - const char kPDBName2[] = "libc.so"; + static constexpr char kPDBName2[] = "libc.so"; const time_t kPDBTimestamp2 = 0x386d4380; const uint32_t kPDBAge2 = 2; @@ -668,7 +668,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[0].VersionInfo.dwFileType = VFT_APP; module_paths[0] = "/usr/bin/true"; module_pdbs[0] = "true"; - const uint8_t kUUIDBytes0[16] = + static constexpr uint8_t kUUIDBytes0[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; uuids[0].InitializeFromBytes(kUUIDBytes0); @@ -684,7 +684,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[1].VersionInfo.dwFileType = VFT_DLL; module_paths[1] = "/usr/lib/libSystem.B.dylib"; module_pdbs[1] = "libSystem.B.dylib.pdb"; - const uint8_t kUUIDBytes1[16] = + static constexpr uint8_t kUUIDBytes1[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; uuids[1].InitializeFromBytes(kUUIDBytes1); @@ -700,7 +700,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[2].VersionInfo.dwFileType = VFT_UNKNOWN; module_paths[2] = "/usr/lib/dyld"; module_pdbs[2] = "/usr/lib/dyld.pdb"; - const uint8_t kUUIDBytes2[16] = + static constexpr uint8_t kUUIDBytes2[16] = {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0}; uuids[2].InitializeFromBytes(kUUIDBytes2); diff --git a/minidump/minidump_rva_list_writer_test.cc b/minidump/minidump_rva_list_writer_test.cc index 1d26b27b..c961b735 100644 --- a/minidump/minidump_rva_list_writer_test.cc +++ b/minidump/minidump_rva_list_writer_test.cc @@ -76,7 +76,7 @@ TEST(MinidumpRVAListWriter, OneChild) { TEST(MinidumpRVAListWriter, ThreeChildren) { TestMinidumpRVAListWriter list_writer; - const uint32_t kValues[] = { 0x80000000, 0x55555555, 0x66006600 }; + static constexpr uint32_t kValues[] = {0x80000000, 0x55555555, 0x66006600}; list_writer.AddChild(kValues[0]); list_writer.AddChild(kValues[1]); diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index 6a1e5c64..25aedf13 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -49,7 +49,7 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { base::string16()); } - const struct { + static constexpr struct { size_t input_length; const char* input_string; size_t output_length; @@ -106,7 +106,7 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { StringFile string_file; - const char* kTestData[] = { + static constexpr const char* kTestData[] = { "\200", // continuation byte "\300", // start byte followed by EOF "\310\177", // start byte without continuation @@ -160,7 +160,7 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { std::string()); } - const struct { + static constexpr struct { size_t length; const char* string; } kTestData[] = { diff --git a/minidump/minidump_system_info_writer_test.cc b/minidump/minidump_system_info_writer_test.cc index 0dd90559..62c41933 100644 --- a/minidump/minidump_system_info_writer_test.cc +++ b/minidump/minidump_system_info_writer_test.cc @@ -129,9 +129,9 @@ TEST(MinidumpSystemInfoWriter, X86_Win) { const uint32_t kOSVersionMajor = 6; const uint32_t kOSVersionMinor = 1; const uint32_t kOSVersionBuild = 7601; - const char kCSDVersion[] = "Service Pack 1"; + static constexpr char kCSDVersion[] = "Service Pack 1"; const uint16_t kSuiteMask = VER_SUITE_SINGLEUSERTS; - const char kCPUVendor[] = "AuthenticAMD"; + static constexpr char kCPUVendor[] = "AuthenticAMD"; const uint32_t kCPUVersion = 0x00100f62; const uint32_t kCPUFeatures = 0x078bfbff; const uint32_t kAMDFeatures = 0xefd3fbff; @@ -200,8 +200,8 @@ TEST(MinidumpSystemInfoWriter, AMD64_Mac) { const uint32_t kOSVersionMajor = 10; const uint32_t kOSVersionMinor = 9; const uint32_t kOSVersionBuild = 4; - const char kCSDVersion[] = "13E28"; - const uint64_t kCPUFeatures[2] = {0x10427f4c, 0x00000000}; + static constexpr char kCSDVersion[] = "13E28"; + static constexpr uint64_t kCPUFeatures[2] = {0x10427f4c, 0x00000000}; system_info_writer->SetCPUArchitecture(kCPUArchitecture); system_info_writer->SetCPULevelAndRevision(kCPULevel, kCPURevision); @@ -248,7 +248,7 @@ TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) { auto system_info_writer = base::WrapUnique(new MinidumpSystemInfoWriter()); const MinidumpCPUArchitecture kCPUArchitecture = kMinidumpCPUArchitectureX86; - const uint32_t kCPUVendor[] = {'uneG', 'Ieni', 'letn'}; + static constexpr uint32_t kCPUVendor[] = {'uneG', 'Ieni', 'letn'}; system_info_writer->SetCPUArchitecture(kCPUArchitecture); system_info_writer->SetCPUX86Vendor( @@ -313,8 +313,8 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) { expect_system_info.Cpu.X86CpuInfo.VersionInformation = kCPUSignature; expect_system_info.Cpu.X86CpuInfo.FeatureInformation = kCPUX86Features & 0xffffffff; - const char kCPUVendor[] = "GenuineIntel"; - const char kOSVersionBuild[] = "13F34"; + static constexpr char kCPUVendor[] = "GenuineIntel"; + static constexpr char kOSVersionBuild[] = "13F34"; TestSystemSnapshot system_snapshot; system_snapshot.SetCPUArchitecture(kCPUArchitectureX86); @@ -408,7 +408,7 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_AMD64) { (1 << PF_RDRAND_INSTRUCTION_AVAILABLE) | (UINT64_C(1) << PF_RDTSCP_INSTRUCTION_AVAILABLE); expect_system_info.Cpu.OtherCpuInfo.ProcessorFeatures[1] = 0; - const char kOSVersionBuild[] = "13F34"; + static constexpr char kOSVersionBuild[] = "13F34"; TestSystemSnapshot system_snapshot; system_snapshot.SetCPUArchitecture(kCPUArchitectureX86_64); diff --git a/minidump/minidump_unloaded_module_writer_test.cc b/minidump/minidump_unloaded_module_writer_test.cc index a6de044f..63cb84d8 100644 --- a/minidump/minidump_unloaded_module_writer_test.cc +++ b/minidump/minidump_unloaded_module_writer_test.cc @@ -74,7 +74,7 @@ TEST(MinidumpUnloadedModuleWriter, EmptyModule) { auto unloaded_module_list_writer = base::WrapUnique(new MinidumpUnloadedModuleListWriter()); - const char kModuleName[] = "test_dll"; + static constexpr char kModuleName[] = "test_dll"; auto unloaded_module_writer = base::WrapUnique(new MinidumpUnloadedModuleWriter()); @@ -113,7 +113,7 @@ TEST(MinidumpUnloadedModuleWriter, OneModule) { auto unloaded_module_list_writer = base::WrapUnique(new MinidumpUnloadedModuleListWriter()); - const char kModuleName[] = "statically_linked"; + static constexpr char kModuleName[] = "statically_linked"; const uint64_t kModuleBase = 0x10da69000; const uint32_t kModuleSize = 0x1000; const uint32_t kChecksum = 0x76543210; diff --git a/minidump/minidump_writable.cc b/minidump/minidump_writable.cc index 8b739060..47e21ff4 100644 --- a/minidump/minidump_writable.cc +++ b/minidump/minidump_writable.cc @@ -248,7 +248,7 @@ bool MinidumpWritable::WritePaddingAndObject(FileWriterInterface* file_writer) { // The number of elements in kZeroes must be at least one less than the // maximum Alignment() ever encountered. - const uint8_t kZeroes[kMaximumAlignment - 1] = {}; + static constexpr uint8_t kZeroes[kMaximumAlignment - 1] = {}; DCHECK_LE(leading_pad_bytes_, arraysize(kZeroes)); if (leading_pad_bytes_) { diff --git a/snapshot/linux/process_reader_test.cc b/snapshot/linux/process_reader_test.cc index 4acbb489..e3743bed 100644 --- a/snapshot/linux/process_reader_test.cc +++ b/snapshot/linux/process_reader_test.cc @@ -81,7 +81,7 @@ TEST(ProcessReader, SelfBasic) { EXPECT_EQ(process_reader.ProcessID(), getpid()); EXPECT_EQ(process_reader.ParentProcessID(), getppid()); - const char kTestMemory[] = "Some test memory"; + static constexpr char kTestMemory[] = "Some test memory"; char buffer[arraysize(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast(kTestMemory), @@ -90,7 +90,7 @@ TEST(ProcessReader, SelfBasic) { EXPECT_STREQ(kTestMemory, buffer); } -const char kTestMemory[] = "Read me from another process"; +constexpr char kTestMemory[] = "Read me from another process"; class BasicChildTest : public Multiprocess { public: diff --git a/snapshot/mac/mach_o_image_annotations_reader_test.cc b/snapshot/mac/mach_o_image_annotations_reader_test.cc index c73eebbf..68d6c4e0 100644 --- a/snapshot/mac/mach_o_image_annotations_reader_test.cc +++ b/snapshot/mac/mach_o_image_annotations_reader_test.cc @@ -212,7 +212,8 @@ class TestMachOImageAnnotationsReader final // dyld exposes its error_string at least as far back as Mac OS X 10.4. if (test_type_ == kCrashDyld) { - const char kExpectedAnnotation[] = "could not load inserted library"; + static constexpr char kExpectedAnnotation[] = + "could not load inserted library"; size_t expected_annotation_length = strlen(kExpectedAnnotation); bool found = false; for (const std::string& annotation : all_annotations_vector) { diff --git a/snapshot/mac/mach_o_image_segment_reader_test.cc b/snapshot/mac/mach_o_image_segment_reader_test.cc index 6e4d415a..2da97e85 100644 --- a/snapshot/mac/mach_o_image_segment_reader_test.cc +++ b/snapshot/mac/mach_o_image_segment_reader_test.cc @@ -53,7 +53,7 @@ TEST(MachOImageSegmentReader, SegmentNameString) { // Segment names defined in . All of these should come // through SegmentNameString() cleanly and without truncation. - const char* kSegmentTestData[] = { + static constexpr const char* kSegmentTestData[] = { SEG_TEXT, SEG_DATA, SEG_OBJC, @@ -91,7 +91,7 @@ TEST(MachOImageSegmentReader, SectionNameString) { // Section names defined in . All of these should come // through SectionNameString() cleanly and without truncation. - const char* kSectionTestData[] = { + static constexpr const char* kSectionTestData[] = { SECT_TEXT, SECT_FVMLIB_INIT0, SECT_FVMLIB_INIT1, @@ -115,12 +115,11 @@ TEST(MachOImageSegmentReader, SectionNameString) { } TEST(MachOImageSegmentReader, SegmentAndSectionNameString) { - struct SegmentAndSectionTestData { + static constexpr struct { const char* segment; const char* section; const char* output; - }; - const SegmentAndSectionTestData kSegmentAndSectionTestData[] = { + } kSegmentAndSectionTestData[] = { {"segment", "section", "segment,section"}, {"Segment", "Section", "Segment,Section"}, {"SEGMENT", "SECTION", "SEGMENT,SECTION"}, @@ -172,7 +171,7 @@ TEST(MachOImageSegmentReader, SegmentAndSectionNameString) { for (size_t index = 0; index < arraysize(kSegmentAndSectionTestData); ++index) { - const SegmentAndSectionTestData& test = kSegmentAndSectionTestData[index]; + const auto& test = kSegmentAndSectionTestData[index]; EXPECT_EQ(MachOImageSegmentReader::SegmentAndSectionNameString( test.segment, test.section), test.output) diff --git a/snapshot/mac/process_reader_test.cc b/snapshot/mac/process_reader_test.cc index 3a6a1c8b..f1aa1ca2 100644 --- a/snapshot/mac/process_reader_test.cc +++ b/snapshot/mac/process_reader_test.cc @@ -58,7 +58,7 @@ namespace crashpad { namespace test { namespace { -const char kDyldPath[] = "/usr/lib/dyld"; +constexpr char kDyldPath[] = "/usr/lib/dyld"; TEST(ProcessReader, SelfBasic) { ProcessReader process_reader; @@ -73,7 +73,7 @@ TEST(ProcessReader, SelfBasic) { EXPECT_EQ(process_reader.ProcessID(), getpid()); EXPECT_EQ(process_reader.ParentProcessID(), getppid()); - const char kTestMemory[] = "Some test memory"; + static constexpr char kTestMemory[] = "Some test memory"; char buffer[arraysize(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( FromPointerCast(kTestMemory), @@ -82,7 +82,7 @@ TEST(ProcessReader, SelfBasic) { EXPECT_STREQ(kTestMemory, buffer); } -const char kTestMemory[] = "Read me from another process"; +constexpr char kTestMemory[] = "Read me from another process"; class ProcessReaderChild final : public MachMultiprocess { public: diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 7839b403..25ecf3da 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -65,7 +65,7 @@ bool ReadIntoVersioned(ProcessReader* process_reader, template size_t dyld_all_image_infos::ExpectedSizeForVersion( decltype(dyld_all_image_infos::version) version) { - const size_t kSizeForVersion[] = { + static constexpr size_t kSizeForVersion[] = { offsetof(dyld_all_image_infos, infoArrayCount), // 0 offsetof(dyld_all_image_infos, libSystemInitialized), // 1 offsetof(dyld_all_image_infos, jitInfo), // 2 diff --git a/snapshot/mac/system_snapshot_mac.cc b/snapshot/mac/system_snapshot_mac.cc index 135fe98e..2bafb274 100644 --- a/snapshot/mac/system_snapshot_mac.cc +++ b/snapshot/mac/system_snapshot_mac.cc @@ -364,9 +364,9 @@ void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status, // no transitions to or from daylight saving time occurred or will occur // within a year of the current date. Arizona, which last observed daylight // saving time in 1967, is an example. - const int kMonthDeltas[] = - { 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, - 7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12 }; + static constexpr int kMonthDeltas[] = + {0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, + 7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12}; for (size_t index = 0; index < arraysize(kMonthDeltas) && !found_transition; ++index) { diff --git a/snapshot/mac/system_snapshot_mac_test.cc b/snapshot/mac/system_snapshot_mac_test.cc index f21d9a27..fb4166f9 100644 --- a/snapshot/mac/system_snapshot_mac_test.cc +++ b/snapshot/mac/system_snapshot_mac_test.cc @@ -210,7 +210,7 @@ TEST_F(SystemSnapshotMacTest, TimeZone) { // standard_name and daylight_name can be nullptr where no name exists to // verify, as may happen when some versions of the timezone database carry // invented names and others do not. - const struct { + static constexpr struct { const char* tz; bool observes_dst; float standard_offset_hours; diff --git a/snapshot/win/pe_image_reader_test.cc b/snapshot/win/pe_image_reader_test.cc index 041d72a2..bf53279d 100644 --- a/snapshot/win/pe_image_reader_test.cc +++ b/snapshot/win/pe_image_reader_test.cc @@ -128,7 +128,7 @@ TEST(PEImageReader, VSFixedFileInfo_OneModule) { ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(), ProcessSuspensionState::kRunning)); - const wchar_t kModuleName[] = L"kernel32.dll"; + static constexpr wchar_t kModuleName[] = L"kernel32.dll"; const HMODULE module_handle = GetModuleHandle(kModuleName); ASSERT_TRUE(module_handle) << ErrorMessage("GetModuleHandle"); diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 87e72a94..9e62e118 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -41,14 +41,14 @@ TEST(ProcessReaderWin, SelfBasic) { EXPECT_EQ(process_reader.GetProcessInfo().ProcessID(), GetCurrentProcessId()); - const char kTestMemory[] = "Some test memory"; + static constexpr char kTestMemory[] = "Some test memory"; char buffer[arraysize(kTestMemory)]; ASSERT_TRUE(process_reader.ReadMemory( reinterpret_cast(kTestMemory), sizeof(kTestMemory), &buffer)); EXPECT_STREQ(kTestMemory, buffer); } -const char kTestMemory[] = "Read me from another process"; +constexpr char kTestMemory[] = "Read me from another process"; class ProcessReaderChild final : public WinMultiprocess { public: diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index f580fd09..326f199c 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -528,7 +528,7 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock( &env_block[0]); env_block.resize( static_cast(bytes_read / sizeof(env_block[0]))); - const wchar_t terminator[] = { 0, 0 }; + static constexpr wchar_t terminator[] = {0, 0}; size_t at = env_block.find(std::wstring(terminator, arraysize(terminator))); if (at != std::wstring::npos) env_block.resize(at + arraysize(terminator)); diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index a8f6fcb1..e228905e 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -98,7 +98,7 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { os_server_ = version_info.wProductType != VER_NT_WORKSTATION; } - const wchar_t kSystemDll[] = L"kernel32.dll"; + static constexpr wchar_t kSystemDll[] = L"kernel32.dll"; VS_FIXEDFILEINFO ffi; if (GetModuleVersionAndType(base::FilePath(kSystemDll), &ffi)) { std::string flags_string = GetStringForFileFlags(ffi.dwFileFlags); diff --git a/test/file.cc b/test/file.cc index 75af744d..04b4625f 100644 --- a/test/file.cc +++ b/test/file.cc @@ -28,11 +28,11 @@ bool FileExists(const base::FilePath& path) { #if defined(OS_POSIX) struct stat st; int rv = lstat(path.value().c_str(), &st); - const char stat_function[] = "lstat"; + static constexpr char stat_function[] = "lstat"; #elif defined(OS_WIN) struct _stat st; int rv = _wstat(path.value().c_str(), &st); - const char stat_function[] = "_wstat"; + static constexpr char stat_function[] = "_wstat"; #else #error "Not implemented" #endif @@ -48,11 +48,11 @@ FileOffset FileSize(const base::FilePath& path) { #if defined(OS_POSIX) struct stat st; int rv = lstat(path.value().c_str(), &st); - const char stat_function[] = "lstat"; + static constexpr char stat_function[] = "lstat"; #elif defined(OS_WIN) struct _stati64 st; int rv = _wstati64(path.value().c_str(), &st); - const char stat_function[] = "_wstati64"; + static constexpr char stat_function[] = "_wstati64"; #else #error "Not implemented" #endif diff --git a/test/hex_string_test.cc b/test/hex_string_test.cc index 1915a856..68745e6f 100644 --- a/test/hex_string_test.cc +++ b/test/hex_string_test.cc @@ -24,7 +24,7 @@ namespace { TEST(HexString, HexString) { EXPECT_EQ(BytesToHexString(nullptr, 0), ""); - const char kBytes[] = "Abc123xyz \x0a\x7f\xf0\x9f\x92\xa9_"; + static constexpr char kBytes[] = "Abc123xyz \x0a\x7f\xf0\x9f\x92\xa9_"; EXPECT_EQ(BytesToHexString(kBytes, arraysize(kBytes)), "41626331323378797a200a7ff09f92a95f00"); } diff --git a/test/win/win_child_process.cc b/test/win/win_child_process.cc index 4c821a0c..44177f63 100644 --- a/test/win/win_child_process.cc +++ b/test/win/win_child_process.cc @@ -35,7 +35,7 @@ namespace test { namespace { -const char kIsMultiprocessChild[] = "--is-multiprocess-child"; +constexpr char kIsMultiprocessChild[] = "--is-multiprocess-child"; bool GetSwitch(const char* switch_name, std::string* value) { int num_args; diff --git a/tools/crashpad_database_util.cc b/tools/crashpad_database_util.cc index b2c4cb49..cc21698b 100644 --- a/tools/crashpad_database_util.cc +++ b/tools/crashpad_database_util.cc @@ -92,7 +92,7 @@ struct Options { // performed. Various string representations of a boolean are recognized // case-insensitively. bool StringToBool(const char* string, bool* boolean) { - const char* const kFalseWords[] = { + static constexpr const char* kFalseWords[] = { "0", "false", "no", @@ -100,7 +100,7 @@ bool StringToBool(const char* string, bool* boolean) { "disabled", "clear", }; - const char* const kTrueWords[] = { + static constexpr const char* kTrueWords[] = { "1", "true", "yes", @@ -153,7 +153,7 @@ bool StringToTime(const char* string, time_t* out_time, bool utc) { const char* end = string + strlen(string); - const char* const kFormats[] = { + static constexpr const char* kFormats[] = { "%Y-%m-%d %H:%M:%S %Z", "%Y-%m-%d %H:%M:%S", "%+", @@ -294,7 +294,7 @@ int DatabaseUtilMain(int argc, char* argv[]) { kOptionVersion = -3, }; - const option long_options[] = { + static constexpr option long_options[] = { {"create", no_argument, nullptr, kOptionCreate}, {"database", required_argument, nullptr, kOptionDatabase}, {"show-client-id", no_argument, nullptr, kOptionShowClientID}, diff --git a/tools/crashpad_http_upload.cc b/tools/crashpad_http_upload.cc index d4ec3f9c..f8a85c43 100644 --- a/tools/crashpad_http_upload.cc +++ b/tools/crashpad_http_upload.cc @@ -74,7 +74,7 @@ int HTTPUploadMain(int argc, char* argv[]) { } options = {}; options.upload_gzip = true; - const option long_options[] = { + static constexpr option long_options[] = { {"file", required_argument, nullptr, kOptionFile}, {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip}, {"output", required_argument, nullptr, kOptionOutput}, diff --git a/tools/generate_dump.cc b/tools/generate_dump.cc index b98b1f4f..956af81b 100644 --- a/tools/generate_dump.cc +++ b/tools/generate_dump.cc @@ -85,7 +85,7 @@ int GenerateDumpMain(int argc, char* argv[]) { } options = {}; options.suspend = true; - const option long_options[] = { + static constexpr option long_options[] = { {"no-suspend", no_argument, nullptr, kOptionNoSuspend}, {"output", required_argument, nullptr, kOptionOutput}, {"help", no_argument, nullptr, kOptionHelp}, diff --git a/tools/mac/catch_exception_tool.cc b/tools/mac/catch_exception_tool.cc index 3a535cb2..d4dc3c12 100644 --- a/tools/mac/catch_exception_tool.cc +++ b/tools/mac/catch_exception_tool.cc @@ -214,7 +214,7 @@ int CatchExceptionToolMain(int argc, char* argv[]) { Options options = {}; - const option long_options[] = { + static constexpr option long_options[] = { {"file", required_argument, nullptr, kOptionFile}, {"mach-service", required_argument, nullptr, kOptionMachService}, {"persistent", no_argument, nullptr, kOptionPersistent}, diff --git a/tools/mac/exception_port_tool.cc b/tools/mac/exception_port_tool.cc index 3faa00fe..a047e964 100644 --- a/tools/mac/exception_port_tool.cc +++ b/tools/mac/exception_port_tool.cc @@ -106,8 +106,8 @@ struct ExceptionHandlerDescription { std::string handler; }; -const char kHandlerNull[] = "NULL"; -const char kHandlerBootstrapColon[] = "bootstrap:"; +constexpr char kHandlerNull[] = "NULL"; +constexpr char kHandlerBootstrapColon[] = "bootstrap:"; // Populates |description| based on a textual representation in // |handler_string_ro|, returning true on success and false on failure (parse @@ -120,11 +120,11 @@ const char kHandlerBootstrapColon[] = "bootstrap:"; // SymbolicConstantsMach. bool ParseHandlerString(const char* handler_string_ro, ExceptionHandlerDescription* description) { - const char kTargetEquals[] = "target="; - const char kMaskEquals[] = "mask="; - const char kBehaviorEquals[] = "behavior="; - const char kFlavorEquals[] = "flavor="; - const char kHandlerEquals[] = "handler="; + static constexpr char kTargetEquals[] = "target="; + static constexpr char kMaskEquals[] = "mask="; + static constexpr char kBehaviorEquals[] = "behavior="; + static constexpr char kFlavorEquals[] = "flavor="; + static constexpr char kHandlerEquals[] = "handler="; std::string handler_string(handler_string_ro); char* handler_string_c = &handler_string[0]; @@ -400,7 +400,7 @@ int ExceptionPortToolMain(int argc, char* argv[]) { bool numeric; } options = {}; - const option long_options[] = { + static constexpr option long_options[] = { {"set-handler", required_argument, nullptr, kOptionSetPort}, {"show-bootstrap", required_argument, nullptr, kOptionShowBootstrap}, {"pid", required_argument, nullptr, kOptionPid}, diff --git a/tools/mac/on_demand_service_tool.mm b/tools/mac/on_demand_service_tool.mm index c6b69520..70de1b52 100644 --- a/tools/mac/on_demand_service_tool.mm +++ b/tools/mac/on_demand_service_tool.mm @@ -81,7 +81,7 @@ int OnDemandServiceToolMain(int argc, char* argv[]) { std::vector mach_services; } options = {}; - const option long_options[] = { + static constexpr option long_options[] = { {"load", no_argument, nullptr, kOptionLoadJob}, {"unload", no_argument, nullptr, kOptionUnloadJob}, {"label", required_argument, nullptr, kOptionJobLabel}, diff --git a/tools/mac/run_with_crashpad.cc b/tools/mac/run_with_crashpad.cc index 135d6d98..39095145 100644 --- a/tools/mac/run_with_crashpad.cc +++ b/tools/mac/run_with_crashpad.cc @@ -84,7 +84,7 @@ int RunWithCrashpadMain(int argc, char* argv[]) { kOptionVersion = -3, }; - const option long_options[] = { + static constexpr option long_options[] = { {"handler", required_argument, nullptr, kOptionHandler}, {"annotation", required_argument, nullptr, kOptionAnnotation}, {"database", required_argument, nullptr, kOptionDatabase}, diff --git a/util/file/delimited_file_reader_test.cc b/util/file/delimited_file_reader_test.cc index 84ecb846..79e331f7 100644 --- a/util/file/delimited_file_reader_test.cc +++ b/util/file/delimited_file_reader_test.cc @@ -257,7 +257,7 @@ TEST(DelimitedFileReader, ReallyLongMultiLineFile) { } TEST(DelimitedFileReader, EmbeddedNUL) { - const char kString[] = "embedded\0NUL\n"; + static constexpr char kString[] = "embedded\0NUL\n"; StringFile string_file; string_file.SetString(std::string(kString, arraysize(kString) - 1)); DelimitedFileReader delimited_file_reader(&string_file); @@ -275,7 +275,7 @@ TEST(DelimitedFileReader, EmbeddedNUL) { } TEST(DelimitedFileReader, NULDelimiter) { - const char kString[] = "aa\0b\0ccc\0"; + static constexpr char kString[] = "aa\0b\0ccc\0"; StringFile string_file; string_file.SetString(std::string(kString, arraysize(kString) - 1)); DelimitedFileReader delimited_file_reader(&string_file); @@ -299,7 +299,8 @@ TEST(DelimitedFileReader, NULDelimiter) { } TEST(DelimitedFileReader, EdgeCases) { - const size_t kSizes[] = {4094, 4095, 4096, 4097, 8190, 8191, 8192, 8193}; + static constexpr size_t kSizes[] = + {4094, 4095, 4096, 4097, 8190, 8191, 8192, 8193}; for (size_t index = 0; index < arraysize(kSizes); ++index) { size_t size = kSizes[index]; SCOPED_TRACE( diff --git a/util/file/file_io_test.cc b/util/file/file_io_test.cc index a784abd2..400cbace 100644 --- a/util/file/file_io_test.cc +++ b/util/file/file_io_test.cc @@ -660,7 +660,7 @@ TEST(FileIO, FileSizeByHandle) { ASSERT_NE(file_handle.get(), kInvalidFileHandle); EXPECT_EQ(LoggingFileSizeByHandle(file_handle.get()), 0); - const char data[] = "zippyzap"; + static constexpr char data[] = "zippyzap"; ASSERT_TRUE(LoggingWriteFile(file_handle.get(), &data, sizeof(data))); EXPECT_EQ(LoggingFileSizeByHandle(file_handle.get()), 9); diff --git a/util/linux/process_memory_test.cc b/util/linux/process_memory_test.cc index 21377553..4ad2e756 100644 --- a/util/linux/process_memory_test.cc +++ b/util/linux/process_memory_test.cc @@ -135,8 +135,8 @@ bool ReadCStringSizeLimited(const ProcessMemory& memory, FromPointerCast(pointer), size, result); } -const char kConstCharEmpty[] = ""; -const char kConstCharShort[] = "A short const char[]"; +constexpr char kConstCharEmpty[] = ""; +constexpr char kConstCharShort[] = "A short const char[]"; class ReadCStringTest : public TargetProcessTest { public: diff --git a/util/mac/checked_mach_address_range_test.cc b/util/mac/checked_mach_address_range_test.cc index 860bdff8..089f6815 100644 --- a/util/mac/checked_mach_address_range_test.cc +++ b/util/mac/checked_mach_address_range_test.cc @@ -43,7 +43,7 @@ bool ExpectationForValidity64(Validity validity) { } TEST(CheckedMachAddressRange, IsValid) { - const struct TestData { + static constexpr struct { mach_vm_address_t base; mach_vm_size_t size; Validity validity; @@ -117,7 +117,7 @@ TEST(CheckedMachAddressRange, IsValid) { }; for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %zu, base 0x%llx, size 0x%llx", index, testcase.base, @@ -132,7 +132,7 @@ TEST(CheckedMachAddressRange, IsValid) { } TEST(CheckedMachAddressRange, ContainsValue) { - const struct TestData { + static constexpr struct { mach_vm_address_t value; bool expectation; } kTestData[] = { @@ -167,7 +167,7 @@ TEST(CheckedMachAddressRange, ContainsValue) { ASSERT_TRUE(parent_range_32.IsValid()); for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE( base::StringPrintf("index %zu, value 0x%llx", index, testcase.value)); @@ -185,7 +185,7 @@ TEST(CheckedMachAddressRange, ContainsValue) { } TEST(CheckedMachAddressRange, ContainsRange) { - const struct TestData { + static constexpr struct { mach_vm_address_t base; mach_vm_size_t size; bool expectation; @@ -224,7 +224,7 @@ TEST(CheckedMachAddressRange, ContainsRange) { ASSERT_TRUE(parent_range_32.IsValid()); for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %zu, base 0x%llx, size 0x%llx", index, testcase.base, diff --git a/util/mac/launchd_test.mm b/util/mac/launchd_test.mm index 8d9db762..12ed8320 100644 --- a/util/mac/launchd_test.mm +++ b/util/mac/launchd_test.mm @@ -153,7 +153,7 @@ TEST(Launchd, CFPropertyToLaunchData_Data) { @autoreleasepool { base::mac::ScopedLaunchData launch_data; - const uint8_t data_c[] = { + static constexpr uint8_t data_c[] = { 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2}; NSData* data_ns = [NSData dataWithBytes:data_c length:sizeof(data_c)]; launch_data.reset(CFPropertyToLaunchData(data_ns)); diff --git a/util/mac/service_management_test.mm b/util/mac/service_management_test.mm index 769c32f1..55019df0 100644 --- a/util/mac/service_management_test.mm +++ b/util/mac/service_management_test.mm @@ -114,7 +114,8 @@ TEST(ServiceManagement, SubmitRemoveJob) { base::StringPrintf("sleep 10; echo %s", cookie.c_str()); NSString* shell_script_ns = base::SysUTF8ToNSString(shell_script); - const char kJobLabel[] = "org.chromium.crashpad.test.service_management"; + static constexpr char kJobLabel[] = + "org.chromium.crashpad.test.service_management"; NSDictionary* job_dictionary_ns = @{ @LAUNCH_JOBKEY_LABEL : @"org.chromium.crashpad.test.service_management", @LAUNCH_JOBKEY_RUNATLOAD : @YES, diff --git a/util/mac/xattr_test.cc b/util/mac/xattr_test.cc index 477bb138..56318d13 100644 --- a/util/mac/xattr_test.cc +++ b/util/mac/xattr_test.cc @@ -55,7 +55,7 @@ class Xattr : public testing::Test { base::FilePath path_; }; -const char kKey[] = "com.google.crashpad.test"; +constexpr char kKey[] = "org.chromium.crashpad.test"; TEST_F(Xattr, ReadNonExistentXattr) { std::string value; diff --git a/util/mach/child_port_server.cc b/util/mach/child_port_server.cc index 4fc723ac..9a34d431 100644 --- a/util/mach/child_port_server.cc +++ b/util/mach/child_port_server.cc @@ -106,7 +106,8 @@ bool ChildPortServer::MachMessageServerFunction( } std::set ChildPortServer::MachMessageServerRequestIDs() { - const mach_msg_id_t request_ids[] = {kMachMessageIDChildPortCheckIn}; + static constexpr mach_msg_id_t request_ids[] = + {kMachMessageIDChildPortCheckIn}; return std::set(&request_ids[0], &request_ids[arraysize(request_ids)]); } diff --git a/util/mach/composite_mach_message_server_test.cc b/util/mach/composite_mach_message_server_test.cc index 3a37e49b..9325ba33 100644 --- a/util/mach/composite_mach_message_server_test.cc +++ b/util/mach/composite_mach_message_server_test.cc @@ -182,13 +182,13 @@ TEST(CompositeMachMessageServer, OneHandler) { } TEST(CompositeMachMessageServer, ThreeHandlers) { - const mach_msg_id_t kRequestIDs0[] = {5}; + static constexpr mach_msg_id_t kRequestIDs0[] = {5}; const kern_return_t kReturnCode0 = KERN_SUCCESS; - const mach_msg_id_t kRequestIDs1[] = {4, 7}; + static constexpr mach_msg_id_t kRequestIDs1[] = {4, 7}; const kern_return_t kReturnCode1 = KERN_PROTECTION_FAILURE; - const mach_msg_id_t kRequestIDs2[] = {10, 0, 20}; + static constexpr mach_msg_id_t kRequestIDs2[] = {10, 0, 20}; const mach_msg_size_t kRequestSize2 = 6144; const mach_msg_size_t kReplySize2 = 16384; const kern_return_t kReturnCode2 = KERN_NOT_RECEIVER; diff --git a/util/mach/exc_client_variants_test.cc b/util/mach/exc_client_variants_test.cc index 3bf77bb5..b7288563 100644 --- a/util/mach/exc_client_variants_test.cc +++ b/util/mach/exc_client_variants_test.cc @@ -264,7 +264,7 @@ mach_exception_subcode_t TestExcClientVariants::exception_subcode_ = 0xffffffff00000000; TEST(ExcClientVariants, UniversalExceptionRaise) { - const exception_behavior_t kBehaviors[] = { + static constexpr exception_behavior_t kBehaviors[] = { EXCEPTION_DEFAULT, EXCEPTION_STATE, EXCEPTION_STATE_IDENTITY, diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index 482edac3..149184b2 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -877,7 +877,7 @@ TEST(ExcServerVariants, MockUnknownID) { // UniversalMachExcServer should not dispatch the message to // MachMessageServerFunction, but should generate a MIG_BAD_ID error reply. - const mach_msg_id_t unknown_ids[] = { + static constexpr mach_msg_id_t unknown_ids[] = { // Reasonable things to check. -101, -100, @@ -1130,11 +1130,10 @@ TEST(ExcServerVariants, ThreadStates) { // So far, all of the tests worked with MACHINE_THREAD_STATE. Now try all of // the other thread state flavors that are expected to work. - struct TestData { + static constexpr struct { thread_state_flavor_t flavor; mach_msg_type_number_t count; - }; - const TestData test_data[] = { + } test_data[] = { #if defined(ARCH_CPU_X86_FAMILY) // For the x86 family, exception handlers can only properly receive the // thread, float, and exception state flavors. There’s a bug in the kernel @@ -1179,7 +1178,7 @@ TEST(ExcServerVariants, ThreadStates) { }; for (size_t index = 0; index < arraysize(test_data); ++index) { - const TestData& test = test_data[index]; + const auto& test = test_data[index]; SCOPED_TRACE( base::StringPrintf("index %zu, flavor %d", index, test.flavor)); @@ -1195,13 +1194,12 @@ TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { const kern_return_t prefer_not_set_thread_state = MacOSXMinorVersion() < 11 ? MACH_RCV_PORT_DIED : KERN_SUCCESS; - struct TestData { + const struct { exception_type_t exception; exception_behavior_t behavior; bool set_thread_state; kern_return_t kr; - }; - const TestData kTestData[] = { + } kTestData[] = { {EXC_CRASH, EXCEPTION_DEFAULT, false, KERN_SUCCESS}, {EXC_CRASH, EXCEPTION_STATE, false, prefer_not_set_thread_state}, {EXC_CRASH, EXCEPTION_STATE_IDENTITY, false, prefer_not_set_thread_state}, @@ -1253,7 +1251,7 @@ TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { }; for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& test_data = kTestData[index]; + const auto& test_data = kTestData[index]; SCOPED_TRACE( base::StringPrintf("index %zu, behavior %d, set_thread_state %s", index, @@ -1268,7 +1266,7 @@ TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { } TEST(ExcServerVariants, ExcServerCopyState) { - const natural_t old_state[] = {1, 2, 3, 4, 5}; + static constexpr natural_t old_state[] = {1, 2, 3, 4, 5}; natural_t new_state[10] = {}; const mach_msg_type_number_t old_state_count = arraysize(old_state); diff --git a/util/mach/exception_behaviors_test.cc b/util/mach/exception_behaviors_test.cc index 3ccb2027..d45110d9 100644 --- a/util/mach/exception_behaviors_test.cc +++ b/util/mach/exception_behaviors_test.cc @@ -26,14 +26,13 @@ namespace test { namespace { TEST(ExceptionBehaviors, ExceptionBehaviors) { - struct TestData { + static constexpr struct { exception_behavior_t behavior; bool state; bool identity; bool mach_exception_codes; exception_behavior_t basic_behavior; - }; - const TestData kTestData[] = { + } kTestData[] = { {EXCEPTION_DEFAULT, false, true, false, EXCEPTION_DEFAULT}, {EXCEPTION_STATE, true, false, false, EXCEPTION_STATE}, {EXCEPTION_STATE_IDENTITY, true, true, false, EXCEPTION_STATE_IDENTITY}, @@ -55,7 +54,7 @@ TEST(ExceptionBehaviors, ExceptionBehaviors) { }; for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& test_data = kTestData[index]; + const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, behavior %d", index, test_data.behavior)); diff --git a/util/mach/exception_types_test.cc b/util/mach/exception_types_test.cc index ff09164e..c24428a2 100644 --- a/util/mach/exception_types_test.cc +++ b/util/mach/exception_types_test.cc @@ -31,13 +31,12 @@ namespace test { namespace { TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { - struct TestData { + static constexpr struct { mach_exception_code_t code_0; exception_type_t exception; mach_exception_code_t original_code_0; int signal; - }; - const TestData kTestData[] = { + } kTestData[] = { {0xb100001, EXC_BAD_ACCESS, KERN_INVALID_ADDRESS, SIGSEGV}, {0xb100002, EXC_BAD_ACCESS, KERN_PROTECTION_FAILURE, SIGSEGV}, {0xa100002, EXC_BAD_ACCESS, KERN_PROTECTION_FAILURE, SIGBUS}, @@ -69,7 +68,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { }; for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& test_data = kTestData[index]; + const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, code_0 0x%llx", index, test_data.code_0)); @@ -86,7 +85,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { // Now make sure that ExcCrashRecoverOriginalException() properly ignores // optional arguments. static_assert(arraysize(kTestData) >= 1, "must have something to test"); - const TestData& test_data = kTestData[0]; + const auto& test_data = kTestData[0]; EXPECT_EQ( ExcCrashRecoverOriginalException(test_data.code_0, nullptr, nullptr), test_data.exception); @@ -133,12 +132,11 @@ TEST(ExceptionTypes, ExcCrashCouldContainException) { (static_cast(flavor) & 0x7ull) << 58))) TEST(ExceptionTypes, ExceptionCodeForMetrics) { - struct TestData { + static constexpr struct { exception_type_t exception; mach_exception_code_t code_0; int32_t metrics_code; - }; - const TestData kTestData[] = { + } kTestData[] = { #define ENCODE_EXC(type, code_0) \ { (type), (code_0), ((type) << 16) | (code_0) } ENCODE_EXC(EXC_BAD_ACCESS, KERN_INVALID_ADDRESS), @@ -241,7 +239,7 @@ TEST(ExceptionTypes, ExceptionCodeForMetrics) { }; for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& test_data = kTestData[index]; + const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %zu, exception 0x%x, code_0 0x%llx", index, test_data.exception, diff --git a/util/mach/mach_message_server_test.cc b/util/mach/mach_message_server_test.cc index e42ef6a5..e0ffebe8 100644 --- a/util/mach/mach_message_server_test.cc +++ b/util/mach/mach_message_server_test.cc @@ -279,7 +279,7 @@ class TestMachMessageServer : public MachMessageServer::Interface, } std::set MachMessageServerRequestIDs() override { - const mach_msg_id_t request_ids[] = {kRequestMessageID}; + static constexpr mach_msg_id_t request_ids[] = {kRequestMessageID}; return std::set(&request_ids[0], &request_ids[arraysize(request_ids)]); } diff --git a/util/mach/notify_server.cc b/util/mach/notify_server.cc index 9ac377d1..2dbdf73e 100644 --- a/util/mach/notify_server.cc +++ b/util/mach/notify_server.cc @@ -259,7 +259,7 @@ bool NotifyServer::MachMessageServerFunction( } std::set NotifyServer::MachMessageServerRequestIDs() { - const mach_msg_id_t request_ids[] = { + static constexpr mach_msg_id_t request_ids[] = { MACH_NOTIFY_PORT_DELETED, MACH_NOTIFY_PORT_DESTROYED, MACH_NOTIFY_NO_SENDERS, diff --git a/util/mach/symbolic_constants_mach.cc b/util/mach/symbolic_constants_mach.cc index 26cc564f..b7296be2 100644 --- a/util/mach/symbolic_constants_mach.cc +++ b/util/mach/symbolic_constants_mach.cc @@ -26,7 +26,7 @@ namespace { -const char* kExceptionNames[] = { +constexpr const char* kExceptionNames[] = { nullptr, // sed -Ene 's/^#define[[:space:]]EXC_([[:graph:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/ "\1",/p' @@ -48,10 +48,10 @@ const char* kExceptionNames[] = { static_assert(arraysize(kExceptionNames) == EXC_TYPES_COUNT, "kExceptionNames length"); -const char kExcPrefix[] = "EXC_"; -const char kExcMaskPrefix[] = "EXC_MASK_"; +constexpr char kExcPrefix[] = "EXC_"; +constexpr char kExcMaskPrefix[] = "EXC_MASK_"; -const char* kBehaviorNames[] = { +constexpr const char* kBehaviorNames[] = { nullptr, // sed -Ene 's/^# define[[:space:]]EXCEPTION_([[:graph:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/ "\1",/p' @@ -61,11 +61,11 @@ const char* kBehaviorNames[] = { "STATE_IDENTITY", }; -const char kBehaviorPrefix[] = "EXCEPTION_"; -const char kMachExceptionCodesFull[] = "MACH_EXCEPTION_CODES"; -const char kMachExceptionCodesShort[] = "MACH"; +constexpr char kBehaviorPrefix[] = "EXCEPTION_"; +constexpr char kMachExceptionCodesFull[] = "MACH_EXCEPTION_CODES"; +constexpr char kMachExceptionCodesShort[] = "MACH"; -const char* kFlavorNames[] = { +constexpr const char* kFlavorNames[] = { "THREAD_STATE_FLAVOR_LIST", #if defined(__i386__) || defined(__x86_64__) @@ -128,7 +128,7 @@ const char* kFlavorNames[] = { // Certain generic flavors have high constants not contiguous with the flavors // above. List them separately alongside their constants. -const struct { +constexpr struct { thread_state_flavor_t flavor; const char* name; } kGenericFlavorNames[] = { @@ -139,7 +139,7 @@ const struct { // Returns the short name for a flavor name, given its full flavor name. std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) { // For generic flavors like THREAD_STATE_NONE and THREAD_STATE_FLAVOR_LIST_*. - const char kThreadState[] = "THREAD_STATE_"; + static constexpr char kThreadState[] = "THREAD_STATE_"; size_t prefix_len = strlen(kThreadState); const char* flavor_data = flavor.data(); size_t flavor_len = flavor.size(); @@ -150,11 +150,11 @@ std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) { // For architecture-specific flavors. #if defined(__i386__) || defined(__x86_64__) - const char kArchPrefix[] = "x86_"; + static constexpr char kArchPrefix[] = "x86_"; #elif defined(__ppc__) || defined(__ppc64__) - const char kArchPrefix[] = "PPC_"; + static constexpr char kArchPrefix[] = "PPC_"; #elif defined(__arm__) || defined(__arm64__) - const char kArchPrefix[] = "ARM_" + static constexpr char kArchPrefix[] = "ARM_" #endif prefix_len = strlen(kArchPrefix); if (flavor_len >= prefix_len && @@ -162,7 +162,7 @@ std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) { // Shorten the suffix by removing _STATE. If the suffix contains a // significant designation like 32 or 64, keep it, so that a full name like // x86_THREAD_STATE64 becomes a short name like THREAD64. - const struct { + static constexpr struct { const char* orig; const char* repl; } kStateSuffixes[] = { @@ -343,7 +343,7 @@ bool StringToExceptionMask(const base::StringPiece& string, // EXC_MASK_ALL is a special case: it is not in kExceptionNames as it exists // only as a mask value. - const char kExcMaskAll[] = "ALL"; + static constexpr char kExcMaskAll[] = "ALL"; if ((can_match_full && short_string.compare(kExcMaskAll) == 0) || ((options & kAllowShortName) && string.compare(kExcMaskAll) == 0)) { *exception_mask = ExcMaskAll(); diff --git a/util/mach/symbolic_constants_mach_test.cc b/util/mach/symbolic_constants_mach_test.cc index f3086d25..c8d6d48e 100644 --- a/util/mach/symbolic_constants_mach_test.cc +++ b/util/mach/symbolic_constants_mach_test.cc @@ -32,7 +32,7 @@ namespace test { namespace { // Options to use for normal tests, those that don’t require kAllowOr. -const StringToSymbolicConstantOptions kNormalOptions[] = { +constexpr StringToSymbolicConstantOptions kNormalOptions[] = { 0, kAllowFullName, kAllowShortName, @@ -118,7 +118,7 @@ void TestStringToSomething(const base::StringPiece& string, } } -const struct { +constexpr struct { exception_type_t exception; const char* full_name; const char* short_name; @@ -217,7 +217,7 @@ TEST(SymbolicConstantsMach, StringToException) { } } - const char* const kNegativeTestData[] = { + static constexpr const char* kNegativeTestData[] = { "EXC_CRASH ", " EXC_BAD_INSTRUCTION", "CRASH ", @@ -235,7 +235,7 @@ TEST(SymbolicConstantsMach, StringToException) { TestStringToException(kNegativeTestData[index], options, false, 0); } - const struct { + static constexpr struct { const char* string; size_t length; } kNULTestData[] = { @@ -276,7 +276,7 @@ TEST(SymbolicConstantsMach, StringToException) { } } -const struct { +constexpr struct { exception_mask_t exception_mask; const char* full_name; const char* short_name; @@ -370,7 +370,7 @@ void TestStringToExceptionMask(const base::StringPiece& string, TEST(SymbolicConstantsMach, StringToExceptionMask) { // Don’t use kNormalOptions, because kAllowOr needs to be tested. - const StringToSymbolicConstantOptions kOptions[] = { + static constexpr StringToSymbolicConstantOptions kOptions[] = { 0, kAllowFullName, kAllowShortName, @@ -430,7 +430,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { } } - const char* const kNegativeTestData[] = { + static constexpr const char* kNegativeTestData[] = { "EXC_MASK_CRASH ", " EXC_MASK_BAD_INSTRUCTION", "EXC_MASK_EXC_MASK_BAD_ACCESS", @@ -450,7 +450,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { TestStringToExceptionMask(kNegativeTestData[index], options, false, 0); } - const struct { + static constexpr struct { const char* string; size_t length; } kNULTestData[] = { @@ -479,7 +479,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { } } - const struct { + static const struct { const char* string; StringToSymbolicConstantOptions options; exception_mask_t mask; @@ -531,7 +531,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { } } -const struct { +constexpr struct { exception_behavior_t behavior; const char* full_name; const char* short_name; @@ -643,7 +643,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { } } - const char* const kNegativeTestData[] = { + static constexpr const char* kNegativeTestData[] = { "EXCEPTION_DEFAULT ", " EXCEPTION_STATE", "EXCEPTION_EXCEPTION_STATE_IDENTITY", @@ -666,7 +666,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { kNegativeTestData[index], options, false, 0); } - const struct { + static constexpr struct { const char* string; size_t length; } kNULTestData[] = { @@ -694,7 +694,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { } } - const struct { + static constexpr struct { const char* string; StringToSymbolicConstantOptions options; exception_behavior_t behavior; @@ -763,7 +763,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { } } -const struct { +constexpr struct { thread_state_flavor_t flavor; const char* full_name; const char* short_name; @@ -917,7 +917,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { } } - const char* const kNegativeTestData[] = { + static constexpr const char* kNegativeTestData[] = { "THREAD_STATE_NONE ", " THREAD_STATE_NONE", "NONE ", @@ -965,7 +965,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { kNegativeTestData[index], options, false, 0); } - const struct { + static constexpr struct { const char* string; size_t length; } kNULTestData[] = { diff --git a/util/mach/task_memory_test.cc b/util/mach/task_memory_test.cc index 514f48f1..24adb409 100644 --- a/util/mach/task_memory_test.cc +++ b/util/mach/task_memory_test.cc @@ -194,6 +194,27 @@ TEST(TaskMemory, ReadCStringSelf) { EXPECT_FALSE(result.empty()); EXPECT_EQ(result, kStaticConstCharShort); + constexpr char kConstexprCharEmpty[] = ""; + ASSERT_TRUE(ReadCStringSelf(&memory, kConstexprCharEmpty, &result)); + EXPECT_TRUE(result.empty()); + EXPECT_EQ(result, kConstexprCharEmpty); + + constexpr char kConstexprCharShort[] = "A short constexpr char[]"; + ASSERT_TRUE(ReadCStringSelf(&memory, kConstexprCharShort, &result)); + EXPECT_FALSE(result.empty()); + EXPECT_EQ(result, kConstexprCharShort); + + static constexpr char kStaticConstexprCharEmpty[] = ""; + ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstexprCharEmpty, &result)); + EXPECT_TRUE(result.empty()); + EXPECT_EQ(result, kStaticConstexprCharEmpty); + + static constexpr char kStaticConstexprCharShort[] = + "A short static constexpr char[]"; + ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstexprCharShort, &result)); + EXPECT_FALSE(result.empty()); + EXPECT_EQ(result, kStaticConstexprCharShort); + std::string string_short("A short std::string in a function"); ASSERT_TRUE(ReadCStringSelf(&memory, &string_short[0], &result)); EXPECT_FALSE(result.empty()); @@ -280,7 +301,7 @@ TEST(TaskMemory, ReadCStringSizeLimited_ConstCharEmpty) { TaskMemory memory(mach_task_self()); std::string result; - const char kConstCharEmpty[] = ""; + static constexpr char kConstCharEmpty[] = ""; ASSERT_TRUE(ReadCStringSizeLimitedSelf( &memory, kConstCharEmpty, arraysize(kConstCharEmpty), &result)); EXPECT_TRUE(result.empty()); @@ -302,7 +323,7 @@ TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) { TaskMemory memory(mach_task_self()); std::string result; - const char kConstCharShort[] = "A short const char[]"; + static constexpr char kConstCharShort[] = "A short const char[]"; ASSERT_TRUE(ReadCStringSizeLimitedSelf( &memory, kConstCharShort, arraysize(kConstCharShort), &result)); EXPECT_FALSE(result.empty()); @@ -322,7 +343,7 @@ TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharEmpty) { TaskMemory memory(mach_task_self()); std::string result; - static const char kStaticConstCharEmpty[] = ""; + static constexpr char kStaticConstCharEmpty[] = ""; ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, kStaticConstCharEmpty, arraysize(kStaticConstCharEmpty), @@ -349,7 +370,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharShort) { TaskMemory memory(mach_task_self()); std::string result; - static const char kStaticConstCharShort[] = "A short static const char[]"; + static constexpr char kStaticConstCharShort[] = + "A short static constexpr char[]"; ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, kStaticConstCharShort, arraysize(kStaticConstCharShort), @@ -461,7 +483,7 @@ TEST(TaskMemory, MappedMemoryDeallocates) { TaskMemory memory(mach_task_self()); std::unique_ptr mapped; - static const char kTestBuffer[] = "hello!"; + static constexpr char kTestBuffer[] = "hello!"; mach_vm_address_t test_address = FromPointerCast(&kTestBuffer); ASSERT_TRUE((mapped = memory.ReadMapped(test_address, sizeof(kTestBuffer)))); @@ -498,7 +520,7 @@ TEST(TaskMemory, MappedMemoryReadCString) { TaskMemory memory(mach_task_self()); std::unique_ptr mapped; - static const char kTestBuffer[] = "0\0" "2\0" "45\0" "789"; + static constexpr char kTestBuffer[] = "0\0" "2\0" "45\0" "789"; const mach_vm_address_t kTestAddress = FromPointerCast(&kTestBuffer); ASSERT_TRUE((mapped = memory.ReadMapped(kTestAddress, 10))); diff --git a/util/misc/clock_test.cc b/util/misc/clock_test.cc index d7f9cd71..95330eb2 100644 --- a/util/misc/clock_test.cc +++ b/util/misc/clock_test.cc @@ -71,7 +71,7 @@ void TestSleepNanoseconds(uint64_t nanoseconds) { } TEST(Clock, SleepNanoseconds) { - const uint64_t kTestData[] = { + static constexpr uint64_t kTestData[] = { 0, 1, static_cast(1E3), // 1 microsecond diff --git a/util/misc/implicit_cast.h b/util/misc/implicit_cast.h index 6f8a1a30..018800ab 100644 --- a/util/misc/implicit_cast.h +++ b/util/misc/implicit_cast.h @@ -34,8 +34,8 @@ namespace crashpad { // implicit_cast would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. -template -inline To implicit_cast(From const &f) { +template +constexpr To implicit_cast(From const& f) { return f; } diff --git a/util/misc/scoped_forbid_return_test.cc b/util/misc/scoped_forbid_return_test.cc index 78787d49..4f73ea58 100644 --- a/util/misc/scoped_forbid_return_test.cc +++ b/util/misc/scoped_forbid_return_test.cc @@ -43,7 +43,7 @@ void ScopedForbidReturnHelper(ForbidReturnType type) { } } -const char kForbiddenMessage[] = "attempt to exit scope forbidden"; +constexpr char kForbiddenMessage[] = "attempt to exit scope forbidden"; TEST(ScopedForbidReturnDeathTest, Default) { // kForbiddenMessage may appear to be unused if ASSERT_DEATH_CHECK() throws it diff --git a/util/misc/uuid.cc b/util/misc/uuid.cc index ac2468c6..12c7935a 100644 --- a/util/misc/uuid.cc +++ b/util/misc/uuid.cc @@ -66,7 +66,7 @@ bool UUID::InitializeFromString(const base::StringPiece& string) { return false; UUID temp; - const char kScanFormat[] = + static constexpr char kScanFormat[] = "%08" SCNx32 "-%04" SCNx16 "-%04" SCNx16 "-%02" SCNx8 "%02" SCNx8 "-%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8 "%02" SCNx8; diff --git a/util/misc/uuid_test.cc b/util/misc/uuid_test.cc index e550751b..72b8216b 100644 --- a/util/misc/uuid_test.cc +++ b/util/misc/uuid_test.cc @@ -45,22 +45,22 @@ TEST(UUID, UUID) { EXPECT_EQ(uuid_zero.data_5[5], 0u); EXPECT_EQ(uuid_zero.ToString(), "00000000-0000-0000-0000-000000000000"); - const uint8_t kBytes[16] = {0x00, - 0x01, - 0x02, - 0x03, - 0x04, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0a, - 0x0b, - 0x0c, - 0x0d, - 0x0e, - 0x0f}; + static constexpr uint8_t kBytes[16] = {0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0a, + 0x0b, + 0x0c, + 0x0d, + 0x0e, + 0x0f}; UUID uuid; uuid.InitializeFromBytes(kBytes); EXPECT_EQ(uuid.data_1, 0x00010203u); @@ -110,22 +110,22 @@ TEST(UUID, UUID) { // have been valid. EXPECT_EQ(uuid_2, uuid); - const uint8_t kMoreBytes[16] = {0xff, - 0xee, - 0xdd, - 0xcc, - 0xbb, - 0xaa, - 0x99, - 0x88, - 0x77, - 0x66, - 0x55, - 0x44, - 0x33, - 0x22, - 0x11, - 0x00}; + static constexpr uint8_t kMoreBytes[16] = {0xff, + 0xee, + 0xdd, + 0xcc, + 0xbb, + 0xaa, + 0x99, + 0x88, + 0x77, + 0x66, + 0x55, + 0x44, + 0x33, + 0x22, + 0x11, + 0x00}; uuid.InitializeFromBytes(kMoreBytes); EXPECT_EQ(uuid.data_1, 0xffeeddccu); EXPECT_EQ(uuid.data_2, 0xbbaau); @@ -164,7 +164,7 @@ TEST(UUID, UUID) { } TEST(UUID, FromString) { - const struct TestCase { + static constexpr struct TestCase { const char* uuid_string; bool success; } kCases[] = { diff --git a/util/net/http_multipart_builder.cc b/util/net/http_multipart_builder.cc index 91105be9..cd88e430 100644 --- a/util/net/http_multipart_builder.cc +++ b/util/net/http_multipart_builder.cc @@ -29,9 +29,9 @@ namespace crashpad { namespace { -const char kCRLF[] = "\r\n"; +constexpr char kCRLF[] = "\r\n"; -const char kBoundaryCRLF[] = "\r\n\r\n"; +constexpr char kBoundaryCRLF[] = "\r\n\r\n"; // Generates a random string suitable for use as a multipart boundary. std::string GenerateBoundaryString() { @@ -47,7 +47,7 @@ std::string GenerateBoundaryString() { // randomness (62^32 > 2^190). std::string boundary_string = "---MultipartBoundary-"; for (int index = 0; index < 32; ++index) { - const char kCharacters[] = + static constexpr char kCharacters[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; int random_value = base::RandInt(0, static_cast(strlen(kCharacters)) - 1); diff --git a/util/net/http_multipart_builder_test.cc b/util/net/http_multipart_builder_test.cc index 79366bc2..71b2fa84 100644 --- a/util/net/http_multipart_builder_test.cc +++ b/util/net/http_multipart_builder_test.cc @@ -55,16 +55,16 @@ std::vector SplitCRLF(const std::string& string) { TEST(HTTPMultipartBuilder, ThreeStringFields) { HTTPMultipartBuilder builder; - const char kKey1[] = "key1"; - const char kValue1[] = "test"; + static constexpr char kKey1[] = "key1"; + static constexpr char kValue1[] = "test"; builder.SetFormData(kKey1, kValue1); - const char kKey2[] = "key2"; - const char kValue2[] = "This is another test."; + static constexpr char kKey2[] = "key2"; + static constexpr char kValue2[] = "This is another test."; builder.SetFormData(kKey2, kValue2); - const char kKey3[] = "key-three"; - const char kValue3[] = "More tests"; + static constexpr char kKey3[] = "key-three"; + static constexpr char kValue3[] = "More tests"; builder.SetFormData(kKey3, kValue3); std::unique_ptr body(builder.GetBodyStream()); @@ -115,7 +115,7 @@ TEST(HTTPMultipartBuilder, ThreeFileAttachments) { ascii_http_body_path, "text/plain"); - const char kFileContents[] = "This is a test.\n"; + static constexpr char kFileContents[] = "This is a test.\n"; std::unique_ptr body(builder.GetBodyStream()); ASSERT_TRUE(body.get()); @@ -158,7 +158,7 @@ TEST(HTTPMultipartBuilder, ThreeFileAttachments) { TEST(HTTPMultipartBuilder, OverwriteFormDataWithEscapedKey) { HTTPMultipartBuilder builder; - const char kKey[] = "a 100% \"silly\"\r\ntest"; + static constexpr char kKey[] = "a 100% \"silly\"\r\ntest"; builder.SetFormData(kKey, "some dummy value"); builder.SetFormData(kKey, "overwrite"); std::unique_ptr body(builder.GetBodyStream()); @@ -183,7 +183,7 @@ TEST(HTTPMultipartBuilder, OverwriteFormDataWithEscapedKey) { TEST(HTTPMultipartBuilder, OverwriteFileAttachment) { HTTPMultipartBuilder builder; - const char kValue[] = "1 2 3 test"; + static constexpr char kValue[] = "1 2 3 test"; builder.SetFormData("a key", kValue); base::FilePath testdata_path = TestPaths::TestDataRoot().Append(FILE_PATH_LITERAL("util/net/testdata")); @@ -240,7 +240,7 @@ TEST(HTTPMultipartBuilder, OverwriteFileAttachment) { TEST(HTTPMultipartBuilder, SharedFormDataAndAttachmentKeyNamespace) { HTTPMultipartBuilder builder; - const char kValue1[] = "11111"; + static constexpr char kValue1[] = "11111"; builder.SetFormData("one", kValue1); base::FilePath ascii_http_body_path = TestPaths::TestDataRoot().Append( FILE_PATH_LITERAL("util/net/testdata/ascii_http_body.txt")); @@ -248,7 +248,7 @@ TEST(HTTPMultipartBuilder, SharedFormDataAndAttachmentKeyNamespace) { "minidump.dmp", ascii_http_body_path, ""); - const char kValue2[] = "this is not a file"; + static constexpr char kValue2[] = "this is not a file"; builder.SetFormData("minidump", kValue2); std::unique_ptr body(builder.GetBodyStream()); diff --git a/util/net/http_transport_libcurl.cc b/util/net/http_transport_libcurl.cc index 1a20913a..70da696d 100644 --- a/util/net/http_transport_libcurl.cc +++ b/util/net/http_transport_libcurl.cc @@ -57,31 +57,31 @@ std::string UserAgent() { // linux-4.9.17/arch/x86/kernel/cpu/bugs.c check_bugs() sets the first digit // to 4, 5, or 6, but no higher. #if defined(__i686__) - const char arch[] = "i686"; + static constexpr char arch[] = "i686"; #elif defined(__i586__) - const char arch[] = "i586"; + static constexpr char arch[] = "i586"; #elif defined(__i486__) - const char arch[] = "i486"; + static constexpr char arch[] = "i486"; #else - const char arch[] = "i386"; + static constexpr char arch[] = "i386"; #endif #elif defined(ARCH_CPU_X86_64) - const char arch[] = "x86_64"; + static constexpr char arch[] = "x86_64"; #elif defined(ARCH_CPU_ARMEL) // linux-4.9.17/arch/arm/kernel/setup.c setup_processor() bases the string // on the ARM processor name and a character identifying little- or // big-endian. The processor name comes from a definition in // arch/arm/mm/proc-*.S. #if defined(__ARM_ARCH_4T__) - const char arch[] = "armv4t" + static constexpr char arch[] = "armv4t" #elif defined(__ARM_ARCH_5TEJ__) - const char arch[] = "armv5tej" + static constexpr char arch[] = "armv5tej" #elif defined(__ARM_ARCH_5TE__) - const char arch[] = "armv5te" + static constexpr char arch[] = "armv5te" #elif defined(__ARM_ARCH_5T__) - const char arch[] = "armv5t" + static constexpr char arch[] = "armv5t" #elif defined(__ARM_ARCH_7M__) - const char arch[] = "armv7m" + static constexpr char arch[] = "armv7m" #else // Most ARM architectures fall into here, including all profile variants of // armv6, armv7, armv8, with one exception, armv7m, handled above. @@ -89,7 +89,7 @@ std::string UserAgent() { // or 8. #define xstr(s) str(s) #define str(s) #s - const char arch[] = "armv" xstr(__ARM_ARCH) + static constexpr char arch[] = "armv" xstr(__ARM_ARCH) #undef str #undef xstr #endif @@ -102,14 +102,14 @@ std::string UserAgent() { // ARM64 uses aarch64 or aarch64_be as directed by ELF_PLATFORM. See // linux-4.9.17/arch/arm64/kernel/setup.c setup_arch(). #if defined(ARCH_CPU_LITTLE_ENDIAN) - const char arch[] = "aarch64"; + static constexpr char arch[] = "aarch64"; #elif defined(ARCH_CPU_BIG_ENDIAN) - const char arch[] = "aarch64_be"; + static constexpr char arch[] = "aarch64_be"; #endif #elif defined(ARCH_CPU_MIPSEL) - const char arch[] = "mips"; + static constexpr char arch[] = "mips"; #elif defined(ARCH_CPU_MIPS64EL) - const char arch[] = "mips64"; + static constexpr char arch[] = "mips64"; #else #error Port #endif diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index 70c3eee4..3b7e7ebd 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -136,7 +136,7 @@ class HTTPTransportTestFixture : public MultiprocessExec { RequestValidator request_validator_; }; -const char kMultipartFormData[] = "multipart/form-data"; +constexpr char kMultipartFormData[] = "multipart/form-data"; void GetHeaderField(const std::string& request, const std::string& header, @@ -179,7 +179,7 @@ void GetMultipartBoundary(const std::string& request, } } -const char kBoundaryEq[] = "boundary="; +constexpr char kBoundaryEq[] = "boundary="; void ValidFormData(HTTPTransportTestFixture* fixture, const std::string& request) { @@ -242,7 +242,7 @@ TEST(HTTPTransport, ValidFormData_Gzip) { test.Run(); } -const char kTextPlain[] = "text/plain"; +constexpr char kTextPlain[] = "text/plain"; void ErrorResponse(HTTPTransportTestFixture* fixture, const std::string& request) { @@ -260,7 +260,7 @@ TEST(HTTPTransport, ErrorResponse) { test.Run(); } -const char kTextBody[] = "hello world"; +constexpr char kTextBody[] = "hello world"; void UnchunkedPlainText(HTTPTransportTestFixture* fixture, const std::string& request) { diff --git a/util/net/http_transport_win.cc b/util/net/http_transport_win.cc index 56fdaad1..ecbe8ea2 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -242,7 +242,8 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) { DWORD content_length_dword; if (chunked) { - const wchar_t kTransferEncodingHeader[] = L"Transfer-Encoding: chunked\r\n"; + static constexpr wchar_t kTransferEncodingHeader[] = + L"Transfer-Encoding: chunked\r\n"; if (!WinHttpAddRequestHeaders( request.get(), kTransferEncodingHeader, diff --git a/util/numeric/checked_address_range_test.cc b/util/numeric/checked_address_range_test.cc index fa7ae87d..e6bd9ecd 100644 --- a/util/numeric/checked_address_range_test.cc +++ b/util/numeric/checked_address_range_test.cc @@ -46,7 +46,7 @@ bool ExpectationForValidity64(Validity validity) { } TEST(CheckedAddressRange, IsValid) { - const struct TestData { + static constexpr struct { uint64_t base; uint64_t size; Validity validity; @@ -120,7 +120,7 @@ TEST(CheckedAddressRange, IsValid) { }; for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%" PRIx64 ", size 0x%" PRIx64, index, @@ -136,7 +136,7 @@ TEST(CheckedAddressRange, IsValid) { } TEST(CheckedAddressRange, ContainsValue) { - const struct TestData { + static constexpr struct { uint64_t value; bool expectation; } kTestData[] = { @@ -171,7 +171,7 @@ TEST(CheckedAddressRange, ContainsValue) { ASSERT_TRUE(parent_range_32.IsValid()); for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", value 0x%" PRIx64, index, testcase.value)); @@ -189,7 +189,7 @@ TEST(CheckedAddressRange, ContainsValue) { } TEST(CheckedAddressRange, ContainsRange) { - const struct TestData { + static constexpr struct { uint64_t base; uint64_t size; bool expectation; @@ -228,7 +228,7 @@ TEST(CheckedAddressRange, ContainsRange) { ASSERT_TRUE(parent_range_32.IsValid()); for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%" PRIx64 ", size 0x%" PRIx64, index, diff --git a/util/numeric/checked_range_test.cc b/util/numeric/checked_range_test.cc index 404b9898..04f6bb1f 100644 --- a/util/numeric/checked_range_test.cc +++ b/util/numeric/checked_range_test.cc @@ -29,7 +29,7 @@ namespace test { namespace { TEST(CheckedRange, IsValid) { - const struct UnsignedTestData { + static constexpr struct { uint32_t base; uint32_t size; bool valid; @@ -79,7 +79,7 @@ TEST(CheckedRange, IsValid) { }; for (size_t index = 0; index < arraysize(kUnsignedTestData); ++index) { - const UnsignedTestData& testcase = kUnsignedTestData[index]; + const auto& testcase = kUnsignedTestData[index]; SCOPED_TRACE(base::StringPrintf("unsigned index %" PRIuS ", base 0x%x, size 0x%x", index, @@ -91,7 +91,7 @@ TEST(CheckedRange, IsValid) { } const int32_t kMinInt32 = std::numeric_limits::min(); - const struct SignedTestData { + static constexpr struct { int32_t base; uint32_t size; bool valid; @@ -141,7 +141,7 @@ TEST(CheckedRange, IsValid) { }; for (size_t index = 0; index < arraysize(kSignedTestData); ++index) { - const SignedTestData& testcase = kSignedTestData[index]; + const auto& testcase = kSignedTestData[index]; SCOPED_TRACE(base::StringPrintf("signed index %" PRIuS ", base 0x%x, size 0x%x", index, @@ -154,7 +154,7 @@ TEST(CheckedRange, IsValid) { } TEST(CheckedRange, ContainsValue) { - const struct TestData { + static constexpr struct { uint32_t value; bool contains; } kTestData[] = { @@ -187,7 +187,7 @@ TEST(CheckedRange, ContainsValue) { ASSERT_TRUE(parent_range.IsValid()); for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", value 0x%x", index, testcase.value)); @@ -196,7 +196,7 @@ TEST(CheckedRange, ContainsValue) { } TEST(CheckedRange, ContainsRange) { - const struct TestData { + static constexpr struct { uint32_t base; uint32_t size; bool contains; @@ -235,7 +235,7 @@ TEST(CheckedRange, ContainsRange) { ASSERT_TRUE(parent_range.IsValid()); for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%x, size 0x%x", index, testcase.base, @@ -248,7 +248,7 @@ TEST(CheckedRange, ContainsRange) { } TEST(CheckedRange, OverlapsRange) { - const struct TestData { + static constexpr struct { uint32_t base; uint32_t size; bool overlaps; @@ -288,7 +288,7 @@ TEST(CheckedRange, OverlapsRange) { ASSERT_TRUE(first_range.IsValid()); for (size_t index = 0; index < arraysize(kTestData); ++index) { - const TestData& testcase = kTestData[index]; + const auto& testcase = kTestData[index]; SCOPED_TRACE(base::StringPrintf("index %" PRIuS ", base 0x%x, size 0x%x", index, testcase.base, diff --git a/util/numeric/int128_test.cc b/util/numeric/int128_test.cc index e0b45999..83b4f6e8 100644 --- a/util/numeric/int128_test.cc +++ b/util/numeric/int128_test.cc @@ -23,10 +23,10 @@ namespace { TEST(Int128, UInt128) { #if defined(ARCH_CPU_LITTLE_ENDIAN) - const uint8_t kBytes[] = + static constexpr uint8_t kBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; #else - const uint8_t kBytes[] = + static constexpr uint8_t kBytes[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; #endif diff --git a/util/posix/close_multiple.cc b/util/posix/close_multiple.cc index 908febf3..6e31eb9c 100644 --- a/util/posix/close_multiple.cc +++ b/util/posix/close_multiple.cc @@ -75,9 +75,9 @@ void CloseNowOrOnExec(int fd, bool ebadf_ok) { // no attempt needs to be made to close file descriptors that are not open. bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) { #if defined(OS_MACOSX) - const char kFDDir[] = "/dev/fd"; + static constexpr char kFDDir[] = "/dev/fd"; #elif defined(OS_LINUX) || defined(OS_ANDROID) - const char kFDDir[] = "/proc/self/fd"; + static constexpr char kFDDir[] = "/proc/self/fd"; #endif DIR* dir = opendir(kFDDir); @@ -99,10 +99,10 @@ bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) { // 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"; + static constexpr char kReaddirName[] = "readdir"; while ((errno = 0, result = readdir(dir)) != nullptr) #else - const char kReaddirName[] = "readdir_r"; + static constexpr char kReaddirName[] = "readdir_r"; dirent entry; while ((errno = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) #endif diff --git a/util/posix/symbolic_constants_posix.cc b/util/posix/symbolic_constants_posix.cc index 4ea2300b..51cc583b 100644 --- a/util/posix/symbolic_constants_posix.cc +++ b/util/posix/symbolic_constants_posix.cc @@ -26,7 +26,7 @@ namespace { -const char* kSignalNames[] = { +constexpr const char* kSignalNames[] = { nullptr, #if defined(OS_MACOSX) @@ -108,7 +108,7 @@ static_assert(arraysize(kSignalNames) == 32, "kSignalNames length"); static_assert(arraysize(kSignalNames) == NSIG, "kSignalNames length"); #endif -const char kSigPrefix[] = "SIG"; +constexpr char kSigPrefix[] = "SIG"; } // namespace diff --git a/util/posix/symbolic_constants_posix_test.cc b/util/posix/symbolic_constants_posix_test.cc index 9cb29b58..4084c2c3 100644 --- a/util/posix/symbolic_constants_posix_test.cc +++ b/util/posix/symbolic_constants_posix_test.cc @@ -29,7 +29,7 @@ namespace crashpad { namespace test { namespace { -const struct { +constexpr struct { int signal; const char* full_name; const char* short_name; @@ -157,7 +157,7 @@ void TestStringToSignal(const base::StringPiece& string, } TEST(SymbolicConstantsPOSIX, StringToSignal) { - const StringToSymbolicConstantOptions kOptions[] = { + static constexpr StringToSymbolicConstantOptions kOptions[] = { 0, kAllowFullName, kAllowShortName, @@ -198,7 +198,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { } } - const char* const kNegativeTestData[] = { + static constexpr const char* kNegativeTestData[] = { "SIGHUP ", " SIGINT", "QUIT ", @@ -216,7 +216,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { TestStringToSignal(kNegativeTestData[index], options, false, 0); } - const struct { + static constexpr struct { const char* string; size_t length; } kNULTestData[] = { diff --git a/util/stdlib/string_number_conversion_test.cc b/util/stdlib/string_number_conversion_test.cc index f6634d0f..dd17c00d 100644 --- a/util/stdlib/string_number_conversion_test.cc +++ b/util/stdlib/string_number_conversion_test.cc @@ -26,7 +26,7 @@ namespace test { namespace { TEST(StringNumberConversion, StringToInt) { - const struct { + static constexpr struct { const char* string; bool valid; int value; @@ -113,7 +113,7 @@ TEST(StringNumberConversion, StringToInt) { // Ensure that embedded NUL characters are treated as bad input. The string // is split to avoid MSVC warning: // "decimal digit terminates octal escape sequence". - const char input[] = "6\000" "6"; + static constexpr char input[] = "6\000" "6"; base::StringPiece input_string(input, arraysize(input) - 1); int output; EXPECT_FALSE(StringToNumber(input_string, &output)); @@ -124,7 +124,7 @@ TEST(StringNumberConversion, StringToInt) { } TEST(StringNumberConversion, StringToUnsignedInt) { - const struct { + static constexpr struct { const char* string; bool valid; unsigned int value; @@ -211,7 +211,7 @@ TEST(StringNumberConversion, StringToUnsignedInt) { // Ensure that embedded NUL characters are treated as bad input. The string // is split to avoid MSVC warning: // "decimal digit terminates octal escape sequence". - const char input[] = "6\000" "6"; + static constexpr char input[] = "6\000" "6"; base::StringPiece input_string(input, arraysize(input) - 1); unsigned int output; EXPECT_FALSE(StringToNumber(input_string, &output)); @@ -222,7 +222,7 @@ TEST(StringNumberConversion, StringToUnsignedInt) { } TEST(StringNumberConversion, StringToInt64) { - const struct { + static constexpr struct { const char* string; bool valid; int64_t value; @@ -271,7 +271,7 @@ TEST(StringNumberConversion, StringToInt64) { } TEST(StringNumberConversion, StringToUnsignedInt64) { - const struct { + static constexpr struct { const char* string; bool valid; uint64_t value; diff --git a/util/stdlib/strlcpy_test.cc b/util/stdlib/strlcpy_test.cc index 57315c3b..5185840f 100644 --- a/util/stdlib/strlcpy_test.cc +++ b/util/stdlib/strlcpy_test.cc @@ -41,7 +41,8 @@ TEST(strlcpy, c16lcpy) { // Test with M, é, Ā, ő, and Ḙ. This is a mix of characters that have zero and // nonzero low and high bytes. - const base::char16 test_characters[] = {0x4d, 0xe9, 0x100, 0x151, 0x1e18}; + static constexpr base::char16 test_characters[] = + {0x4d, 0xe9, 0x100, 0x151, 0x1e18}; for (size_t index = 0; index < arraysize(test_characters); ++index) { base::char16 test_character = test_characters[index]; diff --git a/util/stdlib/strnlen_test.cc b/util/stdlib/strnlen_test.cc index e030fdc8..1913e208 100644 --- a/util/stdlib/strnlen_test.cc +++ b/util/stdlib/strnlen_test.cc @@ -23,7 +23,7 @@ namespace test { namespace { TEST(strnlen, strnlen) { - const char kTestBuffer[] = "abc\0d"; + static constexpr char kTestBuffer[] = "abc\0d"; ASSERT_EQ(strlen(kTestBuffer), 3u); EXPECT_EQ(crashpad::strnlen(kTestBuffer, 0), 0u); EXPECT_EQ(crashpad::strnlen(kTestBuffer, 1), 1u); @@ -33,7 +33,7 @@ TEST(strnlen, strnlen) { EXPECT_EQ(crashpad::strnlen(kTestBuffer, 5), 3u); EXPECT_EQ(crashpad::strnlen(kTestBuffer, 6), 3u); - const char kEmptyBuffer[] = "\0"; + static constexpr char kEmptyBuffer[] = "\0"; ASSERT_EQ(strlen(kEmptyBuffer), 0u); EXPECT_EQ(crashpad::strnlen(kEmptyBuffer, 0), 0u); EXPECT_EQ(crashpad::strnlen(kEmptyBuffer, 1), 0u); diff --git a/util/thread/thread_log_messages_test.cc b/util/thread/thread_log_messages_test.cc index 65c0b854..f906ff15 100644 --- a/util/thread/thread_log_messages_test.cc +++ b/util/thread/thread_log_messages_test.cc @@ -50,7 +50,7 @@ std::string MessageString(const std::string& log_message) { return std::string(); } - const char kFindString[] = "] "; + static constexpr char kFindString[] = "] "; size_t pos = log_message.find(kFindString); if (pos == std::string::npos) { EXPECT_NE(pos, std::string::npos); @@ -78,7 +78,7 @@ TEST(ThreadLogMessages, Basic) { ASSERT_TRUE(LOG_IS_ON(INFO)); { - const char* const kMessages[] = { + static constexpr const char* kMessages[] = { "An info message", "A warning message", "An error message", @@ -101,7 +101,7 @@ TEST(ThreadLogMessages, Basic) { } { - const char kMessage[] = "Sample error message"; + static constexpr char kMessage[] = "Sample error message"; ThreadLogMessages thread_log_messages; diff --git a/util/win/command_line_test.cc b/util/win/command_line_test.cc index 95849b63..1eb15b88 100644 --- a/util/win/command_line_test.cc +++ b/util/win/command_line_test.cc @@ -60,10 +60,10 @@ TEST(CommandLine, AppendCommandLineArgument) { { SCOPED_TRACE("simple"); - const wchar_t* const kArguments[] = { - L"child.exe", - L"argument 1", - L"argument 2", + static constexpr wchar_t* const kArguments[] = { + L"child.exe", + L"argument 1", + L"argument 2", }; AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); } @@ -71,11 +71,11 @@ TEST(CommandLine, AppendCommandLineArgument) { { SCOPED_TRACE("path with spaces"); - const wchar_t* const kArguments[] = { - L"child.exe", - L"argument1", - L"argument 2", - L"\\some\\path with\\spaces", + static constexpr wchar_t* const kArguments[] = { + L"child.exe", + L"argument1", + L"argument 2", + L"\\some\\path with\\spaces", }; AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); } @@ -83,11 +83,11 @@ TEST(CommandLine, AppendCommandLineArgument) { { SCOPED_TRACE("argument with embedded quotation marks"); - const wchar_t* const kArguments[] = { - L"child.exe", - L"argument1", - L"she said, \"you had me at hello\"", - L"\\some\\path with\\spaces", + static constexpr wchar_t* const kArguments[] = { + L"child.exe", + L"argument1", + L"she said, \"you had me at hello\"", + L"\\some\\path with\\spaces", }; AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); } @@ -95,12 +95,12 @@ TEST(CommandLine, AppendCommandLineArgument) { { SCOPED_TRACE("argument with unbalanced quotation marks"); - const wchar_t* const kArguments[] = { - L"child.exe", - L"argument1", - L"argument\"2", - L"argument3", - L"argument4", + static constexpr wchar_t* const kArguments[] = { + L"child.exe", + L"argument1", + L"argument\"2", + L"argument3", + L"argument4", }; AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); } @@ -108,10 +108,10 @@ TEST(CommandLine, AppendCommandLineArgument) { { SCOPED_TRACE("argument ending with backslash"); - const wchar_t* const kArguments[] = { - L"child.exe", - L"\\some\\directory with\\spaces\\", - L"argument2", + static constexpr wchar_t* const kArguments[] = { + L"child.exe", + L"\\some\\directory with\\spaces\\", + L"argument2", }; AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); } @@ -119,10 +119,10 @@ TEST(CommandLine, AppendCommandLineArgument) { { SCOPED_TRACE("empty argument"); - const wchar_t* const kArguments[] = { - L"child.exe", - L"", - L"argument2", + static constexpr wchar_t* const kArguments[] = { + L"child.exe", + L"", + L"argument2", }; AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); } @@ -130,34 +130,34 @@ TEST(CommandLine, AppendCommandLineArgument) { { SCOPED_TRACE("funny nonprintable characters"); - const wchar_t* const kArguments[] = { - L"child.exe", - L"argument 1", - L"argument\t2", - L"argument\n3", - L"argument\v4", - L"argument\"5", - L" ", - L"\t", - L"\n", - L"\v", - L"\"", - L" x", - L"\tx", - L"\nx", - L"\vx", - L"\"x", - L"x ", - L"x\t", - L"x\n", - L"x\v", - L"x\"", - L" ", - L"\t\t", - L"\n\n", - L"\v\v", - L"\"\"", - L" \t\n\v\"", + static constexpr wchar_t* const kArguments[] = { + L"child.exe", + L"argument 1", + L"argument\t2", + L"argument\n3", + L"argument\v4", + L"argument\"5", + L" ", + L"\t", + L"\n", + L"\v", + L"\"", + L" x", + L"\tx", + L"\nx", + L"\vx", + L"\"x", + L"x ", + L"x\t", + L"x\n", + L"x\v", + L"x\"", + L" ", + L"\t\t", + L"\n\n", + L"\v\v", + L"\"\"", + L" \t\n\v\"", }; AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); } diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc index 50f932c8..d715350f 100644 --- a/util/win/process_info_test.cc +++ b/util/win/process_info_test.cc @@ -42,7 +42,7 @@ namespace crashpad { namespace test { namespace { -const wchar_t kNtdllName[] = L"\\ntdll.dll"; +constexpr wchar_t kNtdllName[] = L"\\ntdll.dll"; bool IsProcessWow64(HANDLE process_handle) { static const auto is_wow64_process = @@ -101,7 +101,7 @@ TEST(ProcessInfo, Self) { std::vector modules; EXPECT_TRUE(process_info.Modules(&modules)); ASSERT_GE(modules.size(), 2u); - const wchar_t kSelfName[] = L"\\crashpad_util_test.exe"; + static constexpr wchar_t kSelfName[] = L"\\crashpad_util_test.exe"; ASSERT_GE(modules[0].name.size(), wcslen(kSelfName)); EXPECT_EQ(modules[0].name.substr(modules[0].name.size() - wcslen(kSelfName)), kSelfName); @@ -178,7 +178,7 @@ void TestOtherProcess(const base::string16& directory_modification) { kNtdllName); // lz32.dll is an uncommonly-used-but-always-available module that the test // binary manually loads. - const wchar_t kLz32dllName[] = L"\\lz32.dll"; + static constexpr wchar_t kLz32dllName[] = L"\\lz32.dll"; ASSERT_GE(modules.back().name.size(), wcslen(kLz32dllName)); EXPECT_EQ(modules.back().name.substr(modules.back().name.size() - wcslen(kLz32dllName)), diff --git a/util/win/registration_protocol_win.cc b/util/win/registration_protocol_win.cc index 87c45748..dc31e7d4 100644 --- a/util/win/registration_protocol_win.cc +++ b/util/win/registration_protocol_win.cc @@ -136,7 +136,7 @@ const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { // would in turn cause deadlock. #pragma pack(push, 1) - static const struct SecurityDescriptorBlob { + static constexpr struct SecurityDescriptorBlob { // See https://msdn.microsoft.com/en-us/library/cc230366.aspx. SECURITY_DESCRIPTOR_RELATIVE sd_rel; struct { diff --git a/util/win/registration_protocol_win_test.cc b/util/win/registration_protocol_win_test.cc index 10a5bb63..6601b4e7 100644 --- a/util/win/registration_protocol_win_test.cc +++ b/util/win/registration_protocol_win_test.cc @@ -33,7 +33,7 @@ TEST(SecurityDescriptor, MatchesAdvapi32) { // Mandatory Label, no ACE flags, no ObjectType, integrity level // untrusted. - const wchar_t kSddl[] = L"S:(ML;;;;;S-1-16-0)"; + static constexpr wchar_t kSddl[] = L"S:(ML;;;;;S-1-16-0)"; PSECURITY_DESCRIPTOR sec_desc; ULONG sec_desc_len; ASSERT_TRUE(ConvertStringSecurityDescriptorToSecurityDescriptor( diff --git a/util/win/safe_terminate_process_test.cc b/util/win/safe_terminate_process_test.cc index 2fbc8483..d176002e 100644 --- a/util/win/safe_terminate_process_test.cc +++ b/util/win/safe_terminate_process_test.cc @@ -134,7 +134,7 @@ TEST(SafeTerminateProcess, PatchBadly) { // https://crashpad.chromium.org/bug/179. In reality, this only affects // 32-bit x86, as there’s no calling convention confusion on x86_64. It // doesn’t hurt to run this test in the 64-bit environment, though. - const uint8_t patch[] = { + static constexpr uint8_t patch[] = { #if defined(ARCH_CPU_X86) 0x31, 0xc0, // xor eax, eax #elif defined(ARCH_CPU_X86_64) From 7e6a0145b17baae9d468517fe2711e22647c7ef9 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 26 Jul 2017 10:57:56 -0400 Subject: [PATCH 24/30] mac handler: Record the number of open files in the handler process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "file-limit" annotation has shown that the system as a whole is not likely to be out of file descriptors globally. It’s possible that a file descriptor leak in crashpad_handler itself is responsible for certain crashes. Add a count of the number of open files in the handler process to this annotation to test this theory. Bug: crashpad:180 Change-Id: If6f2304fdabddd29636ba4ac5a7d1e0fff7f4b61 Reviewed-on: https://chromium-review.googlesource.com/585852 Reviewed-by: Robert Sesek --- handler/mac/file_limit_annotation.cc | 48 +++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/handler/mac/file_limit_annotation.cc b/handler/mac/file_limit_annotation.cc index 359ed8e0..bdd8fb1e 100644 --- a/handler/mac/file_limit_annotation.cc +++ b/handler/mac/file_limit_annotation.cc @@ -14,7 +14,9 @@ #include "handler/mac/file_limit_annotation.h" +#include #include +#include #include #include #include @@ -26,6 +28,9 @@ #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" #include "client/simple_string_dictionary.h" +#include "util/posix/scoped_dir.h" + +namespace crashpad { namespace { @@ -44,6 +49,38 @@ std::string FormatFromSysctl(int rv, const int* value, const size_t* size) { return base::StringPrintf("%d", *value); } +// Counts the number of open file descriptors in the process and returns it as a +// string. This /dev/fd and the value returned will include the open file +// descriptor for that directory. If opendir() fails, the returned string will +// be "E" followed by the error number. If readdir_r() fails, it will be "R" +// followed by the error number. +std::string CountOpenFileDescriptors() { + DIR* dir = opendir("/dev/fd"); + if (!dir) { + return base::StringPrintf("E%d", errno); + } + + ScopedDIR dir_owner(dir); + + dirent entry; + dirent* result; + int count = 0; + while ((errno = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) { + const char* entry_name = &(*result->d_name); + if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) { + continue; + } + + ++count; + } + + if (errno != 0) { + return base::StringPrintf("R%d", errno); + } + + return base::StringPrintf("%d", count); +} + // Returns a string for |limit|, or "inf" if |limit| is RLIM_INFINITY. std::string StringForRLim(rlim_t limit) { if (limit == RLIM_INFINITY) { @@ -55,8 +92,6 @@ std::string StringForRLim(rlim_t limit) { } // namespace -namespace crashpad { - void RecordFileLimitAnnotation() { CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo(); SimpleStringDictionary* simple_annotations = @@ -76,6 +111,8 @@ void RecordFileLimitAnnotation() { std::string max_files = FormatFromSysctl( sysctl(mib, arraysize(mib), &value, &size, nullptr, 0), &value, &size); + std::string open_files = CountOpenFileDescriptors(); + rlimit limit; std::string nofile; if (getrlimit(RLIMIT_NOFILE, &limit) != 0) { @@ -85,8 +122,11 @@ void RecordFileLimitAnnotation() { StringForRLim(limit.rlim_cur) + "," + StringForRLim(limit.rlim_max); } - std::string annotation = base::StringPrintf( - "%s,%s,%s", num_files.c_str(), max_files.c_str(), nofile.c_str()); + std::string annotation = base::StringPrintf("%s,%s,%s,%s", + num_files.c_str(), + max_files.c_str(), + open_files.c_str(), + nofile.c_str()); simple_annotations->SetKeyValue("file-limits", annotation.c_str()); } From 6dac7ecdf58e90aec482d0f4fbffb814982a2857 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 25 Jul 2017 19:15:48 -0400 Subject: [PATCH 25/30] Use constexpr at function scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is essentially based on a search for “^ *const [^*&]*=[^(]*$” Change-Id: Id571119d0b9a64c6f387eccd51cea7c9eb530e13 Reviewed-on: https://chromium-review.googlesource.com/585555 Reviewed-by: Leonard Mosescu --- client/crashpad_client_mac.cc | 4 +- client/crashpad_client_win.cc | 11 +- client/simple_string_dictionary_test.cc | 4 +- handler/crash_report_upload_thread.cc | 4 +- handler/handler_main.cc | 2 +- handler/win/crashy_test_program.cc | 6 +- minidump/minidump_context_writer_test.cc | 8 +- .../minidump_crashpad_info_writer_test.cc | 2 +- minidump/minidump_exception_writer.cc | 2 +- minidump/minidump_exception_writer_test.cc | 32 ++--- minidump/minidump_file_writer_test.cc | 127 ++++++++++-------- minidump/minidump_handle_writer_test.cc | 6 +- minidump/minidump_memory_info_writer_test.cc | 6 +- minidump/minidump_memory_writer_test.cc | 32 ++--- minidump/minidump_misc_info_writer.cc | 4 +- minidump/minidump_misc_info_writer_test.cc | 94 ++++++------- ...nidump_module_crashpad_info_writer_test.cc | 8 +- minidump/minidump_module_writer_test.cc | 68 +++++----- minidump/minidump_rva_list_writer_test.cc | 2 +- minidump/minidump_system_info_writer_test.cc | 72 +++++----- minidump/minidump_thread_writer_test.cc | 88 ++++++------ .../minidump_unloaded_module_writer_test.cc | 14 +- minidump/minidump_user_stream_writer_test.cc | 10 +- .../test/minidump_memory_writer_test_util.cc | 2 +- snapshot/capture_memory.cc | 6 +- snapshot/linux/process_reader.cc | 2 +- .../mac/mach_o_image_annotations_reader.cc | 2 +- snapshot/mac/process_reader.cc | 6 +- snapshot/mac/process_reader_test.cc | 6 +- snapshot/win/exception_snapshot_win_test.cc | 4 +- snapshot/win/process_snapshot_win.cc | 2 +- snapshot/win/system_snapshot_win.cc | 2 +- util/file/file_io_test.cc | 2 +- util/linux/memory_map.cc | 4 +- util/linux/thread_info_test.cc | 4 +- util/mach/child_port_handshake.cc | 4 +- .../composite_mach_message_server_test.cc | 20 +-- util/mach/exc_server_variants.cc | 2 +- util/mach/exc_server_variants_test.cc | 14 +- util/mach/exception_ports.cc | 2 +- util/mach/exception_ports_test.cc | 4 +- util/mach/mach_extensions.cc | 7 +- util/mach/mach_message.cc | 3 +- util/mach/mach_message_server_test.cc | 10 +- util/mach/task_memory_test.cc | 12 +- util/misc/clock_win.cc | 2 +- util/net/http_body_gzip.cc | 4 +- util/net/http_body_gzip_test.cc | 2 +- util/net/http_transport_libcurl.cc | 2 +- util/net/http_transport_mac.mm | 32 ++--- util/posix/process_info_linux.cc | 4 +- util/posix/signals.cc | 2 +- util/posix/symbolic_constants_posix_test.cc | 4 +- util/synchronization/semaphore_test.cc | 8 +- util/thread/thread_log_messages_test.cc | 4 +- util/win/capture_context_test.cc | 12 +- util/win/process_info.cc | 2 +- util/win/process_info_test.cc | 4 +- util/win/time.cc | 2 +- 59 files changed, 416 insertions(+), 394 deletions(-) diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index 978024e5..a9e4aca4 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -284,8 +284,8 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { if (restart) { // If the handler was ever started before, don’t restart it too quickly. - const uint64_t kNanosecondsPerSecond = 1E9; - const uint64_t kMinimumStartInterval = 1 * kNanosecondsPerSecond; + constexpr uint64_t kNanosecondsPerSecond = 1E9; + constexpr uint64_t kMinimumStartInterval = 1 * kNanosecondsPerSecond; const uint64_t earliest_next_start_time = handler_restarter->last_start_time_ + kMinimumStartInterval; diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 487b39ab..f9d8e129 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -164,7 +164,7 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { SetEvent(g_signal_exception); // Time to wait for the handler to create a dump. - const DWORD kMillisecondsUntilTerminate = 60 * 1000; + constexpr DWORD kMillisecondsUntilTerminate = 60 * 1000; // Sleep for a while to allow it to process us. Eventually, we terminate // ourselves in case the crash server is gone, so that we don't leave zombies @@ -753,7 +753,7 @@ void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) { // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx have // some of the top nibble set, so we make sure to pick a value that doesn't, // so as to be unlikely to conflict. - const uint32_t kSimulatedExceptionCode = 0x517a7ed; + constexpr uint32_t kSimulatedExceptionCode = 0x517a7ed; EXCEPTION_RECORD record = {}; record.ExceptionCode = kSimulatedExceptionCode; #if defined(ARCH_CPU_64_BITS) @@ -829,7 +829,7 @@ bool CrashpadClient::DumpAndCrashTargetProcess(HANDLE process, } } - const size_t kInjectBufferSize = 4 * 1024; + constexpr size_t kInjectBufferSize = 4 * 1024; WinVMAddress inject_memory = FromPointerCast(VirtualAllocEx(process, nullptr, @@ -1001,7 +1001,10 @@ bool CrashpadClient::DumpAndCrashTargetProcess(HANDLE process, // letting this cause an exception, even when the target is stuck in the // loader lock. HANDLE injected_thread; - const size_t kStackSize = 0x4000; // This is what DebugBreakProcess() uses. + + // This is what DebugBreakProcess() uses. + constexpr size_t kStackSize = 0x4000; + NTSTATUS status = NtCreateThreadEx(&injected_thread, STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, nullptr, diff --git a/client/simple_string_dictionary_test.cc b/client/simple_string_dictionary_test.cc index 6d827b8f..6944934f 100644 --- a/client/simple_string_dictionary_test.cc +++ b/client/simple_string_dictionary_test.cc @@ -121,8 +121,8 @@ TEST(SimpleStringDictionary, Iterator) { char key[SimpleStringDictionary::key_size]; char value[SimpleStringDictionary::value_size]; - const int kDictionaryCapacity = SimpleStringDictionary::num_entries; - const int kPartitionIndex = kDictionaryCapacity - 5; + constexpr int kDictionaryCapacity = SimpleStringDictionary::num_entries; + constexpr int kPartitionIndex = kDictionaryCapacity - 5; // We assume at least this size in the tests below ASSERT_GE(kDictionaryCapacity, 64); diff --git a/handler/crash_report_upload_thread.cc b/handler/crash_report_upload_thread.cc index 252e14fb..19d25ab5 100644 --- a/handler/crash_report_upload_thread.cc +++ b/handler/crash_report_upload_thread.cc @@ -268,7 +268,7 @@ void CrashReportUploadThread::ProcessPendingReport( // If the most recent upload attempt occurred within the past hour, // don’t attempt to upload the new report. If it happened longer ago, // attempt to upload the report. - const int kUploadAttemptIntervalSeconds = 60 * 60; // 1 hour + constexpr int kUploadAttemptIntervalSeconds = 60 * 60; // 1 hour if (now - last_upload_attempt_time < kUploadAttemptIntervalSeconds) { database_->SkipReportUpload( report.uuid, Metrics::CrashSkippedReason::kUploadThrottled); @@ -280,7 +280,7 @@ void CrashReportUploadThread::ProcessPendingReport( // upload attempt time is bogus, and attempt to upload the report. If // the most recent upload time is in the future but within one day, // accept it and don’t attempt to upload the report. - const int kBackwardsClockTolerance = 60 * 60 * 24; // 1 day + constexpr int kBackwardsClockTolerance = 60 * 60 * 24; // 1 day if (last_upload_attempt_time - now < kBackwardsClockTolerance) { database_->SkipReportUpload( report.uuid, Metrics::CrashSkippedReason::kUnexpectedTime); diff --git a/handler/handler_main.cc b/handler/handler_main.cc index f1b08ff9..abc22bf3 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -715,7 +715,7 @@ int HandlerMain(int argc, base::GlobalHistogramAllocator* histogram_allocator = nullptr; if (!options.metrics_dir.empty()) { static constexpr char kMetricsName[] = "CrashpadMetrics"; - const size_t kMetricsFileSize = 1 << 20; + constexpr size_t kMetricsFileSize = 1 << 20; if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( options.metrics_dir, kMetricsFileSize, 0, kMetricsName)) { histogram_allocator = base::GlobalHistogramAllocator::Get(); diff --git a/handler/win/crashy_test_program.cc b/handler/win/crashy_test_program.cc index 0da56cb9..a5532da8 100644 --- a/handler/win/crashy_test_program.cc +++ b/handler/win/crashy_test_program.cc @@ -142,7 +142,7 @@ void SomeCrashyFunction() { void AllocateExtraMemoryToBeSaved( crashpad::SimpleAddressRangeBag* extra_ranges) { - const size_t kNumInts = 2000; + constexpr size_t kNumInts = 2000; int* extra_memory = new int[kNumInts]; g_extra_memory_pointer = extra_memory; for (int i = 0; i < kNumInts; ++i) @@ -154,7 +154,7 @@ void AllocateExtraMemoryToBeSaved( void AllocateExtraUnsavedMemory(crashpad::SimpleAddressRangeBag* extra_ranges) { // Allocate some extra memory, and then Insert() but also Remove() it so we // can confirm it doesn't get saved. - const size_t kNumInts = 2000; + constexpr size_t kNumInts = 2000; int* extra_memory = new int[kNumInts]; g_extra_memory_not_saved = extra_memory; for (int i = 0; i < kNumInts; ++i) @@ -211,7 +211,7 @@ int CrashyMain(int argc, wchar_t* argv[]) { FreeLibrary(wmerror); // Make sure data pointed to by the stack is captured. - const int kDataSize = 512; + constexpr int kDataSize = 512; int* pointed_to_data = new int[kDataSize]; for (int i = 0; i < kDataSize; ++i) pointed_to_data[i] = i | ((i % 2 == 0) ? 0x80000000 : 0); diff --git a/minidump/minidump_context_writer_test.cc b/minidump/minidump_context_writer_test.cc index a6b5f3a9..0c2b5ea2 100644 --- a/minidump/minidump_context_writer_test.cc +++ b/minidump/minidump_context_writer_test.cc @@ -52,7 +52,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) { SCOPED_TRACE("nonzero"); string_file.Reset(); - const uint32_t kSeed = 0x8086; + constexpr uint32_t kSeed = 0x8086; MinidumpContextX86Writer context_writer; InitializeMinidumpContextX86(context_writer.context(), kSeed); @@ -92,7 +92,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { SCOPED_TRACE("nonzero"); string_file.Reset(); - const uint32_t kSeed = 0x808664; + constexpr uint32_t kSeed = 0x808664; MinidumpContextAMD64Writer context_writer; InitializeMinidumpContextAMD64(context_writer.context(), kSeed); @@ -109,7 +109,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { } TEST(MinidumpContextWriter, CreateFromSnapshot_X86) { - const uint32_t kSeed = 32; + constexpr uint32_t kSeed = 32; CPUContextX86 context_snapshot_x86; CPUContext context_snapshot; @@ -131,7 +131,7 @@ TEST(MinidumpContextWriter, CreateFromSnapshot_X86) { } TEST(MinidumpContextWriter, CreateFromSnapshot_AMD64) { - const uint32_t kSeed = 64; + constexpr uint32_t kSeed = 64; CPUContextX86_64 context_snapshot_x86_64; CPUContext context_snapshot; diff --git a/minidump/minidump_crashpad_info_writer_test.cc b/minidump/minidump_crashpad_info_writer_test.cc index 7ae0980b..ab470f14 100644 --- a/minidump/minidump_crashpad_info_writer_test.cc +++ b/minidump/minidump_crashpad_info_writer_test.cc @@ -174,7 +174,7 @@ TEST(MinidumpCrashpadInfoWriter, SimpleAnnotations) { } TEST(MinidumpCrashpadInfoWriter, CrashpadModuleList) { - const uint32_t kMinidumpModuleListIndex = 3; + constexpr uint32_t kMinidumpModuleListIndex = 3; MinidumpFileWriter minidump_file_writer; auto crashpad_info_writer = diff --git a/minidump/minidump_exception_writer.cc b/minidump/minidump_exception_writer.cc index d2466a6b..d870de36 100644 --- a/minidump/minidump_exception_writer.cc +++ b/minidump/minidump_exception_writer.cc @@ -64,7 +64,7 @@ void MinidumpExceptionWriter::SetExceptionInformation( DCHECK_EQ(state(), kStateMutable); const size_t parameters = exception_information.size(); - const size_t kMaxParameters = + constexpr size_t kMaxParameters = ARRAYSIZE_UNSAFE(exception_.ExceptionRecord.ExceptionInformation); CHECK_LE(parameters, kMaxParameters); diff --git a/minidump/minidump_exception_writer_test.cc b/minidump/minidump_exception_writer_test.cc index f2c0816d..5fa7f4a2 100644 --- a/minidump/minidump_exception_writer_test.cc +++ b/minidump/minidump_exception_writer_test.cc @@ -39,12 +39,12 @@ namespace { // This returns the MINIDUMP_EXCEPTION_STREAM stream in |exception_stream|. void GetExceptionStream(const std::string& file_contents, const MINIDUMP_EXCEPTION_STREAM** exception_stream) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kExceptionStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kExceptionStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kContextOffset = + constexpr size_t kContextOffset = kExceptionStreamOffset + sizeof(MINIDUMP_EXCEPTION_STREAM); - const size_t kFileSize = kContextOffset + sizeof(MinidumpContextX86); + constexpr size_t kFileSize = kContextOffset + sizeof(MinidumpContextX86); ASSERT_EQ(kFileSize, file_contents.size()); const MINIDUMP_DIRECTORY* directory; @@ -96,7 +96,7 @@ TEST(MinidumpExceptionWriter, Minimal) { MinidumpFileWriter minidump_file_writer; auto exception_writer = base::WrapUnique(new MinidumpExceptionWriter()); - const uint32_t kSeed = 100; + constexpr uint32_t kSeed = 100; auto context_x86_writer = base::WrapUnique(new MinidumpContextX86Writer()); InitializeMinidumpContextX86(context_x86_writer->context(), kSeed); @@ -128,15 +128,15 @@ TEST(MinidumpExceptionWriter, Standard) { MinidumpFileWriter minidump_file_writer; auto exception_writer = base::WrapUnique(new MinidumpExceptionWriter()); - const uint32_t kSeed = 200; - const uint32_t kThreadID = 1; - const uint32_t kExceptionCode = 2; - const uint32_t kExceptionFlags = 3; - const uint32_t kExceptionRecord = 4; - const uint32_t kExceptionAddress = 5; - const uint64_t kExceptionInformation0 = 6; - const uint64_t kExceptionInformation1 = 7; - const uint64_t kExceptionInformation2 = 7; + constexpr uint32_t kSeed = 200; + constexpr uint32_t kThreadID = 1; + constexpr uint32_t kExceptionCode = 2; + constexpr uint32_t kExceptionFlags = 3; + constexpr uint32_t kExceptionRecord = 4; + constexpr uint32_t kExceptionAddress = 5; + constexpr uint64_t kExceptionInformation0 = 6; + constexpr uint64_t kExceptionInformation1 = 7; + constexpr uint64_t kExceptionInformation2 = 7; auto context_x86_writer = base::WrapUnique(new MinidumpContextX86Writer()); InitializeMinidumpContextX86(context_x86_writer->context(), kSeed); @@ -212,8 +212,8 @@ TEST(MinidumpExceptionWriter, InitializeFromSnapshot) { expect_exception.ExceptionRecord.ExceptionInformation[index] = exception_codes[index]; } - const uint64_t kThreadID = 0xaaaaaaaaaaaaaaaa; - const uint32_t kSeed = 65; + constexpr uint64_t kThreadID = 0xaaaaaaaaaaaaaaaa; + constexpr uint32_t kSeed = 65; TestExceptionSnapshot exception_snapshot; exception_snapshot.SetThreadID(kThreadID); diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index 04ddd4d1..b123742e 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -92,12 +92,13 @@ class TestStream final : public internal::MinidumpStreamWriter { TEST(MinidumpFileWriter, OneStream) { MinidumpFileWriter minidump_file; - const time_t kTimestamp = 0x155d2fb8; + constexpr time_t kTimestamp = 0x155d2fb8; minidump_file.SetTimestamp(kTimestamp); - const size_t kStreamSize = 5; - const MinidumpStreamType kStreamType = static_cast(0x4d); - const uint8_t kStreamValue = 0x5a; + constexpr size_t kStreamSize = 5; + constexpr MinidumpStreamType kStreamType = + static_cast(0x4d); + constexpr uint8_t kStreamValue = 0x5a; auto stream = base::WrapUnique(new TestStream(kStreamType, kStreamSize, kStreamValue)); ASSERT_TRUE(minidump_file.AddStream(std::move(stream))); @@ -105,9 +106,10 @@ TEST(MinidumpFileWriter, OneStream) { StringFile string_file; ASSERT_TRUE(minidump_file.WriteEverything(&string_file)); - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kFileSize = kStreamOffset + kStreamSize; + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kStreamOffset = + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + constexpr size_t kFileSize = kStreamOffset + kStreamSize; ASSERT_EQ(string_file.string().size(), kFileSize); @@ -131,12 +133,13 @@ TEST(MinidumpFileWriter, OneStream) { TEST(MinidumpFileWriter, AddUserExtensionStream) { MinidumpFileWriter minidump_file; - const time_t kTimestamp = 0x155d2fb8; + constexpr time_t kTimestamp = 0x155d2fb8; minidump_file.SetTimestamp(kTimestamp); static constexpr uint8_t kStreamData[] = "Hello World!"; - const size_t kStreamSize = arraysize(kStreamData); - const MinidumpStreamType kStreamType = static_cast(0x4d); + constexpr size_t kStreamSize = arraysize(kStreamData); + constexpr MinidumpStreamType kStreamType = + static_cast(0x4d); auto data_source = base::WrapUnique(new test::BufferExtensionStreamDataSource( kStreamType, kStreamData, kStreamSize)); @@ -150,9 +153,10 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) { StringFile string_file; ASSERT_TRUE(minidump_file.WriteEverything(&string_file)); - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kFileSize = kStreamOffset + kStreamSize; + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kStreamOffset = + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + constexpr size_t kFileSize = kStreamOffset + kStreamSize; ASSERT_EQ(string_file.string().size(), kFileSize); @@ -175,10 +179,11 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) { TEST(MinidumpFileWriter, AddEmptyUserExtensionStream) { MinidumpFileWriter minidump_file; - const time_t kTimestamp = 0x155d2fb8; + constexpr time_t kTimestamp = 0x155d2fb8; minidump_file.SetTimestamp(kTimestamp); - const MinidumpStreamType kStreamType = static_cast(0x4d); + constexpr MinidumpStreamType kStreamType = + static_cast(0x4d); auto data_source = base::WrapUnique( new test::BufferExtensionStreamDataSource(kStreamType, nullptr, 0)); @@ -187,9 +192,10 @@ TEST(MinidumpFileWriter, AddEmptyUserExtensionStream) { StringFile string_file; ASSERT_TRUE(minidump_file.WriteEverything(&string_file)); - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kFileSize = kStreamOffset; + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kStreamOffset = + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + constexpr size_t kFileSize = kStreamOffset; ASSERT_EQ(string_file.string().size(), kFileSize); @@ -206,12 +212,13 @@ TEST(MinidumpFileWriter, AddEmptyUserExtensionStream) { TEST(MinidumpFileWriter, ThreeStreams) { MinidumpFileWriter minidump_file; - const time_t kTimestamp = 0x155d2fb8; + constexpr time_t kTimestamp = 0x155d2fb8; minidump_file.SetTimestamp(kTimestamp); - const size_t kStream0Size = 5; - const MinidumpStreamType kStream0Type = static_cast(0x6d); - const uint8_t kStream0Value = 0x5a; + constexpr size_t kStream0Size = 5; + constexpr MinidumpStreamType kStream0Type = + static_cast(0x6d); + constexpr uint8_t kStream0Value = 0x5a; auto stream0 = base::WrapUnique( new TestStream(kStream0Type, kStream0Size, kStream0Value)); ASSERT_TRUE(minidump_file.AddStream(std::move(stream0))); @@ -219,16 +226,18 @@ TEST(MinidumpFileWriter, ThreeStreams) { // Make the second stream’s type be a smaller quantity than the first stream’s // to test that the streams show up in the order that they were added, not in // numeric order. - const size_t kStream1Size = 3; - const MinidumpStreamType kStream1Type = static_cast(0x4d); - const uint8_t kStream1Value = 0xa5; + constexpr size_t kStream1Size = 3; + constexpr MinidumpStreamType kStream1Type = + static_cast(0x4d); + constexpr uint8_t kStream1Value = 0xa5; auto stream1 = base::WrapUnique( new TestStream(kStream1Type, kStream1Size, kStream1Value)); ASSERT_TRUE(minidump_file.AddStream(std::move(stream1))); - const size_t kStream2Size = 1; - const MinidumpStreamType kStream2Type = static_cast(0x7e); - const uint8_t kStream2Value = 0x36; + constexpr size_t kStream2Size = 1; + constexpr MinidumpStreamType kStream2Type = + static_cast(0x7e); + constexpr uint8_t kStream2Value = 0x36; auto stream2 = base::WrapUnique( new TestStream(kStream2Type, kStream2Size, kStream2Value)); ASSERT_TRUE(minidump_file.AddStream(std::move(stream2))); @@ -236,14 +245,16 @@ TEST(MinidumpFileWriter, ThreeStreams) { StringFile string_file; ASSERT_TRUE(minidump_file.WriteEverything(&string_file)); - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kStream0Offset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kStream0Offset = kDirectoryOffset + 3 * sizeof(MINIDUMP_DIRECTORY); - const size_t kStream1Padding = 3; - const size_t kStream1Offset = kStream0Offset + kStream0Size + kStream1Padding; - const size_t kStream2Padding = 1; - const size_t kStream2Offset = kStream1Offset + kStream1Size + kStream2Padding; - const size_t kFileSize = kStream2Offset + kStream2Size; + constexpr size_t kStream1Padding = 3; + constexpr size_t kStream1Offset = + kStream0Offset + kStream0Size + kStream1Padding; + constexpr size_t kStream2Padding = 1; + constexpr size_t kStream2Offset = + kStream1Offset + kStream1Size + kStream2Padding; + constexpr size_t kFileSize = kStream2Offset + kStream2Size; ASSERT_EQ(string_file.string().size(), kFileSize); @@ -295,17 +306,19 @@ TEST(MinidumpFileWriter, ThreeStreams) { TEST(MinidumpFileWriter, ZeroLengthStream) { MinidumpFileWriter minidump_file; - const size_t kStreamSize = 0; - const MinidumpStreamType kStreamType = static_cast(0x4d); + constexpr size_t kStreamSize = 0; + constexpr MinidumpStreamType kStreamType = + static_cast(0x4d); auto stream = base::WrapUnique(new TestStream(kStreamType, kStreamSize, 0)); ASSERT_TRUE(minidump_file.AddStream(std::move(stream))); StringFile string_file; ASSERT_TRUE(minidump_file.WriteEverything(&string_file)); - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kFileSize = kStreamOffset + kStreamSize; + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kStreamOffset = + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + constexpr size_t kFileSize = kStreamOffset + kStreamSize; ASSERT_EQ(string_file.string().size(), kFileSize); @@ -321,8 +334,8 @@ TEST(MinidumpFileWriter, ZeroLengthStream) { } TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) { - const uint32_t kSnapshotTime = 0x4976043c; - const timeval kSnapshotTimeval = { static_cast(kSnapshotTime), 0 }; + constexpr uint32_t kSnapshotTime = 0x4976043c; + constexpr timeval kSnapshotTimeval = {static_cast(kSnapshotTime), 0}; TestProcessSnapshot process_snapshot; process_snapshot.SetSnapshotTime(kSnapshotTimeval); @@ -333,9 +346,9 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) { process_snapshot.SetSystem(std::move(system_snapshot)); auto peb_snapshot = base::WrapUnique(new TestMemorySnapshot()); - const uint64_t kPebAddress = 0x07f90000; + constexpr uint64_t kPebAddress = 0x07f90000; peb_snapshot->SetAddress(kPebAddress); - const size_t kPebSize = 0x280; + constexpr size_t kPebSize = 0x280; peb_snapshot->SetSize(kPebSize); peb_snapshot->SetValue('p'); process_snapshot.AddExtraMemory(std::move(peb_snapshot)); @@ -383,10 +396,10 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) { TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) { // In a 32-bit environment, this will give a “timestamp out of range” warning, // but the test should complete without failure. - const uint32_t kSnapshotTime = 0xfd469ab8; + constexpr uint32_t kSnapshotTime = 0xfd469ab8; MSVC_SUPPRESS_WARNING(4309); // Truncation of constant value. MSVC_SUPPRESS_WARNING(4838); // Narrowing conversion. - const timeval kSnapshotTimeval = { static_cast(kSnapshotTime), 0 }; + constexpr timeval kSnapshotTimeval = {static_cast(kSnapshotTime), 0}; TestProcessSnapshot process_snapshot; process_snapshot.SetSnapshotTime(kSnapshotTimeval); @@ -449,8 +462,8 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) { } TEST(MinidumpFileWriter, InitializeFromSnapshot_CrashpadInfo) { - const uint32_t kSnapshotTime = 0x15393bd3; - const timeval kSnapshotTimeval = { static_cast(kSnapshotTime), 0 }; + constexpr uint32_t kSnapshotTime = 0x15393bd3; + constexpr timeval kSnapshotTimeval = {static_cast(kSnapshotTime), 0}; TestProcessSnapshot process_snapshot; process_snapshot.SetSnapshotTime(kSnapshotTimeval); @@ -519,16 +532,17 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_CrashpadInfo) { TEST(MinidumpFileWriter, SameStreamType) { MinidumpFileWriter minidump_file; - const size_t kStream0Size = 3; - const MinidumpStreamType kStreamType = static_cast(0x4d); - const uint8_t kStream0Value = 0x5a; + constexpr size_t kStream0Size = 3; + constexpr MinidumpStreamType kStreamType = + static_cast(0x4d); + constexpr uint8_t kStream0Value = 0x5a; auto stream0 = base::WrapUnique( new TestStream(kStreamType, kStream0Size, kStream0Value)); ASSERT_TRUE(minidump_file.AddStream(std::move(stream0))); // An attempt to add a second stream of the same type should fail. - const size_t kStream1Size = 5; - const uint8_t kStream1Value = 0xa5; + constexpr size_t kStream1Size = 5; + constexpr uint8_t kStream1Value = 0xa5; auto stream1 = base::WrapUnique( new TestStream(kStreamType, kStream1Size, kStream1Value)); ASSERT_FALSE(minidump_file.AddStream(std::move(stream1))); @@ -536,9 +550,10 @@ TEST(MinidumpFileWriter, SameStreamType) { StringFile string_file; ASSERT_TRUE(minidump_file.WriteEverything(&string_file)); - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kStream0Offset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kFileSize = kStream0Offset + kStream0Size; + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kStream0Offset = + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + constexpr size_t kFileSize = kStream0Offset + kStream0Size; ASSERT_EQ(string_file.string().size(), kFileSize); diff --git a/minidump/minidump_handle_writer_test.cc b/minidump/minidump_handle_writer_test.cc index 6f238c8f..68b4ff0e 100644 --- a/minidump/minidump_handle_writer_test.cc +++ b/minidump/minidump_handle_writer_test.cc @@ -34,8 +34,8 @@ namespace { void GetHandleDataStream( const std::string& file_contents, const MINIDUMP_HANDLE_DATA_STREAM** handle_data_stream) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kHandleDataStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kHandleDataStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); const MINIDUMP_DIRECTORY* directory; @@ -44,7 +44,7 @@ void GetHandleDataStream( ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_TRUE(directory); - const size_t kDirectoryIndex = 0; + constexpr size_t kDirectoryIndex = 0; ASSERT_EQ(directory[kDirectoryIndex].StreamType, kMinidumpStreamTypeHandleData); diff --git a/minidump/minidump_memory_info_writer_test.cc b/minidump/minidump_memory_info_writer_test.cc index 1458279f..18978fe8 100644 --- a/minidump/minidump_memory_info_writer_test.cc +++ b/minidump/minidump_memory_info_writer_test.cc @@ -33,8 +33,8 @@ namespace { void GetMemoryInfoListStream( const std::string& file_contents, const MINIDUMP_MEMORY_INFO_LIST** memory_info_list) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kMemoryInfoListStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kMemoryInfoListStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); const MINIDUMP_DIRECTORY* directory; @@ -43,7 +43,7 @@ void GetMemoryInfoListStream( ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_TRUE(directory); - const size_t kDirectoryIndex = 0; + constexpr size_t kDirectoryIndex = 0; ASSERT_EQ(directory[kDirectoryIndex].StreamType, kMinidumpStreamTypeMemoryInfoList); diff --git a/minidump/minidump_memory_writer_test.cc b/minidump/minidump_memory_writer_test.cc index 45fdf491..4d3dc57c 100644 --- a/minidump/minidump_memory_writer_test.cc +++ b/minidump/minidump_memory_writer_test.cc @@ -44,7 +44,7 @@ const MinidumpStreamType kBogusStreamType = void GetMemoryListStream(const std::string& file_contents, const MINIDUMP_MEMORY_LIST** memory_list, const uint32_t expected_streams) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); const size_t kMemoryListStreamOffset = kDirectoryOffset + expected_streams * sizeof(MINIDUMP_DIRECTORY); const size_t kMemoryDescriptorsOffset = @@ -99,9 +99,9 @@ TEST(MinidumpMemoryWriter, OneMemoryRegion) { MinidumpFileWriter minidump_file_writer; auto memory_list_writer = base::WrapUnique(new MinidumpMemoryListWriter()); - const uint64_t kBaseAddress = 0xfedcba9876543210; - const uint64_t kSize = 0x1000; - const uint8_t kValue = 'm'; + constexpr uint64_t kBaseAddress = 0xfedcba9876543210; + constexpr uint64_t kSize = 0x1000; + constexpr uint8_t kValue = 'm'; auto memory_writer = base::WrapUnique( new TestMinidumpMemoryWriter(kBaseAddress, kSize, kValue)); @@ -134,12 +134,12 @@ TEST(MinidumpMemoryWriter, TwoMemoryRegions) { MinidumpFileWriter minidump_file_writer; auto memory_list_writer = base::WrapUnique(new MinidumpMemoryListWriter()); - const uint64_t kBaseAddress0 = 0xc0ffee; - const uint64_t kSize0 = 0x0100; - const uint8_t kValue0 = '6'; - const uint64_t kBaseAddress1 = 0xfac00fac; - const uint64_t kSize1 = 0x0200; - const uint8_t kValue1 = '!'; + constexpr uint64_t kBaseAddress0 = 0xc0ffee; + constexpr uint64_t kSize0 = 0x0100; + constexpr uint8_t kValue0 = '6'; + constexpr uint64_t kBaseAddress1 = 0xfac00fac; + constexpr uint64_t kSize1 = 0x0200; + constexpr uint8_t kValue1 = '!'; auto memory_writer_0 = base::WrapUnique( new TestMinidumpMemoryWriter(kBaseAddress0, kSize0, kValue0)); @@ -238,9 +238,9 @@ TEST(MinidumpMemoryWriter, ExtraMemory) { // memory writer a child of the memory list writer. MinidumpFileWriter minidump_file_writer; - const uint64_t kBaseAddress0 = 0x1000; - const size_t kSize0 = 0x0400; - const uint8_t kValue0 = '1'; + constexpr uint64_t kBaseAddress0 = 0x1000; + constexpr size_t kSize0 = 0x0400; + constexpr uint8_t kValue0 = '1'; auto test_memory_stream = base::WrapUnique(new TestMemoryStream(kBaseAddress0, kSize0, kValue0)); @@ -249,9 +249,9 @@ TEST(MinidumpMemoryWriter, ExtraMemory) { ASSERT_TRUE(minidump_file_writer.AddStream(std::move(test_memory_stream))); - const uint64_t kBaseAddress1 = 0x2000; - const size_t kSize1 = 0x0400; - const uint8_t kValue1 = 'm'; + constexpr uint64_t kBaseAddress1 = 0x2000; + constexpr size_t kSize1 = 0x0400; + constexpr uint8_t kValue1 = 'm'; auto memory_writer = base::WrapUnique( new TestMinidumpMemoryWriter(kBaseAddress1, kSize1, kValue1)); diff --git a/minidump/minidump_misc_info_writer.cc b/minidump/minidump_misc_info_writer.cc index 1b775faa..3e0dbbc9 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -42,7 +42,7 @@ namespace { uint32_t TimevalToRoundedSeconds(const timeval& tv) { uint32_t seconds = InRangeCast(tv.tv_sec, std::numeric_limits::max()); - const int kMicrosecondsPerSecond = static_cast(1E6); + constexpr int kMicrosecondsPerSecond = static_cast(1E6); if (tv.tv_usec >= kMicrosecondsPerSecond / 2 && seconds != std::numeric_limits::max()) { ++seconds; @@ -163,7 +163,7 @@ void MinidumpMiscInfoWriter::InitializeFromSnapshot( uint64_t current_hz; uint64_t max_hz; system_snapshot->CPUFrequency(¤t_hz, &max_hz); - const uint32_t kHzPerMHz = static_cast(1E6); + constexpr uint32_t kHzPerMHz = static_cast(1E6); SetProcessorPowerInfo( InRangeCast(current_hz / kHzPerMHz, std::numeric_limits::max()), diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc index ec404ff5..eb682752 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -43,11 +43,11 @@ namespace { template void GetMiscInfoStream(const std::string& file_contents, const T** misc_info) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kMiscInfoStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kMiscInfoStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kMiscInfoStreamSize = sizeof(T); - const size_t kFileSize = kMiscInfoStreamOffset + kMiscInfoStreamSize; + constexpr size_t kMiscInfoStreamSize = sizeof(T); + constexpr size_t kFileSize = kMiscInfoStreamOffset + kMiscInfoStreamSize; ASSERT_EQ(file_contents.size(), kFileSize); @@ -211,7 +211,7 @@ TEST(MinidumpMiscInfoWriter, ProcessId) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kProcessId = 12345; + constexpr uint32_t kProcessId = 12345; misc_info_writer->SetProcessID(kProcessId); @@ -234,9 +234,9 @@ TEST(MinidumpMiscInfoWriter, ProcessTimes) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const time_t kProcessCreateTime = 0x15252f00; - const uint32_t kProcessUserTime = 10; - const uint32_t kProcessKernelTime = 5; + constexpr time_t kProcessCreateTime = 0x15252f00; + constexpr uint32_t kProcessUserTime = 10; + constexpr uint32_t kProcessKernelTime = 5; misc_info_writer->SetProcessTimes( kProcessCreateTime, kProcessUserTime, kProcessKernelTime); @@ -262,11 +262,11 @@ TEST(MinidumpMiscInfoWriter, ProcessorPowerInfo) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kProcessorMaxMhz = 2800; - const uint32_t kProcessorCurrentMhz = 2300; - const uint32_t kProcessorMhzLimit = 3300; - const uint32_t kProcessorMaxIdleState = 5; - const uint32_t kProcessorCurrentIdleState = 1; + constexpr uint32_t kProcessorMaxMhz = 2800; + constexpr uint32_t kProcessorCurrentMhz = 2300; + constexpr uint32_t kProcessorMhzLimit = 3300; + constexpr uint32_t kProcessorMaxIdleState = 5; + constexpr uint32_t kProcessorCurrentIdleState = 1; misc_info_writer->SetProcessorPowerInfo(kProcessorMaxMhz, kProcessorCurrentMhz, @@ -297,7 +297,7 @@ TEST(MinidumpMiscInfoWriter, ProcessIntegrityLevel) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kProcessIntegrityLevel = 0x2000; + constexpr uint32_t kProcessIntegrityLevel = 0x2000; misc_info_writer->SetProcessIntegrityLevel(kProcessIntegrityLevel); @@ -320,7 +320,7 @@ TEST(MinidumpMiscInfoWriter, ProcessExecuteFlags) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kProcessExecuteFlags = 0x13579bdf; + constexpr uint32_t kProcessExecuteFlags = 0x13579bdf; misc_info_writer->SetProcessExecuteFlags(kProcessExecuteFlags); @@ -343,7 +343,7 @@ TEST(MinidumpMiscInfoWriter, ProtectedProcess) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kProtectedProcess = 1; + constexpr uint32_t kProtectedProcess = 1; misc_info_writer->SetProtectedProcess(kProtectedProcess); @@ -366,14 +366,14 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kTimeZoneId = 2; - const int32_t kBias = 300; + constexpr uint32_t kTimeZoneId = 2; + constexpr int32_t kBias = 300; static constexpr char kStandardName[] = "EST"; - const SYSTEMTIME kStandardDate = {0, 11, 1, 0, 2, 0, 0, 0}; - const int32_t kStandardBias = 0; + constexpr SYSTEMTIME kStandardDate = {0, 11, 1, 0, 2, 0, 0, 0}; + constexpr int32_t kStandardBias = 0; static constexpr char kDaylightName[] = "EDT"; - const SYSTEMTIME kDaylightDate = {0, 3, 2, 0, 2, 0, 0, 0}; - const int32_t kDaylightBias = -60; + constexpr SYSTEMTIME kDaylightDate = {0, 3, 2, 0, 2, 0, 0, 0}; + constexpr int32_t kDaylightBias = -60; misc_info_writer->SetTimeZone(kTimeZoneId, kBias, @@ -423,19 +423,19 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kTimeZoneId = 2; - const int32_t kBias = 300; + constexpr uint32_t kTimeZoneId = 2; + constexpr int32_t kBias = 300; MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); std::string standard_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.StandardName) + 1, 's'); - const int32_t kStandardBias = 0; + constexpr int32_t kStandardBias = 0; std::string daylight_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.DaylightName), 'd'); - const int32_t kDaylightBias = -60; + constexpr int32_t kDaylightBias = -60; // Test using kSystemTimeZero, because not all platforms will be able to // provide daylight saving time transition times. - const SYSTEMTIME kSystemTimeZero = {}; + constexpr SYSTEMTIME kSystemTimeZero = {}; misc_info_writer->SetTimeZone(kTimeZoneId, kBias, @@ -551,7 +551,7 @@ TEST(MinidumpMiscInfoWriter, XStateData) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const XSTATE_CONFIG_FEATURE_MSC_INFO kXStateData = { + constexpr XSTATE_CONFIG_FEATURE_MSC_INFO kXStateData = { sizeof(XSTATE_CONFIG_FEATURE_MSC_INFO), 1024, 0x000000000000005f, @@ -585,7 +585,7 @@ TEST(MinidumpMiscInfoWriter, ProcessCookie) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kProcessCookie = 0x12345678; + constexpr uint32_t kProcessCookie = 0x12345678; misc_info_writer->SetProcessCookie(kProcessCookie); @@ -608,25 +608,25 @@ TEST(MinidumpMiscInfoWriter, Everything) { MinidumpFileWriter minidump_file_writer; auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter()); - const uint32_t kProcessId = 12345; - const time_t kProcessCreateTime = 0x15252f00; - const uint32_t kProcessUserTime = 10; - const uint32_t kProcessKernelTime = 5; - const uint32_t kProcessorMaxMhz = 2800; - const uint32_t kProcessorCurrentMhz = 2300; - const uint32_t kProcessorMhzLimit = 3300; - const uint32_t kProcessorMaxIdleState = 5; - const uint32_t kProcessorCurrentIdleState = 1; - const uint32_t kProcessIntegrityLevel = 0x2000; - const uint32_t kProcessExecuteFlags = 0x13579bdf; - const uint32_t kProtectedProcess = 1; - const uint32_t kTimeZoneId = 2; - const int32_t kBias = 300; + constexpr uint32_t kProcessId = 12345; + constexpr time_t kProcessCreateTime = 0x15252f00; + constexpr uint32_t kProcessUserTime = 10; + constexpr uint32_t kProcessKernelTime = 5; + constexpr uint32_t kProcessorMaxMhz = 2800; + constexpr uint32_t kProcessorCurrentMhz = 2300; + constexpr uint32_t kProcessorMhzLimit = 3300; + constexpr uint32_t kProcessorMaxIdleState = 5; + constexpr uint32_t kProcessorCurrentIdleState = 1; + constexpr uint32_t kProcessIntegrityLevel = 0x2000; + constexpr uint32_t kProcessExecuteFlags = 0x13579bdf; + constexpr uint32_t kProtectedProcess = 1; + constexpr uint32_t kTimeZoneId = 2; + constexpr int32_t kBias = 300; static constexpr char kStandardName[] = "EST"; - const int32_t kStandardBias = 0; + constexpr int32_t kStandardBias = 0; static constexpr char kDaylightName[] = "EDT"; - const int32_t kDaylightBias = -60; - const SYSTEMTIME kSystemTimeZero = {}; + constexpr int32_t kDaylightBias = -60; + constexpr SYSTEMTIME kSystemTimeZero = {}; static constexpr char kBuildString[] = "build string"; static constexpr char kDebugBuildString[] = "debug build string"; @@ -773,7 +773,7 @@ TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { process_snapshot.SetProcessCPUTimes(kUserCPUTime, kSystemCPUTime); auto system_snapshot = base::WrapUnique(new TestSystemSnapshot()); - const uint64_t kHzPerMHz = static_cast(1E6); + constexpr uint64_t kHzPerMHz = static_cast(1E6); system_snapshot->SetCPUFrequency( expect_misc_info.ProcessorCurrentMhz * kHzPerMHz, expect_misc_info.ProcessorMaxMhz * kHzPerMHz); diff --git a/minidump/minidump_module_crashpad_info_writer_test.cc b/minidump/minidump_module_crashpad_info_writer_test.cc index 39a92226..b5aa0054 100644 --- a/minidump/minidump_module_crashpad_info_writer_test.cc +++ b/minidump/minidump_module_crashpad_info_writer_test.cc @@ -108,7 +108,7 @@ TEST(MinidumpModuleCrashpadInfoWriter, EmptyModule) { } TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { - const uint32_t kMinidumpModuleListIndex = 1; + constexpr uint32_t kMinidumpModuleListIndex = 1; static constexpr char kKey[] = "key"; static constexpr char kValue[] = "value"; static constexpr char kEntry[] = "entry"; @@ -194,11 +194,11 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { } TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) { - const uint32_t kMinidumpModuleListIndex0 = 0; + constexpr uint32_t kMinidumpModuleListIndex0 = 0; static constexpr char kKey0[] = "key"; static constexpr char kValue0[] = "value"; - const uint32_t kMinidumpModuleListIndex1 = 2; - const uint32_t kMinidumpModuleListIndex2 = 5; + constexpr uint32_t kMinidumpModuleListIndex1 = 2; + constexpr uint32_t kMinidumpModuleListIndex2 = 5; static constexpr char kKey2A[] = "K"; static constexpr char kValue2A[] = "VVV"; static constexpr char kKey2B[] = "river"; diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index 2088b5cf..47ad7f78 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -42,10 +42,10 @@ namespace { void GetModuleListStream(const std::string& file_contents, const MINIDUMP_MODULE_LIST** module_list) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kModuleListStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kModuleListStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kModulesOffset = + constexpr size_t kModulesOffset = kModuleListStreamOffset + sizeof(MINIDUMP_MODULE_LIST); ASSERT_GE(file_contents.size(), kModulesOffset); @@ -311,31 +311,31 @@ TEST(MinidumpModuleWriter, OneModule) { auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter()); static constexpr char kModuleName[] = "statically_linked"; - const uint64_t kModuleBase = 0x10da69000; - const uint32_t kModuleSize = 0x1000; - const uint32_t kChecksum = 0x76543210; - const time_t kTimestamp = 0x386d4380; - const uint32_t kFileVersionMS = 0x00010002; - const uint32_t kFileVersionLS = 0x00030004; - const uint32_t kProductVersionMS = 0x00050006; - const uint32_t kProductVersionLS = 0x00070008; - const uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE | - VS_FF_PATCHED | VS_FF_PRIVATEBUILD | - VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD; - const uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD; - const uint32_t kFileOS = VOS_DOS; - const uint32_t kFileType = VFT_DRV; - const uint32_t kFileSubtype = VFT2_DRV_KEYBOARD; + constexpr uint64_t kModuleBase = 0x10da69000; + constexpr uint32_t kModuleSize = 0x1000; + constexpr uint32_t kChecksum = 0x76543210; + constexpr time_t kTimestamp = 0x386d4380; + constexpr uint32_t kFileVersionMS = 0x00010002; + constexpr uint32_t kFileVersionLS = 0x00030004; + constexpr uint32_t kProductVersionMS = 0x00050006; + constexpr uint32_t kProductVersionLS = 0x00070008; + constexpr uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE | + VS_FF_PATCHED | VS_FF_PRIVATEBUILD | + VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD; + constexpr uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD; + constexpr uint32_t kFileOS = VOS_DOS; + constexpr uint32_t kFileType = VFT_DRV; + constexpr uint32_t kFileSubtype = VFT2_DRV_KEYBOARD; static constexpr char kPDBName[] = "statical.pdb"; static constexpr uint8_t kPDBUUIDBytes[16] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f}; UUID pdb_uuid; pdb_uuid.InitializeFromBytes(kPDBUUIDBytes); - const uint32_t kPDBAge = 1; - const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; + constexpr uint32_t kPDBAge = 1; + constexpr uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; static constexpr char kDebugName[] = "statical.dbg"; - const bool kDebugUTF16 = false; + constexpr bool kDebugUTF16 = false; auto module_writer = base::WrapUnique(new MinidumpModuleWriter()); module_writer->SetName(kModuleName); @@ -421,11 +421,11 @@ TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) { static constexpr char kModuleName[] = "dinosaur"; static constexpr char kPDBName[] = "d1n05.pdb"; - const time_t kPDBTimestamp = 0x386d4380; - const uint32_t kPDBAge = 1; - const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; + constexpr time_t kPDBTimestamp = 0x386d4380; + constexpr uint32_t kPDBAge = 1; + constexpr uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME; static constexpr char kDebugName[] = "d1n05.dbg"; - const bool kDebugUTF16 = true; + constexpr bool kDebugUTF16 = true; auto module_writer = base::WrapUnique(new MinidumpModuleWriter()); module_writer->SetName(kModuleName); @@ -481,26 +481,26 @@ TEST(MinidumpModuleWriter, ThreeModules) { auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter()); static constexpr char kModuleName0[] = "main"; - const uint64_t kModuleBase0 = 0x100101000; - const uint32_t kModuleSize0 = 0xf000; + constexpr uint64_t kModuleBase0 = 0x100101000; + constexpr uint32_t kModuleSize0 = 0xf000; static constexpr char kPDBName0[] = "main"; static constexpr uint8_t kPDBUUIDBytes0[16] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; UUID pdb_uuid_0; pdb_uuid_0.InitializeFromBytes(kPDBUUIDBytes0); - const uint32_t kPDBAge0 = 0; + constexpr uint32_t kPDBAge0 = 0; static constexpr char kModuleName1[] = "ld.so"; - const uint64_t kModuleBase1 = 0x200202000; - const uint32_t kModuleSize1 = 0x1e000; + constexpr uint64_t kModuleBase1 = 0x200202000; + constexpr uint32_t kModuleSize1 = 0x1e000; static constexpr char kModuleName2[] = "libc.so"; - const uint64_t kModuleBase2 = 0x300303000; - const uint32_t kModuleSize2 = 0x2d000; + constexpr uint64_t kModuleBase2 = 0x300303000; + constexpr uint32_t kModuleSize2 = 0x2d000; static constexpr char kPDBName2[] = "libc.so"; - const time_t kPDBTimestamp2 = 0x386d4380; - const uint32_t kPDBAge2 = 2; + constexpr time_t kPDBTimestamp2 = 0x386d4380; + constexpr uint32_t kPDBAge2 = 2; auto module_writer_0 = base::WrapUnique(new MinidumpModuleWriter()); module_writer_0->SetName(kModuleName0); diff --git a/minidump/minidump_rva_list_writer_test.cc b/minidump/minidump_rva_list_writer_test.cc index c961b735..dcd8c3b0 100644 --- a/minidump/minidump_rva_list_writer_test.cc +++ b/minidump/minidump_rva_list_writer_test.cc @@ -57,7 +57,7 @@ TEST(MinidumpRVAListWriter, Empty) { TEST(MinidumpRVAListWriter, OneChild) { TestMinidumpRVAListWriter list_writer; - const uint32_t kValue = 0; + constexpr uint32_t kValue = 0; list_writer.AddChild(kValue); StringFile string_file; diff --git a/minidump/minidump_system_info_writer_test.cc b/minidump/minidump_system_info_writer_test.cc index 62c41933..6fc62b9d 100644 --- a/minidump/minidump_system_info_writer_test.cc +++ b/minidump/minidump_system_info_writer_test.cc @@ -46,10 +46,10 @@ void GetSystemInfoStream(const std::string& file_contents, const size_t kCSDVersionBytesWithNUL = kCSDVersionBytes + sizeof(tmp.Buffer[0]); - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kSystemInfoStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kSystemInfoStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kCSDVersionOffset = + constexpr size_t kCSDVersionOffset = kSystemInfoStreamOffset + sizeof(MINIDUMP_SYSTEM_INFO); const size_t kFileSize = kCSDVersionOffset + sizeof(MINIDUMP_STRING) + kCSDVersionBytesWithNUL; @@ -120,21 +120,22 @@ TEST(MinidumpSystemInfoWriter, X86_Win) { MinidumpFileWriter minidump_file_writer; auto system_info_writer = base::WrapUnique(new MinidumpSystemInfoWriter()); - const MinidumpCPUArchitecture kCPUArchitecture = kMinidumpCPUArchitectureX86; - const uint16_t kCPULevel = 0x0010; - const uint16_t kCPURevision = 0x0602; - const uint8_t kCPUCount = 1; - const MinidumpOS kOS = kMinidumpOSWin32NT; - const MinidumpOSType kOSType = kMinidumpOSTypeWorkstation; - const uint32_t kOSVersionMajor = 6; - const uint32_t kOSVersionMinor = 1; - const uint32_t kOSVersionBuild = 7601; + constexpr MinidumpCPUArchitecture kCPUArchitecture = + kMinidumpCPUArchitectureX86; + constexpr uint16_t kCPULevel = 0x0010; + constexpr uint16_t kCPURevision = 0x0602; + constexpr uint8_t kCPUCount = 1; + constexpr MinidumpOS kOS = kMinidumpOSWin32NT; + constexpr MinidumpOSType kOSType = kMinidumpOSTypeWorkstation; + constexpr uint32_t kOSVersionMajor = 6; + constexpr uint32_t kOSVersionMinor = 1; + constexpr uint32_t kOSVersionBuild = 7601; static constexpr char kCSDVersion[] = "Service Pack 1"; - const uint16_t kSuiteMask = VER_SUITE_SINGLEUSERTS; + constexpr uint16_t kSuiteMask = VER_SUITE_SINGLEUSERTS; static constexpr char kCPUVendor[] = "AuthenticAMD"; - const uint32_t kCPUVersion = 0x00100f62; - const uint32_t kCPUFeatures = 0x078bfbff; - const uint32_t kAMDFeatures = 0xefd3fbff; + constexpr uint32_t kCPUVersion = 0x00100f62; + constexpr uint32_t kCPUFeatures = 0x078bfbff; + constexpr uint32_t kAMDFeatures = 0xefd3fbff; uint32_t cpu_vendor_registers[3]; ASSERT_EQ(strlen(kCPUVendor), sizeof(cpu_vendor_registers)); @@ -190,16 +191,16 @@ TEST(MinidumpSystemInfoWriter, AMD64_Mac) { MinidumpFileWriter minidump_file_writer; auto system_info_writer = base::WrapUnique(new MinidumpSystemInfoWriter()); - const MinidumpCPUArchitecture kCPUArchitecture = + constexpr MinidumpCPUArchitecture kCPUArchitecture = kMinidumpCPUArchitectureAMD64; - const uint16_t kCPULevel = 0x0006; - const uint16_t kCPURevision = 0x3a09; - const uint8_t kCPUCount = 8; - const MinidumpOS kOS = kMinidumpOSMacOSX; - const MinidumpOSType kOSType = kMinidumpOSTypeWorkstation; - const uint32_t kOSVersionMajor = 10; - const uint32_t kOSVersionMinor = 9; - const uint32_t kOSVersionBuild = 4; + constexpr uint16_t kCPULevel = 0x0006; + constexpr uint16_t kCPURevision = 0x3a09; + constexpr uint8_t kCPUCount = 8; + constexpr MinidumpOS kOS = kMinidumpOSMacOSX; + constexpr MinidumpOSType kOSType = kMinidumpOSTypeWorkstation; + constexpr uint32_t kOSVersionMajor = 10; + constexpr uint32_t kOSVersionMinor = 9; + constexpr uint32_t kOSVersionBuild = 4; static constexpr char kCSDVersion[] = "13E28"; static constexpr uint64_t kCPUFeatures[2] = {0x10427f4c, 0x00000000}; @@ -247,7 +248,8 @@ TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) { MinidumpFileWriter minidump_file_writer; auto system_info_writer = base::WrapUnique(new MinidumpSystemInfoWriter()); - const MinidumpCPUArchitecture kCPUArchitecture = kMinidumpCPUArchitectureX86; + constexpr MinidumpCPUArchitecture kCPUArchitecture = + kMinidumpCPUArchitectureX86; static constexpr uint32_t kCPUVendor[] = {'uneG', 'Ieni', 'letn'}; system_info_writer->SetCPUArchitecture(kCPUArchitecture); @@ -277,9 +279,9 @@ TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) { TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) { MINIDUMP_SYSTEM_INFO expect_system_info = {}; - const uint16_t kCPUFamily = 6; - const uint8_t kCPUModel = 70; - const uint8_t kCPUStepping = 1; + constexpr uint16_t kCPUFamily = 6; + constexpr uint8_t kCPUModel = 70; + constexpr uint8_t kCPUStepping = 1; const uint8_t kCPUBasicFamily = static_cast(std::min(kCPUFamily, static_cast(15))); @@ -291,12 +293,12 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) { EXPECT_LE(kCPUStepping, 15); EXPECT_TRUE(kCPUBasicFamily == 6 || kCPUBasicFamily == 15 || kCPUModel <= 15); - const uint8_t kCPUBasicModel = kCPUModel & 0xf; - const uint8_t kCPUExtendedModel = kCPUModel >> 4; + constexpr uint8_t kCPUBasicModel = kCPUModel & 0xf; + constexpr uint8_t kCPUExtendedModel = kCPUModel >> 4; const uint32_t kCPUSignature = (kCPUExtendedFamily << 20) | (kCPUExtendedModel << 16) | (kCPUBasicFamily << 8) | (kCPUBasicModel << 4) | kCPUStepping; - const uint64_t kCPUX86Features = 0x7ffafbffbfebfbff; + constexpr uint64_t kCPUX86Features = 0x7ffafbffbfebfbff; expect_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureX86; expect_system_info.ProcessorLevel = kCPUFamily; expect_system_info.ProcessorRevision = (kCPUModel << 8) | kCPUStepping; @@ -379,9 +381,9 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) { TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_AMD64) { MINIDUMP_SYSTEM_INFO expect_system_info = {}; - const uint8_t kCPUFamily = 6; - const uint8_t kCPUModel = 70; - const uint8_t kCPUStepping = 1; + constexpr uint8_t kCPUFamily = 6; + constexpr uint8_t kCPUModel = 70; + constexpr uint8_t kCPUStepping = 1; expect_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureAMD64; expect_system_info.ProcessorLevel = kCPUFamily; expect_system_info.ProcessorRevision = (kCPUModel << 8) | kCPUStepping; diff --git a/minidump/minidump_thread_writer_test.cc b/minidump/minidump_thread_writer_test.cc index 0fa511ba..d4747ff3 100644 --- a/minidump/minidump_thread_writer_test.cc +++ b/minidump/minidump_thread_writer_test.cc @@ -46,7 +46,7 @@ namespace { void GetThreadListStream(const std::string& file_contents, const MINIDUMP_THREAD_LIST** thread_list, const MINIDUMP_MEMORY_LIST** memory_list) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); const uint32_t kExpectedStreams = memory_list ? 2 : 1; const size_t kThreadListStreamOffset = kDirectoryOffset + kExpectedStreams * sizeof(MINIDUMP_DIRECTORY); @@ -142,12 +142,12 @@ TEST(MinidumpThreadWriter, OneThread_x86_NoStack) { MinidumpFileWriter minidump_file_writer; auto thread_list_writer = base::WrapUnique(new MinidumpThreadListWriter()); - const uint32_t kThreadID = 0x11111111; - const uint32_t kSuspendCount = 1; - const uint32_t kPriorityClass = 0x20; - const uint32_t kPriority = 10; - const uint64_t kTEB = 0x55555555; - const uint32_t kSeed = 123; + constexpr uint32_t kThreadID = 0x11111111; + constexpr uint32_t kSuspendCount = 1; + constexpr uint32_t kPriorityClass = 0x20; + constexpr uint32_t kPriority = 10; + constexpr uint64_t kTEB = 0x55555555; + constexpr uint32_t kSeed = 123; auto thread_writer = base::WrapUnique(new MinidumpThreadWriter()); thread_writer->SetThreadID(kThreadID); @@ -201,15 +201,15 @@ TEST(MinidumpThreadWriter, OneThread_AMD64_Stack) { MinidumpFileWriter minidump_file_writer; auto thread_list_writer = base::WrapUnique(new MinidumpThreadListWriter()); - const uint32_t kThreadID = 0x22222222; - const uint32_t kSuspendCount = 2; - const uint32_t kPriorityClass = 0x30; - const uint32_t kPriority = 20; - const uint64_t kTEB = 0x5555555555555555; - const uint64_t kMemoryBase = 0x765432100000; - const size_t kMemorySize = 32; - const uint8_t kMemoryValue = 99; - const uint32_t kSeed = 456; + constexpr uint32_t kThreadID = 0x22222222; + constexpr uint32_t kSuspendCount = 2; + constexpr uint32_t kPriorityClass = 0x30; + constexpr uint32_t kPriority = 20; + constexpr uint64_t kTEB = 0x5555555555555555; + constexpr uint64_t kMemoryBase = 0x765432100000; + constexpr size_t kMemorySize = 32; + constexpr uint8_t kMemoryValue = 99; + constexpr uint32_t kSeed = 456; auto thread_writer = base::WrapUnique(new MinidumpThreadWriter()); thread_writer->SetThreadID(kThreadID); @@ -282,15 +282,15 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) { auto memory_list_writer = base::WrapUnique(new MinidumpMemoryListWriter()); thread_list_writer->SetMemoryListWriter(memory_list_writer.get()); - const uint32_t kThreadID0 = 1111111; - const uint32_t kSuspendCount0 = 111111; - const uint32_t kPriorityClass0 = 11111; - const uint32_t kPriority0 = 1111; - const uint64_t kTEB0 = 111; - const uint64_t kMemoryBase0 = 0x1110; - const size_t kMemorySize0 = 16; - const uint8_t kMemoryValue0 = 11; - const uint32_t kSeed0 = 1; + constexpr uint32_t kThreadID0 = 1111111; + constexpr uint32_t kSuspendCount0 = 111111; + constexpr uint32_t kPriorityClass0 = 11111; + constexpr uint32_t kPriority0 = 1111; + constexpr uint64_t kTEB0 = 111; + constexpr uint64_t kMemoryBase0 = 0x1110; + constexpr size_t kMemorySize0 = 16; + constexpr uint8_t kMemoryValue0 = 11; + constexpr uint32_t kSeed0 = 1; auto thread_writer_0 = base::WrapUnique(new MinidumpThreadWriter()); thread_writer_0->SetThreadID(kThreadID0); @@ -309,15 +309,15 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) { thread_list_writer->AddThread(std::move(thread_writer_0)); - const uint32_t kThreadID1 = 2222222; - const uint32_t kSuspendCount1 = 222222; - const uint32_t kPriorityClass1 = 22222; - const uint32_t kPriority1 = 2222; - const uint64_t kTEB1 = 222; - const uint64_t kMemoryBase1 = 0x2220; - const size_t kMemorySize1 = 32; - const uint8_t kMemoryValue1 = 22; - const uint32_t kSeed1 = 2; + constexpr uint32_t kThreadID1 = 2222222; + constexpr uint32_t kSuspendCount1 = 222222; + constexpr uint32_t kPriorityClass1 = 22222; + constexpr uint32_t kPriority1 = 2222; + constexpr uint64_t kTEB1 = 222; + constexpr uint64_t kMemoryBase1 = 0x2220; + constexpr size_t kMemorySize1 = 32; + constexpr uint8_t kMemoryValue1 = 22; + constexpr uint32_t kSeed1 = 2; auto thread_writer_1 = base::WrapUnique(new MinidumpThreadWriter()); thread_writer_1->SetThreadID(kThreadID1); @@ -336,15 +336,15 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) { thread_list_writer->AddThread(std::move(thread_writer_1)); - const uint32_t kThreadID2 = 3333333; - const uint32_t kSuspendCount2 = 333333; - const uint32_t kPriorityClass2 = 33333; - const uint32_t kPriority2 = 3333; - const uint64_t kTEB2 = 333; - const uint64_t kMemoryBase2 = 0x3330; - const size_t kMemorySize2 = 48; - const uint8_t kMemoryValue2 = 33; - const uint32_t kSeed2 = 3; + constexpr uint32_t kThreadID2 = 3333333; + constexpr uint32_t kSuspendCount2 = 333333; + constexpr uint32_t kPriorityClass2 = 33333; + constexpr uint32_t kPriority2 = 3333; + constexpr uint64_t kTEB2 = 333; + constexpr uint64_t kMemoryBase2 = 0x3330; + constexpr size_t kMemorySize2 = 48; + constexpr uint8_t kMemoryValue2 = 33; + constexpr uint32_t kSeed2 = 3; auto thread_writer_2 = base::WrapUnique(new MinidumpThreadWriter()); thread_writer_2->SetThreadID(kThreadID2); @@ -533,7 +533,7 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) { uint32_t context_seeds[arraysize(expect_threads)] = {}; MINIDUMP_MEMORY_DESCRIPTOR tebs[arraysize(expect_threads)] = {}; - const size_t kTebSize = 1024; + constexpr size_t kTebSize = 1024; expect_threads[0].ThreadId = 1; expect_threads[0].SuspendCount = 2; diff --git a/minidump/minidump_unloaded_module_writer_test.cc b/minidump/minidump_unloaded_module_writer_test.cc index 63cb84d8..61c7a745 100644 --- a/minidump/minidump_unloaded_module_writer_test.cc +++ b/minidump/minidump_unloaded_module_writer_test.cc @@ -46,10 +46,10 @@ void ExpectUnloadedModule(const MINIDUMP_UNLOADED_MODULE* expected, void GetUnloadedModuleListStream( const std::string& file_contents, const MINIDUMP_UNLOADED_MODULE_LIST** unloaded_module_list) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kUnloadedModuleListStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kUnloadedModuleListStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); - const size_t kUnloadedModulesOffset = + constexpr size_t kUnloadedModulesOffset = kUnloadedModuleListStreamOffset + sizeof(MINIDUMP_UNLOADED_MODULE_LIST); ASSERT_GE(file_contents.size(), kUnloadedModulesOffset); @@ -114,10 +114,10 @@ TEST(MinidumpUnloadedModuleWriter, OneModule) { base::WrapUnique(new MinidumpUnloadedModuleListWriter()); static constexpr char kModuleName[] = "statically_linked"; - const uint64_t kModuleBase = 0x10da69000; - const uint32_t kModuleSize = 0x1000; - const uint32_t kChecksum = 0x76543210; - const time_t kTimestamp = 0x386d4380; + constexpr uint64_t kModuleBase = 0x10da69000; + constexpr uint32_t kModuleSize = 0x1000; + constexpr uint32_t kChecksum = 0x76543210; + constexpr time_t kTimestamp = 0x386d4380; auto unloaded_module_writer = base::WrapUnique(new MinidumpUnloadedModuleWriter()); diff --git a/minidump/minidump_user_stream_writer_test.cc b/minidump/minidump_user_stream_writer_test.cc index e6627e62..86723046 100644 --- a/minidump/minidump_user_stream_writer_test.cc +++ b/minidump/minidump_user_stream_writer_test.cc @@ -35,8 +35,8 @@ void GetUserStream(const std::string& file_contents, MINIDUMP_LOCATION_DESCRIPTOR* user_stream_location, uint32_t stream_type, size_t stream_size) { - const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kUserStreamOffset = + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kUserStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); const MINIDUMP_DIRECTORY* directory; @@ -45,7 +45,7 @@ void GetUserStream(const std::string& file_contents, ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_TRUE(directory); - const size_t kDirectoryIndex = 0; + constexpr size_t kDirectoryIndex = 0; ASSERT_EQ(directory[kDirectoryIndex].StreamType, stream_type); EXPECT_EQ(directory[kDirectoryIndex].Location.Rva, kUserStreamOffset); @@ -100,7 +100,7 @@ TEST(MinidumpUserStreamWriter, InitializeFromSnapshotOneStream) { TestMemorySnapshot* test_data = new TestMemorySnapshot(); test_data->SetAddress(97865); - const size_t kStreamSize = 128; + constexpr size_t kStreamSize = 128; test_data->SetSize(kStreamSize); test_data->SetValue('c'); auto stream = @@ -125,7 +125,7 @@ TEST(MinidumpUserStreamWriter, InitializeFromSnapshotOneStream) { TEST(MinidumpUserStreamWriter, InitializeFromBufferOneStream) { MinidumpFileWriter minidump_file_writer; - const size_t kStreamSize = 128; + constexpr size_t kStreamSize = 128; std::vector data(kStreamSize, 'c'); auto data_source = base::WrapUnique(new test::BufferExtensionStreamDataSource( kTestStreamId, &data[0], data.size())); diff --git a/minidump/test/minidump_memory_writer_test_util.cc b/minidump/test/minidump_memory_writer_test_util.cc index a2fa8b63..03a0e18a 100644 --- a/minidump/test/minidump_memory_writer_test_util.cc +++ b/minidump/test/minidump_memory_writer_test_util.cc @@ -37,7 +37,7 @@ void ExpectMinidumpMemoryDescriptor( EXPECT_EQ(observed->StartOfMemoryRange, expected->StartOfMemoryRange); EXPECT_EQ(observed->Memory.DataSize, expected->Memory.DataSize); if (expected->Memory.Rva != 0) { - const uint32_t kMemoryAlignment = 16; + constexpr uint32_t kMemoryAlignment = 16; EXPECT_EQ(observed->Memory.Rva, (expected->Memory.Rva + kMemoryAlignment - 1) & ~(kMemoryAlignment - 1)); diff --git a/snapshot/capture_memory.cc b/snapshot/capture_memory.cc index eba6729c..c860285a 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -28,7 +28,7 @@ namespace { void MaybeCaptureMemoryAround(CaptureMemory::Delegate* delegate, uint64_t address) { - const uint64_t non_address_offset = 0x10000; + constexpr uint64_t non_address_offset = 0x10000; if (address < non_address_offset) return; @@ -38,9 +38,9 @@ void MaybeCaptureMemoryAround(CaptureMemory::Delegate* delegate, if (address > max_address - non_address_offset) return; - const uint64_t kRegisterByteOffset = 128; + constexpr uint64_t kRegisterByteOffset = 128; const uint64_t target = address - kRegisterByteOffset; - const uint64_t size = 512; + constexpr uint64_t size = 512; static_assert(kRegisterByteOffset <= size / 2, "negative offset too large"); auto ranges = diff --git a/snapshot/linux/process_reader.cc b/snapshot/linux/process_reader.cc index da46f243..d126cfa7 100644 --- a/snapshot/linux/process_reader.cc +++ b/snapshot/linux/process_reader.cc @@ -133,7 +133,7 @@ void ProcessReader::Thread::InitializeStack(ProcessReader* reader) { #if defined(ARCH_CPU_X86_FAMILY) // Adjust start address to include the red zone if (reader->Is64Bit()) { - const LinuxVMSize kRedZoneSize = 128; + constexpr LinuxVMSize kRedZoneSize = 128; LinuxVMAddress red_zone_base = stack_region_start - std::min(kRedZoneSize, stack_region_start); diff --git a/snapshot/mac/mach_o_image_annotations_reader.cc b/snapshot/mac/mach_o_image_annotations_reader.cc index b67a0898..df8bebad 100644 --- a/snapshot/mac/mach_o_image_annotations_reader.cc +++ b/snapshot/mac/mach_o_image_annotations_reader.cc @@ -91,7 +91,7 @@ void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations( // This number was totally made up out of nowhere, but it seems prudent to // enforce some limit. - const size_t kMaxMessageSize = 1024; + constexpr size_t kMaxMessageSize = 1024; if (crash_info.message) { std::string message; if (process_reader_->Memory()->ReadCStringSizeLimited( diff --git a/snapshot/mac/process_reader.cc b/snapshot/mac/process_reader.cc index 5e1f1c7b..43957977 100644 --- a/snapshot/mac/process_reader.cc +++ b/snapshot/mac/process_reader.cc @@ -611,7 +611,7 @@ mach_vm_address_t ProcessReader::CalculateStackRegion( // Regardless of whether the ABI requires a red zone, capture up to // kExtraCaptureSize additional bytes of stack, but only if present in the // region that was already found. - const mach_vm_size_t kExtraCaptureSize = 128; + constexpr mach_vm_size_t kExtraCaptureSize = 128; start_address = std::max(start_address >= kExtraCaptureSize ? start_address - kExtraCaptureSize : start_address, @@ -620,7 +620,7 @@ mach_vm_address_t ProcessReader::CalculateStackRegion( // Align start_address to a 16-byte boundary, which can help readers by // ensuring that data is aligned properly. This could page-align instead, // but that might be wasteful. - const mach_vm_size_t kDesiredAlignment = 16; + constexpr mach_vm_size_t kDesiredAlignment = 16; start_address &= ~(kDesiredAlignment - 1); DCHECK_GE(start_address, region_base); } @@ -685,7 +685,7 @@ void ProcessReader::LocateRedZone(mach_vm_address_t* const start_address, // x86_64 has a red zone. See AMD64 ABI 0.99.6, // http://www.x86-64.org/documentation/abi.pdf, section 3.2.2, “The Stack // Frame”. - const mach_vm_size_t kRedZoneSize = 128; + constexpr mach_vm_size_t kRedZoneSize = 128; mach_vm_address_t red_zone_base = *start_address >= kRedZoneSize ? *start_address - kRedZoneSize : 0; bool red_zone_ok = false; diff --git a/snapshot/mac/process_reader_test.cc b/snapshot/mac/process_reader_test.cc index f1aa1ca2..6d675057 100644 --- a/snapshot/mac/process_reader_test.cc +++ b/snapshot/mac/process_reader_test.cc @@ -384,7 +384,7 @@ TEST(ProcessReader, SelfSeveralThreads) { ASSERT_TRUE(process_reader.Initialize(mach_task_self())); TestThreadPool thread_pool; - const size_t kChildThreads = 16; + constexpr size_t kChildThreads = 16; ASSERT_NO_FATAL_FAILURE(thread_pool.StartThreads(kChildThreads)); // Build a map of all expected threads, keyed by each thread’s ID. The values @@ -523,13 +523,13 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { TEST(ProcessReader, ChildOneThread) { // The main thread plus zero child threads equals one thread. - const size_t kChildThreads = 0; + constexpr size_t kChildThreads = 0; ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); process_reader_threaded_child.Run(); } TEST(ProcessReader, ChildSeveralThreads) { - const size_t kChildThreads = 64; + constexpr size_t kChildThreads = 64; ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads); process_reader_threaded_child.Run(); } diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index 286e7a6f..cc8dd9d4 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -102,7 +102,7 @@ class CrashingDelegate : public ExceptionHandlerServer::Delegate { // Verify the exception happened at the expected location with a bit of // slop space to allow for reading the current PC before the exception // happens. See TestCrashingChild(). - const uint64_t kAllowedOffset = 64; + constexpr uint64_t kAllowedOffset = 64; EXPECT_GT(snapshot.Exception()->ExceptionAddress(), break_near_); EXPECT_LT(snapshot.Exception()->ExceptionAddress(), break_near_ + kAllowedOffset); @@ -205,7 +205,7 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate { // Verify the dump was captured at the expected location with some slop // space. - const uint64_t kAllowedOffset = 64; + constexpr uint64_t kAllowedOffset = 64; EXPECT_GT(snapshot.Exception()->Context()->InstructionPointer(), dump_near_); EXPECT_LT(snapshot.Exception()->Context()->InstructionPointer(), diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index 326f199c..5e3b8be4 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -554,7 +554,7 @@ void ProcessSnapshotWin::ReadLock( AddMemorySnapshot( start, sizeof(process_types::RTL_CRITICAL_SECTION), into); - const decltype(critical_section.DebugInfo) kInvalid = + constexpr decltype(critical_section.DebugInfo) kInvalid = static_cast(-1); if (critical_section.DebugInfo == kInvalid) return; diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index e228905e..4e4114ff 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -192,7 +192,7 @@ void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, *max_hz = 0; return; } - const uint64_t kMhzToHz = static_cast(1E6); + constexpr uint64_t kMhzToHz = static_cast(1E6); *current_hz = std::max_element(info.begin(), info.end(), [](const PROCESSOR_POWER_INFORMATION& a, diff --git a/util/file/file_io_test.cc b/util/file/file_io_test.cc index 400cbace..fdcf7e9a 100644 --- a/util/file/file_io_test.cc +++ b/util/file/file_io_test.cc @@ -398,7 +398,7 @@ void TestOpenFileForWrite(FileHandle (*opener)(const base::FilePath&, EXPECT_TRUE(FileExists(file_path_1)); EXPECT_EQ(FileSize(file_path_1), 0); - const char data = '%'; + constexpr char data = '%'; EXPECT_TRUE(LoggingWriteFile(file_handle.get(), &data, sizeof(data))); // Close file_handle to ensure that the write is flushed to disk. diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 32547134..a393f0b0 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -109,9 +109,9 @@ ParseResult ParseMapsLine(DelimitedFileReader* maps_file_reader, // TODO(jperaza): set bitness properly #if defined(ARCH_CPU_64_BITS) - const bool is_64_bit = true; + constexpr bool is_64_bit = true; #else - const bool is_64_bit = false; + constexpr bool is_64_bit = false; #endif MemoryMap::Mapping mapping; diff --git a/util/linux/thread_info_test.cc b/util/linux/thread_info_test.cc index fe05b4a8..a4bf6baf 100644 --- a/util/linux/thread_info_test.cc +++ b/util/linux/thread_info_test.cc @@ -39,9 +39,9 @@ class SameBitnessTest : public Multiprocess { ASSERT_TRUE(thread_info.Initialize(ChildPID())); #if defined(ARCH_CPU_64_BITS) - const bool am_64_bit = true; + constexpr bool am_64_bit = true; #else - const bool am_64_bit = false; + constexpr bool am_64_bit = false; #endif // ARCH_CPU_64_BITS EXPECT_EQ(thread_info.Is64Bit(), am_64_bit); diff --git a/util/mach/child_port_handshake.cc b/util/mach/child_port_handshake.cc index e3624d70..750d3cbe 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -175,7 +175,7 @@ mach_port_t ChildPortHandshakeServer::RunServer( // be delivered out of order and the check-in message will still be // processed. struct kevent event; - const timespec nonblocking_timeout = {}; + constexpr timespec nonblocking_timeout = {}; const timespec* timeout = blocking ? nullptr : &nonblocking_timeout; rv = HANDLE_EINTR(kevent(kq.get(), nullptr, 0, &event, 1, timeout)); PCHECK(rv != -1) << "kevent"; @@ -341,7 +341,7 @@ ChildPortHandshake::ChildPortHandshake() // SIGPIPE is undesirable when writing to this pipe. Allow broken-pipe writes // to fail with EPIPE instead. - const int value = 1; + constexpr int value = 1; PCHECK(setsockopt(server_write_fd_.get(), SOL_SOCKET, SO_NOSIGPIPE, diff --git a/util/mach/composite_mach_message_server_test.cc b/util/mach/composite_mach_message_server_test.cc index 9325ba33..74e1707a 100644 --- a/util/mach/composite_mach_message_server_test.cc +++ b/util/mach/composite_mach_message_server_test.cc @@ -135,10 +135,10 @@ TEST(CompositeMachMessageServer, HandlerDoesNotHandle) { } TEST(CompositeMachMessageServer, OneHandler) { - const mach_msg_id_t kRequestID = 100; - const mach_msg_size_t kRequestSize = 256; - const mach_msg_size_t kReplySize = 128; - const kern_return_t kReturnCode = KERN_SUCCESS; + constexpr mach_msg_id_t kRequestID = 100; + constexpr mach_msg_size_t kRequestSize = 256; + constexpr mach_msg_size_t kReplySize = 128; + constexpr kern_return_t kReturnCode = KERN_SUCCESS; TestMachMessageHandler handler; handler.AddRequestID(kRequestID); @@ -183,15 +183,15 @@ TEST(CompositeMachMessageServer, OneHandler) { TEST(CompositeMachMessageServer, ThreeHandlers) { static constexpr mach_msg_id_t kRequestIDs0[] = {5}; - const kern_return_t kReturnCode0 = KERN_SUCCESS; + constexpr kern_return_t kReturnCode0 = KERN_SUCCESS; static constexpr mach_msg_id_t kRequestIDs1[] = {4, 7}; - const kern_return_t kReturnCode1 = KERN_PROTECTION_FAILURE; + constexpr kern_return_t kReturnCode1 = KERN_PROTECTION_FAILURE; static constexpr mach_msg_id_t kRequestIDs2[] = {10, 0, 20}; - const mach_msg_size_t kRequestSize2 = 6144; - const mach_msg_size_t kReplySize2 = 16384; - const kern_return_t kReturnCode2 = KERN_NOT_RECEIVER; + constexpr mach_msg_size_t kRequestSize2 = 6144; + constexpr mach_msg_size_t kReplySize2 = 16384; + constexpr kern_return_t kReturnCode2 = KERN_NOT_RECEIVER; TestMachMessageHandler handlers[3]; std::set expect_request_ids; @@ -289,7 +289,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { // CompositeMachMessageServer can’t deal with two handlers that want to handle // the same request ID. TEST(CompositeMachMessageServerDeathTest, DuplicateRequestID) { - const mach_msg_id_t kRequestID = 400; + constexpr mach_msg_id_t kRequestID = 400; TestMachMessageHandler handlers[2]; handlers[0].AddRequestID(kRequestID); diff --git a/util/mach/exc_server_variants.cc b/util/mach/exc_server_variants.cc index 209c45ef..ff918065 100644 --- a/util/mach/exc_server_variants.cc +++ b/util/mach/exc_server_variants.cc @@ -328,7 +328,7 @@ class ExcServer : public MachMessageServer::Interface { bool* destroy_complex_request) override; std::set MachMessageServerRequestIDs() override { - const mach_msg_id_t request_ids[] = { + constexpr mach_msg_id_t request_ids[] = { Traits::kMachMessageIDExceptionRaise, Traits::kMachMessageIDExceptionRaiseState, Traits::kMachMessageIDExceptionRaiseStateIdentity, diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index 149184b2..a947b45e 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -601,7 +601,7 @@ TEST(ExcServerVariants, MockExceptionRaise) { EXPECT_LE(sizeof(reply), universal_mach_exc_server.MachMessageServerReplySize()); - const exception_behavior_t kExceptionBehavior = EXCEPTION_DEFAULT; + constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_DEFAULT; EXPECT_CALL(server, MockCatchMachException(kExceptionBehavior, @@ -646,7 +646,7 @@ TEST(ExcServerVariants, MockExceptionRaiseState) { EXPECT_LE(sizeof(reply), universal_mach_exc_server.MachMessageServerReplySize()); - const exception_behavior_t kExceptionBehavior = EXCEPTION_STATE; + constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_STATE; EXPECT_CALL( server, @@ -695,7 +695,7 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) { EXPECT_LE(sizeof(reply), universal_mach_exc_server.MachMessageServerReplySize()); - const exception_behavior_t kExceptionBehavior = EXCEPTION_STATE_IDENTITY; + constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_STATE_IDENTITY; EXPECT_CALL( server, @@ -741,7 +741,7 @@ TEST(ExcServerVariants, MockMachExceptionRaise) { EXPECT_LE(sizeof(reply), universal_mach_exc_server.MachMessageServerReplySize()); - const exception_behavior_t kExceptionBehavior = + constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES; EXPECT_CALL( @@ -788,7 +788,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) { EXPECT_LE(sizeof(reply), universal_mach_exc_server.MachMessageServerReplySize()); - const exception_behavior_t kExceptionBehavior = + constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_STATE | MACH_EXCEPTION_CODES; EXPECT_CALL( @@ -838,7 +838,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) { EXPECT_LE(sizeof(reply), universal_mach_exc_server.MachMessageServerReplySize()); - const exception_behavior_t kExceptionBehavior = + constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES; EXPECT_CALL( @@ -1269,7 +1269,7 @@ TEST(ExcServerVariants, ExcServerCopyState) { static constexpr natural_t old_state[] = {1, 2, 3, 4, 5}; natural_t new_state[10] = {}; - const mach_msg_type_number_t old_state_count = arraysize(old_state); + constexpr mach_msg_type_number_t old_state_count = arraysize(old_state); mach_msg_type_number_t new_state_count = arraysize(new_state); // EXCEPTION_DEFAULT (with or without MACH_EXCEPTION_CODES) is not diff --git a/util/mach/exception_ports.cc b/util/mach/exception_ports.cc index ef535b4c..3e4e093b 100644 --- a/util/mach/exception_ports.cc +++ b/util/mach/exception_ports.cc @@ -99,7 +99,7 @@ bool ExceptionPorts::GetExceptionPorts(exception_mask_t mask, // later operating system versions have defined more exception types. The // generated task_get_exception_ports() in taskUser.c expects there to be room // for 32. - const int kMaxPorts = 32; + constexpr int kMaxPorts = 32; // task_get_exception_ports() doesn’t actually use the initial value of // handler_count, but 10.9.4 diff --git a/util/mach/exception_ports_test.cc b/util/mach/exception_ports_test.cc index 0bdd92ec..224217bf 100644 --- a/util/mach/exception_ports_test.cc +++ b/util/mach/exception_ports_test.cc @@ -58,7 +58,7 @@ namespace { void TestGetExceptionPorts(const ExceptionPorts& exception_ports, mach_port_t expect_port, exception_behavior_t expect_behavior) { - const exception_mask_t kExceptionMask = EXC_MASK_CRASH; + constexpr exception_mask_t kExceptionMask = EXC_MASK_CRASH; thread_state_flavor_t expect_flavor = (expect_behavior == EXCEPTION_DEFAULT) ? THREAD_STATE_NONE @@ -440,7 +440,7 @@ class TestExceptionPorts : public MachMultiprocess, if (who_crashes_ != kNobodyCrashes) { UniversalMachExcServer universal_mach_exc_server(this); - const mach_msg_timeout_t kTimeoutMs = 50; + constexpr mach_msg_timeout_t kTimeoutMs = 50; kern_return_t kr = MachMessageServer::Run(&universal_mach_exc_server, local_port, diff --git a/util/mach/mach_extensions.cc b/util/mach/mach_extensions.cc index eb4e330e..9e505736 100644 --- a/util/mach/mach_extensions.cc +++ b/util/mach/mach_extensions.cc @@ -103,7 +103,7 @@ exception_mask_t ExcMaskAll() { // See 10.6.8 xnu-1504.15.3/osfmk/mach/exception_types.h. 10.7 uses the same // definition as 10.6. See 10.7.5 xnu-1699.32.7/osfmk/mach/exception_types.h - const exception_mask_t kExcMaskAll_10_6 = + constexpr exception_mask_t kExcMaskAll_10_6 = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | @@ -122,7 +122,7 @@ exception_mask_t ExcMaskAll() { // 10.8 added EXC_MASK_RESOURCE. See 10.8.5 // xnu-2050.48.11/osfmk/mach/exception_types.h. - const exception_mask_t kExcMaskAll_10_8 = + constexpr exception_mask_t kExcMaskAll_10_8 = kExcMaskAll_10_6 | EXC_MASK_RESOURCE; #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 if (mac_os_x_minor_version < 9) { @@ -132,7 +132,8 @@ exception_mask_t ExcMaskAll() { // 10.9 added EXC_MASK_GUARD. See 10.9.4 // xnu-2422.110.17/osfmk/mach/exception_types.h. - const exception_mask_t kExcMaskAll_10_9 = kExcMaskAll_10_8 | EXC_MASK_GUARD; + constexpr exception_mask_t kExcMaskAll_10_9 = + kExcMaskAll_10_8 | EXC_MASK_GUARD; return kExcMaskAll_10_9; } diff --git a/util/mach/mach_message.cc b/util/mach/mach_message.cc index 771f4603..a5617830 100644 --- a/util/mach/mach_message.cc +++ b/util/mach/mach_message.cc @@ -66,7 +66,8 @@ bool TimerRunning(uint64_t deadline, uint64_t remaining = deadline - now; // Round to the nearest millisecond, taking care not to overflow. - const int kHalfMillisecondInNanoseconds = kNanosecondsPerMillisecond / 2; + constexpr int kHalfMillisecondInNanoseconds = + kNanosecondsPerMillisecond / 2; if (remaining <= std::numeric_limits::max() - kHalfMillisecondInNanoseconds) { *remaining_ms = (remaining + kHalfMillisecondInNanoseconds) / diff --git a/util/mach/mach_message_server_test.cc b/util/mach/mach_message_server_test.cc index e0ffebe8..16ba8f20 100644 --- a/util/mach/mach_message_server_test.cc +++ b/util/mach/mach_message_server_test.cc @@ -589,16 +589,16 @@ class TestMachMessageServer : public MachMessageServer::Interface, static uint32_t requests_; static uint32_t replies_; - static const mach_msg_id_t kRequestMessageID = 16237; - static const mach_msg_id_t kReplyMessageID = kRequestMessageID + 100; + static constexpr mach_msg_id_t kRequestMessageID = 16237; + static constexpr mach_msg_id_t kReplyMessageID = kRequestMessageID + 100; DISALLOW_COPY_AND_ASSIGN(TestMachMessageServer); }; uint32_t TestMachMessageServer::requests_; uint32_t TestMachMessageServer::replies_; -const mach_msg_id_t TestMachMessageServer::kRequestMessageID; -const mach_msg_id_t TestMachMessageServer::kReplyMessageID; +constexpr mach_msg_id_t TestMachMessageServer::kRequestMessageID; +constexpr mach_msg_id_t TestMachMessageServer::kReplyMessageID; TEST(MachMessageServer, Basic) { // The client sends one message to the server, which will wait indefinitely in @@ -688,7 +688,7 @@ TEST(MachMessageServer, PersistentNonblockingFourMessages) { // child is allowed to begin sending messages, so // child_wait_for_parent_pipe_early is used to make the child wait until the // parent is ready. - const size_t kTransactionCount = 4; + constexpr size_t kTransactionCount = 4; static_assert(kTransactionCount <= MACH_PORT_QLIMIT_DEFAULT, "must not exceed queue limit"); diff --git a/util/mach/task_memory_test.cc b/util/mach/task_memory_test.cc index 24adb409..d9f0cb77 100644 --- a/util/mach/task_memory_test.cc +++ b/util/mach/task_memory_test.cc @@ -33,7 +33,7 @@ namespace { TEST(TaskMemory, ReadSelf) { vm_address_t address = 0; - const vm_size_t kSize = 4 * PAGE_SIZE; + constexpr vm_size_t kSize = 4 * PAGE_SIZE; kern_return_t kr = vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE); ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_allocate"); @@ -102,7 +102,7 @@ TEST(TaskMemory, ReadSelf) { TEST(TaskMemory, ReadSelfUnmapped) { vm_address_t address = 0; - const vm_size_t kSize = 2 * PAGE_SIZE; + constexpr vm_size_t kSize = 2 * PAGE_SIZE; kern_return_t kr = vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE); ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_allocate"); @@ -221,7 +221,7 @@ TEST(TaskMemory, ReadCStringSelf) { EXPECT_EQ(result, string_short); std::string string_long; - const size_t kStringLongSize = 4 * PAGE_SIZE; + constexpr size_t kStringLongSize = 4 * PAGE_SIZE; for (size_t index = 0; index < kStringLongSize; ++index) { // Don’t include any NUL bytes, because ReadCString stops when it encounters // a NUL. @@ -236,7 +236,7 @@ TEST(TaskMemory, ReadCStringSelf) { TEST(TaskMemory, ReadCStringSelfUnmapped) { vm_address_t address = 0; - const vm_size_t kSize = 2 * PAGE_SIZE; + constexpr vm_size_t kSize = 2 * PAGE_SIZE; kern_return_t kr = vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE); ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_allocate"); @@ -418,7 +418,7 @@ TEST(TaskMemory, ReadCStringSizeLimited_StringLong) { std::string result; std::string string_long; - const size_t kStringLongSize = 4 * PAGE_SIZE; + constexpr size_t kStringLongSize = 4 * PAGE_SIZE; for (size_t index = 0; index < kStringLongSize; ++index) { // Don’t include any NUL bytes, because ReadCString stops when it encounters // a NUL. @@ -498,7 +498,7 @@ TEST(TaskMemory, MappedMemoryDeallocates) { // This is the same but with a big buffer that’s definitely larger than a // single page. This makes sure that the whole mapped region winds up being // deallocated. - const size_t kBigSize = 4 * PAGE_SIZE; + constexpr size_t kBigSize = 4 * PAGE_SIZE; std::unique_ptr big_buffer(new char[kBigSize]); test_address = FromPointerCast(&big_buffer[0]); ASSERT_TRUE((mapped = memory.ReadMapped(test_address, kBigSize))); diff --git a/util/misc/clock_win.cc b/util/misc/clock_win.cc index 2de7ae75..18d07545 100644 --- a/util/misc/clock_win.cc +++ b/util/misc/clock_win.cc @@ -40,7 +40,7 @@ uint64_t ClockMonotonicNanoseconds() { int64_t frequency = QpcFrequency(); int64_t whole_seconds = time.QuadPart / frequency; int64_t leftover_ticks = time.QuadPart % frequency; - const int64_t kNanosecondsPerSecond = static_cast(1E9); + constexpr int64_t kNanosecondsPerSecond = static_cast(1E9); return (whole_seconds * kNanosecondsPerSecond) + ((leftover_ticks * kNanosecondsPerSecond) / frequency); } diff --git a/util/net/http_body_gzip.cc b/util/net/http_body_gzip.cc index 70f4db35..02abe713 100644 --- a/util/net/http_body_gzip.cc +++ b/util/net/http_body_gzip.cc @@ -54,8 +54,8 @@ FileOperationResult GzipHTTPBodyStream::GetBytesBuffer(uint8_t* buffer, // are the values that deflateInit() would use, but they’re not exported // from zlib. deflateInit2() is used instead of deflateInit() to get the // gzip wrapper. - const int kZlibMaxWindowBits = 15; - const int kZlibDefaultMemoryLevel = 8; + constexpr int kZlibMaxWindowBits = 15; + constexpr int kZlibDefaultMemoryLevel = 8; int zr = deflateInit2(z_stream_.get(), Z_DEFAULT_COMPRESSION, diff --git a/util/net/http_body_gzip_test.cc b/util/net/http_body_gzip_test.cc index 770f64af..85887502 100644 --- a/util/net/http_body_gzip_test.cc +++ b/util/net/http_body_gzip_test.cc @@ -83,7 +83,7 @@ void TestGzipDeflateInflate(const std::string& string) { // The minimum size of a gzip wrapper per RFC 1952: a 10-byte header and an // 8-byte trailer. - const size_t kGzipHeaderSize = 18; + constexpr size_t kGzipHeaderSize = 18; // Per http://www.zlib.net/zlib_tech.html, in the worst case, zlib will store // uncompressed data as-is, at an overhead of 5 bytes per 16384-byte block. diff --git a/util/net/http_transport_libcurl.cc b/util/net/http_transport_libcurl.cc index 70da696d..c16a593d 100644 --- a/util/net/http_transport_libcurl.cc +++ b/util/net/http_transport_libcurl.cc @@ -257,7 +257,7 @@ bool HTTPTransportLibcurl::ExecuteSynchronously(std::string* response_body) { TRY_CURL_EASY_SETOPT(curl.get(), CURLOPT_URL, url().c_str()); - const int kMillisecondsPerSecond = 1E3; + constexpr int kMillisecondsPerSecond = 1E3; TRY_CURL_EASY_SETOPT(curl.get(), CURLOPT_TIMEOUT_MS, static_cast(timeout() * kMillisecondsPerSecond)); diff --git a/util/net/http_transport_mac.mm b/util/net/http_transport_mac.mm index 5b4f18c7..8d5f78cc 100644 --- a/util/net/http_transport_mac.mm +++ b/util/net/http_transport_mac.mm @@ -118,23 +118,23 @@ class HTTPBodyStreamCFReadStream { // Creates a new NSInputStream, which the caller owns. NSInputStream* CreateInputStream() { CFStreamClientContext context = { - .version = 0, - .info = this, - .retain = nullptr, - .release = nullptr, - .copyDescription = nullptr + .version = 0, + .info = this, + .retain = nullptr, + .release = nullptr, + .copyDescription = nullptr }; - const CFReadStreamCallBacksV0 callbacks = { - .version = 0, - .open = &Open, - .openCompleted = &OpenCompleted, - .read = &Read, - .getBuffer = &GetBuffer, - .canRead = &CanRead, - .close = &Close, - .copyProperty = &CopyProperty, - .schedule = &Schedule, - .unschedule = &Unschedule + constexpr CFReadStreamCallBacksV0 callbacks = { + .version = 0, + .open = &Open, + .openCompleted = &OpenCompleted, + .read = &Read, + .getBuffer = &GetBuffer, + .canRead = &CanRead, + .close = &Close, + .copyProperty = &CopyProperty, + .schedule = &Schedule, + .unschedule = &Unschedule }; CFReadStreamRef read_stream = CFReadStreamCreate(nullptr, reinterpret_cast(&callbacks), &context); diff --git a/util/posix/process_info_linux.cc b/util/posix/process_info_linux.cc index f37e7411..05896d27 100644 --- a/util/posix/process_info_linux.cc +++ b/util/posix/process_info_linux.cc @@ -227,9 +227,9 @@ bool ProcessInfo::Is64Bit(bool* is_64_bit) const { is_64_bit_initialized_.set_invalid(); #if defined(ARCH_CPU_64_BITS) - const bool am_64_bit = true; + constexpr bool am_64_bit = true; #else - const bool am_64_bit = false; + constexpr bool am_64_bit = false; #endif if (pid_ == getpid()) { diff --git a/util/posix/signals.cc b/util/posix/signals.cc index a19fbafb..d79d53ab 100644 --- a/util/posix/signals.cc +++ b/util/posix/signals.cc @@ -238,7 +238,7 @@ void Signals::RestoreHandlerAndReraiseSignalOnReturn( // Failures in this function should _exit(kFailureExitCode). This is a quick // and quiet failure. This function runs in signal handler context, and it’s // difficult to safely be loud from a signal handler. - const int kFailureExitCode = 191; + constexpr int kFailureExitCode = 191; struct sigaction default_action; sigemptyset(&default_action.sa_mask); diff --git a/util/posix/symbolic_constants_posix_test.cc b/util/posix/symbolic_constants_posix_test.cc index 4084c2c3..8478b7bc 100644 --- a/util/posix/symbolic_constants_posix_test.cc +++ b/util/posix/symbolic_constants_posix_test.cc @@ -122,9 +122,9 @@ TEST(SymbolicConstantsPOSIX, SignalToString) { #if defined(OS_LINUX) || defined(OS_ANDROID) // NSIG is 64 to account for real-time signals. - const int kSignalCount = 32; + constexpr int kSignalCount = 32; #else - const int kSignalCount = NSIG; + constexpr int kSignalCount = NSIG; #endif for (int signal = 0; signal < kSignalCount + 8; ++signal) { diff --git a/util/synchronization/semaphore_test.cc b/util/synchronization/semaphore_test.cc index ccaf742d..e1f3648c 100644 --- a/util/synchronization/semaphore_test.cc +++ b/util/synchronization/semaphore_test.cc @@ -16,6 +16,7 @@ #include +#include "base/macros.h" #include "gtest/gtest.h" #if defined(OS_POSIX) @@ -120,10 +121,9 @@ TEST(Semaphore, TenThreaded) { // resources (10), and the threads each try to obtain the resource a different // number of times. Semaphore semaphore(5); - const size_t kThreads = 10; - ThreadMainInfo info[kThreads]; + ThreadMainInfo info[10]; size_t iterations = 0; - for (size_t index = 0; index < kThreads; ++index) { + for (size_t index = 0; index < arraysize(info); ++index) { info[index].semaphore = &semaphore; info[index].iterations = index; iterations += info[index].iterations; @@ -135,7 +135,7 @@ TEST(Semaphore, TenThreaded) { semaphore.Signal(); } - for (size_t index = 0; index < kThreads; ++index) { + for (size_t index = 0; index < arraysize(info); ++index) { JoinThread(&info[index]); } } diff --git a/util/thread/thread_log_messages_test.cc b/util/thread/thread_log_messages_test.cc index f906ff15..00b612ce 100644 --- a/util/thread/thread_log_messages_test.cc +++ b/util/thread/thread_log_messages_test.cc @@ -44,7 +44,7 @@ std::string MessageString(const std::string& log_message) { return std::string(); } - const char kStartChar = '['; + constexpr char kStartChar = '['; if (log_message[0] != kStartChar) { EXPECT_EQ(log_message[0], kStartChar); return std::string(); @@ -63,7 +63,7 @@ std::string MessageString(const std::string& log_message) { return std::string(); } - const char kEndChar = '\n'; + constexpr char kEndChar = '\n'; if (message_string[message_string.size() - 1] != kEndChar) { EXPECT_NE(message_string[message_string.size() - 1], kEndChar); return std::string(); diff --git a/util/win/capture_context_test.cc b/util/win/capture_context_test.cc index 59bef2ff..4bb6f4f3 100644 --- a/util/win/capture_context_test.cc +++ b/util/win/capture_context_test.cc @@ -34,13 +34,13 @@ namespace { // gtest assertions. void SanityCheckContext(const CONTEXT& context) { #if defined(ARCH_CPU_X86) - const uint32_t must_have = CONTEXT_i386 | - CONTEXT_CONTROL | - CONTEXT_INTEGER | - CONTEXT_SEGMENTS | - CONTEXT_FLOATING_POINT; + constexpr uint32_t must_have = CONTEXT_i386 | + CONTEXT_CONTROL | + CONTEXT_INTEGER | + CONTEXT_SEGMENTS | + CONTEXT_FLOATING_POINT; ASSERT_EQ(context.ContextFlags & must_have, must_have); - const uint32_t may_have = CONTEXT_EXTENDED_REGISTERS; + constexpr uint32_t may_have = CONTEXT_EXTENDED_REGISTERS; ASSERT_EQ(context.ContextFlags & ~(must_have | may_have), 0); #elif defined(ARCH_CPU_X86_64) ASSERT_EQ(context.ContextFlags, diff --git a/util/win/process_info.cc b/util/win/process_info.cc index d3871c2d..9db70282 100644 --- a/util/win/process_info.cc +++ b/util/win/process_info.cc @@ -329,7 +329,7 @@ bool ReadProcessData(HANDLE process, bool ReadMemoryInfo(HANDLE process, bool is_64_bit, ProcessInfo* process_info) { DCHECK(process_info->memory_info_.empty()); - const WinVMAddress min_address = 0; + constexpr WinVMAddress min_address = 0; // We can't use GetSystemInfo() to get the address space range for another // process. VirtualQueryEx() will fail with ERROR_INVALID_PARAMETER if the // address is above the highest memory address accessible to the process, so diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc index d715350f..07c40bb0 100644 --- a/util/win/process_info_test.cc +++ b/util/win/process_info_test.cc @@ -601,7 +601,7 @@ TEST(ProcessInfo, Handles) { // OBJ_INHERIT from ntdef.h, but including that conflicts with other // headers. - const int kObjInherit = 0x2; + constexpr int kObjInherit = 0x2; EXPECT_EQ(handle.attributes, kObjInherit); } if (handle.handle == HandleToInt(scoped_key.get())) { @@ -633,7 +633,7 @@ TEST(ProcessInfo, Handles) { } TEST(ProcessInfo, OutOfRangeCheck) { - const size_t kAllocationSize = 12345; + constexpr size_t kAllocationSize = 12345; std::unique_ptr safe_memory(new char[kAllocationSize]); ProcessInfo info; diff --git a/util/win/time.cc b/util/win/time.cc index 4c6fba19..6d3c9c08 100644 --- a/util/win/time.cc +++ b/util/win/time.cc @@ -46,7 +46,7 @@ timeval FiletimeToTimevalEpoch(const FILETIME& filetime) { // 1601 to 1970 is 369 years + 89 leap days = 134774 days * 86400 seconds per // day. It's not entirely clear, but it appears that these are solar seconds, // not SI seconds, so there are no leap seconds to be considered. - const uint64_t kNumSecondsFrom1601To1970 = (369 * 365 + 89) * 86400ULL; + constexpr uint64_t kNumSecondsFrom1601To1970 = (369 * 365 + 89) * 86400ULL; DCHECK_GE(microseconds, kNumSecondsFrom1601To1970 * kMicrosecondsPerSecond); microseconds -= kNumSecondsFrom1601To1970 * kMicrosecondsPerSecond; return MicrosecondsToTimeval(microseconds); From 8f0636288a0eda130bb9e73860524a97bd0305e6 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 25 Jul 2017 14:31:27 -0400 Subject: [PATCH 26/30] Use constexpr at namespace scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is essentially based on a search for “^const .*=”. Change-Id: I9332c1f0cf7c891ba1ae373dc537f700f9a1d956 Reviewed-on: https://chromium-review.googlesource.com/585452 Reviewed-by: Leonard Mosescu --- client/crash_report_database_win.cc | 4 ++-- minidump/minidump_extensions.cc | 4 ++-- minidump/minidump_extensions.h | 4 ++-- minidump/minidump_memory_writer_test.cc | 2 +- minidump/minidump_writable.cc | 4 ++-- snapshot/mac/mach_o_image_reader.cc | 2 +- snapshot/mac/mach_o_image_reader_test.cc | 15 ++++++++------- test/scoped_temp_dir_win.cc | 2 +- util/file/file_io.h | 18 ++++++++++++++---- util/file/file_io_posix.cc | 3 --- util/file/file_io_win.cc | 3 --- util/mach/child_port_server_test.cc | 8 ++++---- util/mach/exc_server_variants_test.cc | 18 +++++++++--------- util/mach/mach_extensions.cc | 8 ++++---- util/mach/mach_extensions.h | 6 +++--- util/mach/mach_extensions_test.cc | 2 +- util/mach/mach_message.cc | 2 +- util/mach/mach_message.h | 2 +- util/mach/symbolic_constants_mach_test.cc | 16 ++++++++-------- util/misc/clock_posix.cc | 2 +- util/net/http_headers.cc | 23 ----------------------- util/net/http_headers.h | 6 +++--- util/net/http_transport_win.cc | 2 +- util/numeric/in_range_cast_test.cc | 4 ++-- util/thread/worker_thread_test.cc | 2 +- util/util.gyp | 1 - util/win/time.cc | 2 +- 27 files changed, 73 insertions(+), 92 deletions(-) delete mode 100644 util/net/http_headers.cc diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index 1e1b4d7a..538eff5f 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -43,8 +43,8 @@ constexpr wchar_t kSettings[] = L"settings.dat"; constexpr wchar_t kCrashReportFileExtension[] = L"dmp"; -const uint32_t kMetadataFileHeaderMagic = 'CPAD'; -const uint32_t kMetadataFileVersion = 1; +constexpr uint32_t kMetadataFileHeaderMagic = 'CPAD'; +constexpr uint32_t kMetadataFileVersion = 1; using OperationStatus = CrashReportDatabase::OperationStatus; diff --git a/minidump/minidump_extensions.cc b/minidump/minidump_extensions.cc index a956817e..bfb0e60e 100644 --- a/minidump/minidump_extensions.cc +++ b/minidump/minidump_extensions.cc @@ -16,7 +16,7 @@ namespace crashpad { -const uint32_t MinidumpModuleCrashpadInfo::kVersion; -const uint32_t MinidumpCrashpadInfo::kVersion; +constexpr uint32_t MinidumpModuleCrashpadInfo::kVersion; +constexpr uint32_t MinidumpCrashpadInfo::kVersion; } // namespace crashpad diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index 245ef8b5..f3615669 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -290,7 +290,7 @@ struct ALIGNAS(4) PACKED MinidumpModuleCrashpadInfo { //! \brief The structure’s currently-defined version number. //! //! \sa version - static const uint32_t kVersion = 1; + static constexpr uint32_t kVersion = 1; //! \brief The structure’s version number. //! @@ -387,7 +387,7 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo { //! \brief The structure’s currently-defined version number. //! //! \sa version - static const uint32_t kVersion = 1; + static constexpr uint32_t kVersion = 1; //! \brief The structure’s version number. //! diff --git a/minidump/minidump_memory_writer_test.cc b/minidump/minidump_memory_writer_test.cc index 4d3dc57c..ffa56d51 100644 --- a/minidump/minidump_memory_writer_test.cc +++ b/minidump/minidump_memory_writer_test.cc @@ -35,7 +35,7 @@ namespace crashpad { namespace test { namespace { -const MinidumpStreamType kBogusStreamType = +constexpr MinidumpStreamType kBogusStreamType = static_cast(1234); // expected_streams is the expected number of streams in the file. The memory diff --git a/minidump/minidump_writable.cc b/minidump/minidump_writable.cc index 47e21ff4..42a714f1 100644 --- a/minidump/minidump_writable.cc +++ b/minidump/minidump_writable.cc @@ -24,7 +24,7 @@ namespace { -const size_t kMaximumAlignment = 16; +constexpr size_t kMaximumAlignment = 16; } // namespace @@ -82,7 +82,7 @@ void MinidumpWritable::RegisterLocationDescriptor( registered_location_descriptors_.push_back(location_descriptor); } -const size_t MinidumpWritable::kInvalidSize = +constexpr size_t MinidumpWritable::kInvalidSize = std::numeric_limits::max(); MinidumpWritable::MinidumpWritable() diff --git a/snapshot/mac/mach_o_image_reader.cc b/snapshot/mac/mach_o_image_reader.cc index f16aa554..7cb4040f 100644 --- a/snapshot/mac/mach_o_image_reader.cc +++ b/snapshot/mac/mach_o_image_reader.cc @@ -33,7 +33,7 @@ namespace { -const uint32_t kInvalidSegmentIndex = std::numeric_limits::max(); +constexpr uint32_t kInvalidSegmentIndex = std::numeric_limits::max(); } // namespace diff --git a/snapshot/mac/mach_o_image_reader_test.cc b/snapshot/mac/mach_o_image_reader_test.cc index 6d6e49d0..d6b801f8 100644 --- a/snapshot/mac/mach_o_image_reader_test.cc +++ b/snapshot/mac/mach_o_image_reader_test.cc @@ -47,16 +47,16 @@ namespace { // are different. #if defined(ARCH_CPU_64_BITS) using MachHeader = mach_header_64; -const uint32_t kMachMagic = MH_MAGIC_64; +constexpr uint32_t kMachMagic = MH_MAGIC_64; using SegmentCommand = segment_command_64; -const uint32_t kSegmentCommand = LC_SEGMENT_64; +constexpr uint32_t kSegmentCommand = LC_SEGMENT_64; using Section = section_64; using Nlist = nlist_64; #else using MachHeader = mach_header; -const uint32_t kMachMagic = MH_MAGIC; +constexpr uint32_t kMachMagic = MH_MAGIC; using SegmentCommand = segment_command; -const uint32_t kSegmentCommand = LC_SEGMENT; +constexpr uint32_t kSegmentCommand = LC_SEGMENT; using Section = section; // This needs to be called “struct nlist” because “nlist” without the struct @@ -65,9 +65,9 @@ using Nlist = struct nlist; #endif #if defined(ARCH_CPU_X86_64) -const int kCPUType = CPU_TYPE_X86_64; +constexpr int kCPUType = CPU_TYPE_X86_64; #elif defined(ARCH_CPU_X86) -const int kCPUType = CPU_TYPE_X86; +constexpr int kCPUType = CPU_TYPE_X86; #endif // Verifies that |expect_section| and |actual_section| agree. @@ -327,7 +327,8 @@ void ExpectSegmentCommands(const MachHeader* expect_image, // In some cases, the expected slide value for an image is unknown, because no // reasonable API to return it is provided. When this happens, use kSlideUnknown // to avoid checking the actual slide value against anything. -const mach_vm_size_t kSlideUnknown = std::numeric_limits::max(); +constexpr mach_vm_size_t kSlideUnknown = + std::numeric_limits::max(); // Verifies that |expect_image| is a vaild Mach-O header for the current system // by checking its |magic| and |cputype| fields. Then, verifies that the diff --git a/test/scoped_temp_dir_win.cc b/test/scoped_temp_dir_win.cc index 0413ec42..d9707af6 100644 --- a/test/scoped_temp_dir_win.cc +++ b/test/scoped_temp_dir_win.cc @@ -38,7 +38,7 @@ base::FilePath GenerateCandidateName() { return system_temp_dir.Append(new_dir_name); } -const int kRetries = 50; +constexpr int kRetries = 50; } // namespace diff --git a/util/file/file_io.h b/util/file/file_io.h index c70dff30..044a0a69 100644 --- a/util/file/file_io.h +++ b/util/file/file_io.h @@ -45,11 +45,12 @@ using FileOffset = off_t; //! \brief Scoped wrapper of a FileHandle. using ScopedFileHandle = base::ScopedFD; +//! \brief The return value of read and write calls. +using FileOperationResult = ssize_t; + //! \brief A value that can never be a valid FileHandle. const FileHandle kInvalidFileHandle = -1; -using FileOperationResult = ssize_t; - #elif defined(OS_WIN) using FileHandle = HANDLE; @@ -109,19 +110,28 @@ enum class StdioStream { namespace internal { +#if defined(OS_POSIX) || DOXYGEN + //! \brief The name of the native read function used by ReadFile(). //! //! This value may be useful for logging. //! //! \sa kNativeWriteFunctionName -extern const char kNativeReadFunctionName[]; +constexpr char kNativeReadFunctionName[] = "read"; //! \brief The name of the native write function used by WriteFile(). //! //! This value may be useful for logging. //! //! \sa kNativeReadFunctionName -extern const char kNativeWriteFunctionName[]; +constexpr char kNativeWriteFunctionName[] = "write"; + +#elif defined(OS_WIN) + +constexpr char kNativeReadFunctionName[] = "ReadFile"; +constexpr char kNativeWriteFunctionName[] = "WriteFile"; + +#endif //! \brief The internal implementation of ReadFileExactly() and its wrappers. //! diff --git a/util/file/file_io_posix.cc b/util/file/file_io_posix.cc index 49441244..60a36996 100644 --- a/util/file/file_io_posix.cc +++ b/util/file/file_io_posix.cc @@ -96,9 +96,6 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly, namespace internal { -const char kNativeReadFunctionName[] = "read"; -const char kNativeWriteFunctionName[] = "write"; - FileOperationResult NativeWriteFile(FileHandle file, const void* buffer, size_t size) { diff --git a/util/file/file_io_win.cc b/util/file/file_io_win.cc index 467fc3c8..7428034a 100644 --- a/util/file/file_io_win.cc +++ b/util/file/file_io_win.cc @@ -84,9 +84,6 @@ FileHandle OpenFileForOutput(DWORD access, namespace internal { -const char kNativeReadFunctionName[] = "ReadFile"; -const char kNativeWriteFunctionName[] = "WriteFile"; - FileOperationResult NativeWriteFile(FileHandle file, const void* buffer, size_t size) { diff --git a/util/mach/child_port_server_test.cc b/util/mach/child_port_server_test.cc index d579ce91..984d64ac 100644 --- a/util/mach/child_port_server_test.cc +++ b/util/mach/child_port_server_test.cc @@ -32,12 +32,12 @@ using testing::Return; // Fake Mach ports. These aren’t used as ports in these tests, they’re just used // as cookies to make sure that the correct values get passed to the correct // places. -const mach_port_t kServerLocalPort = 0x05050505; -const mach_port_t kCheckInPort = 0x06060606; +constexpr mach_port_t kServerLocalPort = 0x05050505; +constexpr mach_port_t kCheckInPort = 0x06060606; // Other fake values. -const mach_msg_type_name_t kCheckInPortRightType = MACH_MSG_TYPE_PORT_SEND; -const child_port_token_t kCheckInToken = 0xfedcba9876543210; +constexpr mach_msg_type_name_t kCheckInPortRightType = MACH_MSG_TYPE_PORT_SEND; +constexpr child_port_token_t kCheckInToken = 0xfedcba9876543210; // The definition of the request structure from child_port.h isn’t available // here. It needs custom initialization code, so duplicate the expected diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index a947b45e..358cd1ec 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -43,28 +43,28 @@ using testing::Return; // Fake Mach ports. These aren’t used as ports in these tests, they’re just used // as cookies to make sure that the correct values get passed to the correct // places. -const mach_port_t kClientRemotePort = 0x01010101; -const mach_port_t kServerLocalPort = 0x02020202; -const thread_t kExceptionThreadPort = 0x03030303; -const task_t kExceptionTaskPort = 0x04040404; +constexpr mach_port_t kClientRemotePort = 0x01010101; +constexpr mach_port_t kServerLocalPort = 0x02020202; +constexpr thread_t kExceptionThreadPort = 0x03030303; +constexpr task_t kExceptionTaskPort = 0x04040404; // Other fake exception values. -const exception_type_t kExceptionType = EXC_BAD_ACCESS; +constexpr exception_type_t kExceptionType = EXC_BAD_ACCESS; // Test using an exception code with the high bit set to ensure that it gets // promoted to the wider mach_exception_data_type_t type as a signed quantity. -const exception_data_type_t kTestExceptonCodes[] = { +constexpr exception_data_type_t kTestExceptonCodes[] = { KERN_PROTECTION_FAILURE, implicit_cast(0xfedcba98), }; -const mach_exception_data_type_t kTestMachExceptionCodes[] = { +constexpr mach_exception_data_type_t kTestMachExceptionCodes[] = { KERN_PROTECTION_FAILURE, implicit_cast(0xfedcba9876543210), }; -const thread_state_flavor_t kThreadStateFlavor = MACHINE_THREAD_STATE; -const mach_msg_type_number_t kThreadStateFlavorCount = +constexpr thread_state_flavor_t kThreadStateFlavor = MACHINE_THREAD_STATE; +constexpr mach_msg_type_number_t kThreadStateFlavorCount = MACHINE_THREAD_STATE_COUNT; void InitializeMachMsgPortDescriptor(mach_msg_port_descriptor_t* descriptor, diff --git a/util/mach/mach_extensions.cc b/util/mach/mach_extensions.cc index 9e505736..5450ab28 100644 --- a/util/mach/mach_extensions.cc +++ b/util/mach/mach_extensions.cc @@ -34,9 +34,9 @@ struct BootstrapCheckInTraits { mach_port_t* service_port) { return bootstrap_check_in(bootstrap_port, service_name, service_port); } - static const char kName[]; + static constexpr char kName[] = "bootstrap_check_in"; }; -const char BootstrapCheckInTraits::kName[] = "bootstrap_check_in"; +constexpr char BootstrapCheckInTraits::kName[]; struct BootstrapLookUpTraits { using Type = base::mac::ScopedMachSendRight; @@ -45,9 +45,9 @@ struct BootstrapLookUpTraits { mach_port_t* service_port) { return bootstrap_look_up(bootstrap_port, service_name, service_port); } - static const char kName[]; + static constexpr char kName[] = "bootstrap_look_up"; }; -const char BootstrapLookUpTraits::kName[] = "bootstrap_look_up"; +constexpr char BootstrapLookUpTraits::kName[]; template typename Traits::Type BootstrapCheckInOrLookUp( diff --git a/util/mach/mach_extensions.h b/util/mach/mach_extensions.h index 5eeca9ae..25e401c2 100644 --- a/util/mach/mach_extensions.h +++ b/util/mach/mach_extensions.h @@ -30,7 +30,7 @@ namespace crashpad { //! are not performed, use kMachPortNull instead of an explicit `implicit_cast` //! of `MACH_PORT_NULL` to `mach_port_t`. This is useful for logging and testing //! assertions. -const mach_port_t kMachPortNull = MACH_PORT_NULL; +constexpr mach_port_t kMachPortNull = MACH_PORT_NULL; //! \brief `MACH_EXCEPTION_CODES` with the correct type for a Mach exception //! behavior, `exception_behavior_t`. @@ -38,7 +38,7 @@ const mach_port_t kMachPortNull = MACH_PORT_NULL; //! Signedness problems can occur when ORing `MACH_EXCEPTION_CODES` as a signed //! integer, because a signed integer overflow results. This constant can be //! used instead of `MACH_EXCEPTION_CODES` in such cases. -const exception_behavior_t kMachExceptionCodes = MACH_EXCEPTION_CODES; +constexpr exception_behavior_t kMachExceptionCodes = MACH_EXCEPTION_CODES; // Because exception_mask_t is an int and has one bit for each defined // exception_type_t, it’s reasonable to assume that there cannot be any @@ -49,7 +49,7 @@ const exception_behavior_t kMachExceptionCodes = MACH_EXCEPTION_CODES; // EXC_MASK_CRASH. //! \brief An exception type to use for simulated exceptions. -const exception_type_t kMachExceptionSimulated = 'CPsx'; +constexpr exception_type_t kMachExceptionSimulated = 'CPsx'; //! \brief A const version of `thread_state_t`. //! diff --git a/util/mach/mach_extensions_test.cc b/util/mach/mach_extensions_test.cc index 289a1999..1c5b368c 100644 --- a/util/mach/mach_extensions_test.cc +++ b/util/mach/mach_extensions_test.cc @@ -62,7 +62,7 @@ TEST(MachExtensions, NewMachPort_DeadName) { EXPECT_EQ(type, MACH_PORT_TYPE_DEAD_NAME); } -const exception_mask_t kExcMaskBasic = +constexpr exception_mask_t kExcMaskBasic = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | diff --git a/util/mach/mach_message.cc b/util/mach/mach_message.cc index a5617830..5294c035 100644 --- a/util/mach/mach_message.cc +++ b/util/mach/mach_message.cc @@ -28,7 +28,7 @@ namespace crashpad { namespace { -const int kNanosecondsPerMillisecond = 1E6; +constexpr int kNanosecondsPerMillisecond = 1E6; // TimerRunning() determines whether |deadline| has passed. If |deadline| is // kMachMessageDeadlineWaitIndefinitely, |*timeout_options| is set to diff --git a/util/mach/mach_message.h b/util/mach/mach_message.h index df4b6b4f..e0fc6f6f 100644 --- a/util/mach/mach_message.h +++ b/util/mach/mach_message.h @@ -26,7 +26,7 @@ namespace crashpad { //! //! This constant is provided because the macros normally used to request this //! behavior are cumbersome. -const mach_msg_option_t kMachMessageReceiveAuditTrailer = +constexpr mach_msg_option_t kMachMessageReceiveAuditTrailer = MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT); diff --git a/util/mach/symbolic_constants_mach_test.cc b/util/mach/symbolic_constants_mach_test.cc index c8d6d48e..32711412 100644 --- a/util/mach/symbolic_constants_mach_test.cc +++ b/util/mach/symbolic_constants_mach_test.cc @@ -147,9 +147,9 @@ struct ConvertExceptionTraits { ValueType* value) { return StringToException(string, options, value); } - static const char kValueName[]; + static constexpr char kValueName[] = "exception"; }; -const char ConvertExceptionTraits::kValueName[] = "exception"; +constexpr char ConvertExceptionTraits::kValueName[]; void TestExceptionToString(exception_type_t value, const char* expect_full, @@ -322,9 +322,9 @@ struct ConvertExceptionMaskTraits { ValueType* value) { return StringToExceptionMask(string, options, value); } - static const char kValueName[]; + static constexpr char kValueName[] = "exception_mask"; }; -const char ConvertExceptionMaskTraits::kValueName[] = "exception_mask"; +constexpr char ConvertExceptionMaskTraits::kValueName[]; void TestExceptionMaskToString(exception_mask_t value, const char* expect_full, @@ -565,9 +565,9 @@ struct ConvertExceptionBehaviorTraits { ValueType* value) { return StringToExceptionBehavior(string, options, value); } - static const char kValueName[]; + static constexpr char kValueName[] = "behavior"; }; -const char ConvertExceptionBehaviorTraits::kValueName[] = "behavior"; +constexpr char ConvertExceptionBehaviorTraits::kValueName[]; void TestExceptionBehaviorToString(exception_behavior_t value, const char* expect_full, @@ -828,9 +828,9 @@ struct ConvertThreadStateFlavorTraits { ValueType* value) { return StringToThreadStateFlavor(string, options, value); } - static const char kValueName[]; + static constexpr char kValueName[] = "flavor"; }; -const char ConvertThreadStateFlavorTraits::kValueName[] = "flavor"; +constexpr char ConvertThreadStateFlavorTraits::kValueName[]; void TestThreadStateFlavorToString(exception_type_t value, const char* expect_full, diff --git a/util/misc/clock_posix.cc b/util/misc/clock_posix.cc index 24171091..51c1406d 100644 --- a/util/misc/clock_posix.cc +++ b/util/misc/clock_posix.cc @@ -22,7 +22,7 @@ namespace { -const uint64_t kNanosecondsPerSecond = 1E9; +constexpr uint64_t kNanosecondsPerSecond = 1E9; } // namespace diff --git a/util/net/http_headers.cc b/util/net/http_headers.cc deleted file mode 100644 index 37d84c67..00000000 --- a/util/net/http_headers.cc +++ /dev/null @@ -1,23 +0,0 @@ -// 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/net/http_headers.h" - -namespace crashpad { - -const char kContentType[] = "Content-Type"; -const char kContentLength[] = "Content-Length"; -const char kContentEncoding[] = "Content-Encoding"; - -} // namespace crashpad diff --git a/util/net/http_headers.h b/util/net/http_headers.h index 851ff31c..50335063 100644 --- a/util/net/http_headers.h +++ b/util/net/http_headers.h @@ -24,13 +24,13 @@ namespace crashpad { using HTTPHeaders = std::map; //! \brief The header name `"Content-Type"`. -extern const char kContentType[]; +constexpr char kContentType[] = "Content-Type"; //! \brief The header name `"Content-Length"`. -extern const char kContentLength[]; +constexpr char kContentLength[] = "Content-Length"; //! \brief The header name `"Content-Encoding"`. -extern const char kContentEncoding[]; +constexpr char kContentEncoding[] = "Content-Encoding"; } // namespace crashpad diff --git a/util/net/http_transport_win.cc b/util/net/http_transport_win.cc index ecbe8ea2..27cd4048 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -39,7 +39,7 @@ namespace crashpad { namespace { -const wchar_t kWinHttpDll[] = L"winhttp.dll"; +constexpr wchar_t kWinHttpDll[] = L"winhttp.dll"; std::string UserAgent() { std::string user_agent = diff --git a/util/numeric/in_range_cast_test.cc b/util/numeric/in_range_cast_test.cc index 6e74129f..73f5fd57 100644 --- a/util/numeric/in_range_cast_test.cc +++ b/util/numeric/in_range_cast_test.cc @@ -25,8 +25,8 @@ namespace crashpad { namespace test { namespace { -const int32_t kInt32Min = std::numeric_limits::min(); -const int64_t kInt64Min = std::numeric_limits::min(); +constexpr int32_t kInt32Min = std::numeric_limits::min(); +constexpr int64_t kInt64Min = std::numeric_limits::min(); TEST(InRangeCast, Uint32) { EXPECT_EQ(InRangeCast(0, 1), 0u); diff --git a/util/thread/worker_thread_test.cc b/util/thread/worker_thread_test.cc index 2070c6ad..9b11fef1 100644 --- a/util/thread/worker_thread_test.cc +++ b/util/thread/worker_thread_test.cc @@ -22,7 +22,7 @@ namespace crashpad { namespace test { namespace { -const uint64_t kNanosecondsPerSecond = static_cast(1E9); +constexpr uint64_t kNanosecondsPerSecond = static_cast(1E9); class WorkDelegate : public WorkerThread::Delegate { public: diff --git a/util/util.gyp b/util/util.gyp index 5facdaeb..80d5e117 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -140,7 +140,6 @@ 'net/http_body.h', 'net/http_body_gzip.cc', 'net/http_body_gzip.h', - 'net/http_headers.cc', 'net/http_headers.h', 'net/http_multipart_builder.cc', 'net/http_multipart_builder.h', diff --git a/util/win/time.cc b/util/win/time.cc index 6d3c9c08..f3c2360a 100644 --- a/util/win/time.cc +++ b/util/win/time.cc @@ -22,7 +22,7 @@ namespace crashpad { namespace { -const uint64_t kMicrosecondsPerSecond = static_cast(1E6); +constexpr uint64_t kMicrosecondsPerSecond = static_cast(1E6); uint64_t FiletimeToMicroseconds(const FILETIME& filetime) { uint64_t t = (static_cast(filetime.dwHighDateTime) << 32) | From b653f861532117050c155a213d1fb7be7ba1f450 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 28 Jul 2017 21:21:13 -0400 Subject: [PATCH 27/30] Fix Windows build after 8f0636288a0e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang, GCC, and MSVS 2017 were fine with a “constexpr” definition corresponding to a class-scope “static const” declaration, but MSVS 2015 is not. Change-Id: I8c80c6e62d1a312bad161db98e584be225b70bbf Reviewed-on: https://chromium-review.googlesource.com/592644 Reviewed-by: Mark Mentovai --- minidump/minidump_writable.cc | 5 ----- minidump/minidump_writable.h | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/minidump/minidump_writable.cc b/minidump/minidump_writable.cc index 42a714f1..d2b58f5b 100644 --- a/minidump/minidump_writable.cc +++ b/minidump/minidump_writable.cc @@ -16,8 +16,6 @@ #include -#include - #include "base/logging.h" #include "util/file/file_writer.h" #include "util/numeric/safe_assignment.h" @@ -82,9 +80,6 @@ void MinidumpWritable::RegisterLocationDescriptor( registered_location_descriptors_.push_back(location_descriptor); } -constexpr size_t MinidumpWritable::kInvalidSize = - std::numeric_limits::max(); - MinidumpWritable::MinidumpWritable() : registered_rvas_(), registered_location_descriptors_(), diff --git a/minidump/minidump_writable.h b/minidump/minidump_writable.h index 98273751..3518e6a9 100644 --- a/minidump/minidump_writable.h +++ b/minidump/minidump_writable.h @@ -19,6 +19,7 @@ #include #include +#include #include #include "base/macros.h" @@ -134,7 +135,7 @@ class MinidumpWritable { //! \brief A size value used to signal failure by methods that return //! `size_t`. - static const size_t kInvalidSize; + static constexpr size_t kInvalidSize = std::numeric_limits::max(); MinidumpWritable(); From a06ca92083f517843b05a0047d14c57002f417c1 Mon Sep 17 00:00:00 2001 From: Dirk Pranke Date: Sat, 29 Jul 2017 14:02:10 -0700 Subject: [PATCH 28/30] Switch CQ to use the new swarmbucket (LUCI) builders. This updates the crashpad CQ config to use the builders configured in https://chromium-review.googlesource.com/c/580607/. TBR=mark@chromium.org BUG=743139 Change-Id: I29ae95f9d29630ba4522467efefe058548da623b Reviewed-on: https://chromium-review.googlesource.com/592849 Reviewed-by: Dirk Pranke --- infra/config/cq.cfg | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index b436f9f8..b25a4aaa 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg @@ -33,14 +33,10 @@ verifiers { try_job { buckets { name: "master.client.crashpad" - builders { name: "crashpad_try_mac_dbg" } - builders { name: "crashpad_try_mac_rel" } - builders { name: "crashpad_try_win_x64_dbg" } - builders { name: "crashpad_try_win_x64_rel" } - builders { name: "crashpad_try_win_x86_dbg" } - builders { name: "crashpad_try_win_x86_rel" } - builders { name: "crashpad_try_win_x86_wow64_dbg" } - builders { name: "crashpad_try_win_x86_wow64_rel" } + builders { name: "mac_dbg" } + builders { name: "mac_rel" } + builders { name: "win_x64_dbg" } + builders { name: "win_x64_rel" } } } } From 3a5837c7737900bbdfd77cffdd797a7a2d6c06d5 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 28 Jul 2017 21:39:29 -0400 Subject: [PATCH 29/30] #include "build/build_config.h" where necessary Change-Id: I982ec4f7a87fa92925d22267f948df6ca5febea7 Reviewed-on: https://chromium-review.googlesource.com/592693 Reviewed-by: Joshua Peraza --- snapshot/linux/elf_image_reader.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/snapshot/linux/elf_image_reader.cc b/snapshot/linux/elf_image_reader.cc index 07fdfcf5..fbc0667b 100644 --- a/snapshot/linux/elf_image_reader.cc +++ b/snapshot/linux/elf_image_reader.cc @@ -20,6 +20,7 @@ #include #include "base/logging.h" +#include "build/build_config.h" namespace crashpad { From c332e7ffdab60989cd47111b4958b074b44c1a39 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 28 Jul 2017 21:44:35 -0400 Subject: [PATCH 30/30] Fix Doxygen usage in util/misc/lexing.h Change-Id: Ifdef347426655df2ab54aed0eec0cfbe4bbd7cb1 Reviewed-on: https://chromium-review.googlesource.com/592696 Reviewed-by: Joshua Peraza --- util/misc/lexing.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/misc/lexing.h b/util/misc/lexing.h index d9829485..ba37e0ca 100644 --- a/util/misc/lexing.h +++ b/util/misc/lexing.h @@ -21,8 +21,8 @@ namespace crashpad { //! //! \param[in,out] input A pointer to the char string to match against. \a input //! is advanced past the matched pattern if it is found. -//! \param[in] pattern The pattern to match at the start of \input. -//! \return `true` if the pattern is matched exactly and \input is advanced, +//! \param[in] pattern The pattern to match at the start of \a input. +//! \return `true` if the pattern is matched exactly and \a input is advanced, //! otherwise `false`. bool AdvancePastPrefix(const char** input, const char* pattern);