Update sentry-native to 0.7.2

This commit is contained in:
Marek Roszko 2024-04-29 20:11:06 -04:00
parent 7fdb5e98a2
commit 2f0ff4e557
292 changed files with 27639 additions and 5178 deletions

View File

@ -1,11 +1,68 @@
# Changelog
## 0.7.2
**Features**:
- Add optional Gzip transport compression via build option `SENTRY_TRANSPORT_COMPRESSION`. Requires system `zlib`. ([#954](https://github.com/getsentry/sentry-native/pull/954))
- Enable automatic MIME detection of attachments sent with crash-reports from the `crashpad_handler`. ([#973](https://github.com/getsentry/sentry-native/pull/973), [crashpad#98](https://github.com/getsentry/crashpad/pull/98))
**Fixes**:
- Fix the Linux build when targeting RISC-V. ([#972](https://github.com/getsentry/sentry-native/pull/972))
**Thank you**:
- [@Strive-Sun](https://github.com/Strive-Sun)
- [@jwinarske](https://github.com/jwinarske)
## 0.7.1
**Features**:
- Add user feedback capability to the Native SDK. ([#966](https://github.com/getsentry/sentry-native/pull/966))
**Internal**:
- Remove the `CRASHPAD_WER_ENABLED` build flag. The WER module is now built for all supported Windows targets, and registration is conditional on runtime Windows version checks. ([#950](https://github.com/getsentry/sentry-native/pull/950), [crashpad#96](https://github.com/getsentry/crashpad/pull/96))
**Docs**:
- Add usage of the breadcrumb `data` property to the example. [#951](https://github.com/getsentry/sentry-native/pull/951)
## 0.7.0
**Breaking changes**:
- Make `crashpad` the default backend for Linux. ([#927](https://github.com/getsentry/sentry-native/pull/927))
- Remove build option `SENTRY_CRASHPAD_SYSTEM`. ([#928](https://github.com/getsentry/sentry-native/pull/928))
**Fixes**:
- Maintain `crashpad` client instance during Native SDK lifecycle. ([#910](https://github.com/getsentry/sentry-native/pull/910))
- Specify correct dependencies for CMake client projects using a system-provided breakpad. ([#926](https://github.com/getsentry/sentry-native/pull/926))
- Correct the Windows header include used by `sentry.h`, which fixes the build of [Swift bindings](https://github.com/thebrowsercompany/swift-sentry). ([#935](https://github.com/getsentry/sentry-native/pull/935))
**Internal**:
- Updated `crashpad` to 2023-11-24. ([#912](https://github.com/getsentry/sentry-native/pull/912), [crashpad#91](https://github.com/getsentry/crashpad/pull/91))
- Fixing `crashpad` build for Windows on ARM64. ([#919](https://github.com/getsentry/sentry-native/pull/919), [crashpad#90](https://github.com/getsentry/crashpad/pull/90), [crashpad#92](https://github.com/getsentry/crashpad/pull/92), [crashpad#93](https://github.com/getsentry/crashpad/pull/93), [crashpad#94](https://github.com/getsentry/crashpad/pull/94))
- Remove options memory leak during consent setting. ([#922](https://github.com/getsentry/sentry-native/pull/922))
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@compnerd](https://github.com/compnerd)
- [@stima](https://github.com/stima)
- [@hyp](https://github.com/hyp)
## 0.6.7
**Fixes**:
- Disable sigaltstack on Android ([#901](https://github.com/getsentry/sentry-native/pull/901))
- Prevent stuck crashpad-client on Windows ([#902](https://github.com/getsentry/sentry-native/pull/902), [crashpad#89](https://github.com/getsentry/crashpad/pull/89))
- Disable sigaltstack on Android. ([#901](https://github.com/getsentry/sentry-native/pull/901))
- Prevent stuck crashpad-client on Windows. ([#902](https://github.com/getsentry/sentry-native/pull/902), [crashpad#89](https://github.com/getsentry/crashpad/pull/89))
## 0.6.6

View File

@ -26,11 +26,11 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
endif()
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD 11)
endif()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)
endif()
include(GNUInstallDirs)
@ -55,6 +55,8 @@ endif()
option(SENTRY_PIC "Build sentry (and dependent) libraries as position independent libraries" ON)
option(SENTRY_TRANSPORT_COMPRESSION "Enable transport gzip compression" OFF)
option(SENTRY_BUILD_TESTS "Build sentry-native tests" "${SENTRY_MAIN_PROJECT}")
option(SENTRY_BUILD_EXAMPLES "Build sentry-native example(s)" "${SENTRY_MAIN_PROJECT}")
@ -96,7 +98,7 @@ else()
endif()
set(SENTRY_TRANSPORT ${SENTRY_DEFAULT_TRANSPORT} CACHE STRING
"The HTTP transport that sentry uses to submit events to the sentry server, can be either 'none', 'curl' or 'winhttp' on windows.")
"The HTTP transport that sentry uses to submit events to the sentry server, can be either 'none', 'curl' or 'winhttp' on windows.")
if(SENTRY_TRANSPORT STREQUAL "winhttp")
set(SENTRY_TRANSPORT_WINHTTP TRUE)
@ -125,10 +127,8 @@ option(SENTRY_ENABLE_INSTALL "Enable sentry installation" "${SENTRY_MAIN_PROJECT
if(MSVC AND CMAKE_GENERATOR_TOOLSET MATCHES "_xp$")
message(WARNING "Crashpad is not supported for MSVC with XP toolset. Default backend was switched to 'breakpad'")
set(SENTRY_DEFAULT_BACKEND "breakpad")
elseif((APPLE AND NOT IOS) OR WIN32)
elseif((APPLE AND NOT IOS) OR WIN32 OR LINUX)
set(SENTRY_DEFAULT_BACKEND "crashpad")
elseif(LINUX)
set(SENTRY_DEFAULT_BACKEND "breakpad")
else()
set(SENTRY_DEFAULT_BACKEND "inproc")
endif()
@ -280,17 +280,20 @@ if(SENTRY_TRANSPORT_CURL)
find_package(CURL REQUIRED COMPONENTS AsynchDNS)
endif()
if(TARGET CURL::libcurl) # Only available in cmake 3.12+
target_link_libraries(sentry PRIVATE CURL::libcurl)
else()
# Needed for cmake < 3.12 support (cmake 3.12 introduced the target CURL::libcurl)
target_include_directories(sentry PRIVATE ${CURL_INCLUDE_DIR})
# The exported sentry target must not contain any path of the build machine, therefore use generator expressions
string(REPLACE ";" "$<SEMICOLON>" GENEX_CURL_LIBRARIES "${CURL_LIBRARIES}")
string(REPLACE ";" "$<SEMICOLON>" GENEX_CURL_COMPILE_DEFINITIONS "${CURL_COMPILE_DEFINITIONS}")
target_link_libraries(sentry PRIVATE $<BUILD_INTERFACE:${GENEX_CURL_LIBRARIES}>)
target_compile_definitions(sentry PRIVATE $<BUILD_INTERFACE:${GENEX_CURL_COMPILE_DEFINITIONS}>)
target_link_libraries(sentry PRIVATE CURL::libcurl)
endif()
if(SENTRY_TRANSPORT_COMPRESSION)
if(NOT ZLIB_FOUND)
find_package(ZLIB REQUIRED)
endif()
if(SENTRY_BACKEND_CRASHPAD)
set(CRASHPAD_ZLIB_SYSTEM ON CACHE BOOL "Force CRASHPAD_ZLIB_SYSTEM when enabling transport compression" FORCE)
endif()
target_link_libraries(sentry PRIVATE ZLIB::ZLIB)
target_compile_definitions(sentry PRIVATE SENTRY_TRANSPORT_COMPRESSION)
endif()
set_property(TARGET sentry PROPERTY C_VISIBILITY_PRESET hidden)
@ -367,11 +370,11 @@ endif()
# handle platform libraries
if(ANDROID)
set(_SENTRY_PLATFORM_LIBS "dl" "log")
set(_SENTRY_PLATFORM_LIBS "dl" "log")
elseif(LINUX)
set(_SENTRY_PLATFORM_LIBS "dl" "rt")
set(_SENTRY_PLATFORM_LIBS "dl" "rt")
elseif(WIN32)
set(_SENTRY_PLATFORM_LIBS "dbghelp" "shlwapi" "version")
set(_SENTRY_PLATFORM_LIBS "dbghelp" "shlwapi" "version")
endif()
if(SENTRY_TRANSPORT_WINHTTP)
@ -385,9 +388,9 @@ endif()
# apply platform libraries to sentry library
if(SENTRY_LIBRARY_TYPE STREQUAL "STATIC")
target_link_libraries(sentry PUBLIC ${_SENTRY_PLATFORM_LIBS})
target_link_libraries(sentry PUBLIC ${_SENTRY_PLATFORM_LIBS})
else()
target_link_libraries(sentry PRIVATE ${_SENTRY_PLATFORM_LIBS})
target_link_libraries(sentry PRIVATE ${_SENTRY_PLATFORM_LIBS})
endif()
# suppress some errors and warnings for MinGW target
@ -415,88 +418,73 @@ if(SENTRY_WITH_LIBUNWINDSTACK)
endif()
if(SENTRY_BACKEND_CRASHPAD)
option(SENTRY_CRASHPAD_SYSTEM "Use system crashpad" OFF)
if(SENTRY_CRASHPAD_SYSTEM)
find_package(crashpad REQUIRED)
target_link_libraries(sentry PUBLIC crashpad::client)
if(SENTRY_BUILD_SHARED_LIBS)
set(CRASHPAD_ENABLE_INSTALL OFF CACHE BOOL "Enable crashpad installation" FORCE)
else()
# FIXME: required for cmake 3.12 and lower:
# - NEW behavior lets normal variable override option
cmake_policy(SET CMP0077 NEW)
if(SENTRY_BUILD_SHARED_LIBS)
set(CRASHPAD_ENABLE_INSTALL OFF CACHE BOOL "Enable crashpad installation" FORCE)
else()
set(CRASHPAD_ENABLE_INSTALL ON CACHE BOOL "Enable crashpad installation" FORCE)
endif()
add_subdirectory(external/crashpad crashpad_build)
set(CRASHPAD_ENABLE_INSTALL ON CACHE BOOL "Enable crashpad installation" FORCE)
endif()
add_subdirectory(external/crashpad crashpad_build)
if(CRASHPAD_WER_ENABLED)
add_dependencies(sentry crashpad::wer)
endif()
if(WIN32)
add_dependencies(sentry crashpad::wer)
endif()
# set static runtime if enabled
if(SENTRY_BUILD_RUNTIMESTATIC AND MSVC)
set_property(TARGET crashpad_client PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_compat PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_getopt PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_handler PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_handler_lib PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_minidump PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_snapshot PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_tools PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_util PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
if(CRASHPAD_WER_ENABLED)
set_property(TARGET crashpad_wer PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
set_property(TARGET crashpad_zlib PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET mini_chromium PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
# set static runtime if enabled
if(SENTRY_BUILD_RUNTIMESTATIC AND MSVC)
set_property(TARGET crashpad_client PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_compat PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_getopt PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_handler PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_handler_lib PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_minidump PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_snapshot PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_tools PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_util PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_wer PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_zlib PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET mini_chromium PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
if(DEFINED SENTRY_FOLDER)
set_target_properties(crashpad_client PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_compat PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_getopt PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_handler PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_handler_lib PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_minidump PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_snapshot PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_tools PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_util PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_zlib PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(mini_chromium PROPERTIES FOLDER ${SENTRY_FOLDER})
if(CRASHPAD_WER_ENABLED)
set_target_properties(crashpad_wer PROPERTIES FOLDER ${SENTRY_FOLDER})
endif()
endif()
if(DEFINED SENTRY_FOLDER)
set_target_properties(crashpad_client PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_compat PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_getopt PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_handler PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_handler_lib PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_minidump PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_snapshot PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_tools PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_util PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_zlib PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(mini_chromium PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_wer PROPERTIES FOLDER ${SENTRY_FOLDER})
endif()
target_link_libraries(sentry PRIVATE
$<BUILD_INTERFACE:crashpad::client>
$<INSTALL_INTERFACE:sentry_crashpad::client>
)
install(EXPORT crashpad_export NAMESPACE sentry_crashpad:: FILE sentry_crashpad-targets.cmake
DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
)
if(WIN32 AND MSVC)
sentry_install(FILES $<TARGET_PDB_FILE:crashpad_handler>
DESTINATION "${CMAKE_INSTALL_BINDIR}" OPTIONAL)
if (CRASHPAD_WER_ENABLED)
sentry_install(FILES $<TARGET_PDB_FILE:crashpad_wer>
DESTINATION "${CMAKE_INSTALL_BINDIR}" OPTIONAL)
endif()
endif()
target_link_libraries(sentry PRIVATE
$<BUILD_INTERFACE:crashpad::client>
$<INSTALL_INTERFACE:sentry_crashpad::client>
)
install(EXPORT crashpad_export NAMESPACE sentry_crashpad:: FILE sentry_crashpad-targets.cmake
DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
)
if(WIN32 AND MSVC)
sentry_install(FILES $<TARGET_PDB_FILE:crashpad_handler>
DESTINATION "${CMAKE_INSTALL_BINDIR}" OPTIONAL)
sentry_install(FILES $<TARGET_PDB_FILE:crashpad_wer>
DESTINATION "${CMAKE_INSTALL_BINDIR}" OPTIONAL)
endif()
add_dependencies(sentry crashpad::handler)
if(CRASHPAD_WER_ENABLED)
add_compile_definitions(CRASHPAD_WER_ENABLED)
endif()
elseif(SENTRY_BACKEND_BREAKPAD)
option(SENTRY_BREAKPAD_SYSTEM "Use system breakpad" OFF)
if(SENTRY_BREAKPAD_SYSTEM)
# system breakpad is using pkg-config, see `external/breakpad/breakpad-client.pc.in`
find_package(PkgConfig REQUIRED)
pkg_check_modules(BREAKPAD REQUIRED IMPORTED_TARGET breakpad-client)
target_link_libraries(sentry PUBLIC PkgConfig::BREAKPAD)
if(SENTRY_BUILD_SHARED_LIBS)
target_link_libraries(sentry PRIVATE PkgConfig::BREAKPAD)
else()
target_link_libraries(sentry PUBLIC PkgConfig::BREAKPAD)
endif()
else()
add_subdirectory(external)
target_include_directories(sentry PRIVATE
@ -579,10 +567,9 @@ if(SENTRY_BUILD_EXAMPLES)
if(MSVC)
target_compile_options(sentry_example PRIVATE $<BUILD_INTERFACE:/wd5105>)
if(CRASHPAD_WER_ENABLED)
# to test handling SEH by-passing exceptions we need to enable the control flow guard
target_compile_options(sentry_example PRIVATE $<BUILD_INTERFACE:/guard:cf>)
endif()
# to test handling SEH by-passing exceptions we need to enable the control flow guard
target_compile_options(sentry_example PRIVATE $<BUILD_INTERFACE:/guard:cf>)
endif()
# set static runtime if enabled
@ -608,4 +595,4 @@ endif()
if(SENTRY_BUILD_SHARED_LIBS)
target_link_libraries(sentry PRIVATE
"$<$<OR:$<PLATFORM_ID:Linux>,$<PLATFORM_ID:Android>>:-Wl,--build-id=sha1,--version-script=${PROJECT_SOURCE_DIR}/src/exports.map>")
endif()
endif()

View File

@ -17,6 +17,10 @@ applications, optimized for C and C++. Sentry allows to add tags, breadcrumbs
and arbitrary custom context to enrich error reports. Supports Sentry _20.6.0_
and later.
### Note <!-- omit in toc -->
Using the `sentry-native` SDK in a standalone use case is currently an experimental feature. The SDKs primary function is to fuel our other SDKs, like [`sentry-java`](https://github.com/getsentry/sentry-java) or [`sentry-unreal`](https://github.com/getsentry/sentry-unreal). Support from our side is best effort and we do what we can to respond to issues in a timely fashion, but please understand if we wont be able to address your issues or feature suggestions.
## Resources <!-- omit in toc -->
- [SDK Documentation](https://docs.sentry.io/platforms/native/)
@ -227,9 +231,9 @@ using `cmake -D BUILD_SHARED_LIBS=OFF ..`.
Sentry can use different backends depending on platform.
- **crashpad**: This uses the out-of-process crashpad handler. It is currently
only supported on Desktop OSs, and used as the default on Windows and macOS.
only supported on Desktop OSs, and used as the default on Windows, Linux and macOS.
- **breakpad**: This uses the in-process breakpad handler. It is currently
only supported on Desktop OSs, and used as the default on Linux.
only supported on Desktop OSs.
- **inproc**: A small in-process handler which is supported on all platforms,
and is used as default on Android.
- **none**: This builds `sentry-native` without a backend, so it does not handle
@ -238,12 +242,8 @@ using `cmake -D BUILD_SHARED_LIBS=OFF ..`.
- `SENTRY_INTEGRATION_QT` (Default: OFF):
Builds the Qt integration, which turns Qt log messages into breadcrumbs.
- `SENTRY_BREAKPAD_SYSTEM` / `SENTRY_CRASHPAD_SYSTEM` (Default: OFF):
This instructs the build system to use system-installed breakpad or crashpad
libraries instead of using the in-tree version. This is generally not recommended
for crashpad, as sentry uses a patched version that has attachment support.
This is being worked on upstream as well, and a future version might work with
an unmodified crashpad version as well.
- `SENTRY_BREAKPAD_SYSTEM` (Default: OFF):
This instructs the build system to use system-installed breakpad libraries instead of using the in-tree version.
| Feature | Windows | macOS | Linux | Android | iOS |
| ---------- | ------- | ----- | ----- | ------- | --- |

View File

@ -9,17 +9,21 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef NDEBUG
# undef NDEBUG
#endif
#include <assert.h>
#ifdef SENTRY_PLATFORM_WINDOWS
# include <synchapi.h>
# define sleep_s(SECONDS) Sleep((SECONDS)*1000)
#else
# include <signal.h>
# include <unistd.h>
# define sleep_s(SECONDS) sleep(SECONDS)
#endif
@ -93,7 +97,9 @@ has_arg(int argc, char **argv, const char *arg)
return false;
}
#ifdef CRASHPAD_WER_ENABLED
#if defined(SENTRY_PLATFORM_WINDOWS) && !defined(__MINGW32__) \
&& !defined(__MINGW64__)
int
call_rffe_many_times()
{
@ -138,7 +144,7 @@ trigger_fastfail_crash()
__fastfail(77);
}
#endif // CRASHPAD_WER_ENABLED
#endif
#ifdef SENTRY_PLATFORM_AIX
// AIX has a null page mapped to the bottom of memory, which means null derefs
@ -258,6 +264,21 @@ main(int argc, char **argv)
debug_crumb, "category", sentry_value_new_string("example!"));
sentry_value_set_by_key(
debug_crumb, "level", sentry_value_new_string("debug"));
// extend the `http` crumb with (optional) data properties as documented
// here:
// https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/#breadcrumb-types
sentry_value_t http_data = sentry_value_new_object();
sentry_value_set_by_key(http_data, "url",
sentry_value_new_string("https://example.com/api/1.0/users"));
sentry_value_set_by_key(
http_data, "method", sentry_value_new_string("GET"));
sentry_value_set_by_key(
http_data, "status_code", sentry_value_new_int32(200));
sentry_value_set_by_key(
http_data, "reason", sentry_value_new_string("OK"));
sentry_value_set_by_key(debug_crumb, "data", http_data);
sentry_add_breadcrumb(debug_crumb);
sentry_value_t nl_crumb
@ -301,7 +322,8 @@ main(int argc, char **argv)
if (has_arg(argc, argv, "crash")) {
trigger_crash();
}
#ifdef CRASHPAD_WER_ENABLED
#if defined(SENTRY_PLATFORM_WINDOWS) && !defined(__MINGW32__) \
&& !defined(__MINGW64__)
if (has_arg(argc, argv, "fastfail")) {
trigger_fastfail_crash();
}
@ -343,6 +365,16 @@ main(int argc, char **argv)
sentry_capture_event(event);
}
if (has_arg(argc, argv, "capture-user-feedback")) {
sentry_value_t event = sentry_value_new_message_event(
SENTRY_LEVEL_INFO, "my-logger", "Hello user feedback!");
sentry_uuid_t event_id = sentry_capture_event(event);
sentry_value_t user_feedback = sentry_value_new_user_feedback(
&event_id, "some-name", "some-email", "some-comment");
sentry_capture_user_feedback(user_feedback);
}
if (has_arg(argc, argv, "capture-transaction")) {
sentry_transaction_context_t *tx_ctx

View File

@ -34,6 +34,18 @@ jobs:
cmake -B cmake-build-stacks -D CRASHPAD_ENABLE_STACKTRACE=ON
cmake --build cmake-build-stacks --parallel
- name: Build crashpad Windows ARM64
if: ${{ runner.os == 'Windows' }}
run: |
cmake -B cmake-build-arm64 -DCMAKE_TOOLCHAIN_FILE="cmake/toolchains/win_arm64.cmake" -DCRASHPAD_BUILD_TOOLS=On
cmake --build cmake-build-arm64 --config RelWithDebInfo -- /p:Platform=ARM64
- name: Build crashpad with client-side stack traces Windows ARM64
if: ${{ runner.os == 'Windows' }}
run: |
cmake -B cmake-build-stacks-arm64 -DCMAKE_TOOLCHAIN_FILE="cmake/toolchains/win_arm64.cmake" -DCRASHPAD_ENABLE_STACKTRACE=ON
cmake --build cmake-build-stacks-arm64 --config RelWithDebInfo -- /p:Platform=ARM64
build-ios:
runs-on: macos-latest
steps:

View File

@ -21,7 +21,7 @@ else()
endif()
option(CRASHPAD_ZLIB_SYSTEM "Use system zlib library" "${CRASHPAD_ZLIB_SYSTEM_DEFAULT}")
if(CRASHPAD_ZLIB_SYSTEM)
if(CRASHPAD_ZLIB_SYSTEM AND NOT ZLIB_FOUND)
find_package(ZLIB REQUIRED)
endif()
@ -50,7 +50,11 @@ function(crashpad_install_dev)
endfunction()
if(WIN32)
enable_language(ASM_MASM)
if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES ARM64)
enable_language(ASM_MARMASM)
else()
enable_language(ASM_MASM)
endif()
if(MINGW)
find_program(JWASM_FOUND jwasm)
@ -119,24 +123,10 @@ if(MSVC)
$<$<COMPILE_LANGUAGE:C,CXX>:/wd4577> # 'noexcept' used with no exception handling mode specified.
$<$<COMPILE_LANGUAGE:C,CXX>:/wd4996> # 'X' was declared deprecated.
)
# WER support is only available starting from Win10 build 10941
if("${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}" VERSION_LESS 10.0.19041)
message(STATUS "WER support disabled. Needs target platform >= 10.0.19041 (actual: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})")
else()
SET(CRASHPAD_WER_ENABLED TRUE)
SET(CRASHPAD_WER_ENABLED TRUE PARENT_SCOPE)
message(STATUS "WER support enabled")
endif()
elseif(MINGW)
# redirect to wmain
# FIXME: cmake 3.13 added target_link_options
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode")
if(CRASHPAD_WER_ENABLED)
message(STATUS "WER support enabled")
else()
message(STATUS "WER support disabled. Define CRASHPAD_WER_ENABLED = TRUE to enable.")
endif()
endif()
add_library(crashpad::interface ALIAS crashpad_interface)

View File

@ -47,13 +47,13 @@ deps = {
'9719c1e1e676814c456b55f5f070eabad6709d31',
'crashpad/third_party/mini_chromium/mini_chromium':
Var('chromium_git') + '/chromium/mini_chromium@' +
'10f39a97650a0fe0b305415c15434443c0690a20',
'9e21183c1ea369398d6f6ddd302c8db580bd19c4',
'crashpad/third_party/libfuzzer/src':
Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' +
'fda403cf93ecb8792cb1d061564d89a6553ca020',
'crashpad/third_party/zlib/zlib':
Var('chromium_git') + '/chromium/src/third_party/zlib@' +
'13dc246a58e4b72104d35f9b1809af95221ebda7',
'fef58692c1d7bec94c4ed3d030a45a1832a9615d',
# CIPD packages.
'buildtools/linux64': {
@ -89,8 +89,8 @@ deps = {
'crashpad/third_party/linux/clang/linux-amd64': {
'packages': [
{
'package': 'fuchsia/clang/linux-amd64',
'version': 'goma',
'package': 'fuchsia/third_party/clang/linux-amd64',
'version': 'Tpc85d1ZwSlZ6UKl2d96GRUBGNA5JKholOKe24sRDr0C',
},
],
'condition': 'checkout_linux and pull_linux_clang',
@ -99,8 +99,8 @@ deps = {
'crashpad/third_party/fuchsia/clang/mac-amd64': {
'packages': [
{
'package': 'fuchsia/clang/mac-amd64',
'version': 'goma',
'package': 'fuchsia/third_party/clang/mac-amd64',
'version': 'MAOjNhwTu5JU3P_0C9dITiyCTtQ1n7lRJnMfB9hhvOkC',
},
],
'condition': 'checkout_fuchsia and host_os == "mac"',
@ -109,8 +109,8 @@ deps = {
'crashpad/third_party/fuchsia/clang/linux-amd64': {
'packages': [
{
'package': 'fuchsia/clang/linux-amd64',
'version': 'goma',
'package': 'fuchsia/third_party/clang/linux-amd64',
'version': 'Tpc85d1ZwSlZ6UKl2d96GRUBGNA5JKholOKe24sRDr0C',
},
],
'condition': 'checkout_fuchsia and host_os == "linux"',

View File

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>${IOS_BUNDLE_ID_PREFIX}.googletest.${GTEST_BUNDLE_ID_SUFFIX:rfc1034identifier}</string>
<string>${IOS_BUNDLE_ID_PREFIX}.${GTEST_BUNDLE_ID_SUFFIX:rfc1034identifier}</string>
<key>UIApplicationDelegate</key>
<string>CrashpadUnitTestDelegate</string>
</dict>

View File

@ -246,6 +246,14 @@ class Annotation {
std::atomic<Annotation*>& link_node() { return link_node_; }
Annotation* GetLinkNode(std::memory_order order = std::memory_order_seq_cst) {
return link_node_.load(order);
}
const Annotation* GetLinkNode(
std::memory_order order = std::memory_order_seq_cst) const {
return link_node_.load(order);
}
private:
//! \brief Linked list next-node pointer. Accessed only by \sa AnnotationList.
//!
@ -323,9 +331,11 @@ class StringAnnotation : public Annotation {
void Set(base::StringPiece string) {
Annotation::ValueSizeType size =
std::min(MaxSize, base::saturated_cast<ValueSizeType>(string.size()));
memcpy(value_, string.data(), size);
string = string.substr(0, size);
std::copy(string.begin(), string.end(), value_);
// Check for no embedded `NUL` characters.
DCHECK(!memchr(value_, '\0', size)) << "embedded NUL";
DCHECK(string.find('\0', /*pos=*/0) == base::StringPiece::npos)
<< "embedded NUL";
SetSize(size);
}

View File

@ -77,7 +77,7 @@ Annotation* AnnotationList::Iterator::operator*() const {
AnnotationList::Iterator& AnnotationList::Iterator::operator++() {
CHECK_NE(curr_, tail_);
curr_ = curr_->link_node();
curr_ = curr_->GetLinkNode();
return *this;
}
@ -86,12 +86,42 @@ bool AnnotationList::Iterator::operator==(
return curr_ == other.curr_;
}
AnnotationList::ConstIterator::ConstIterator(const Annotation* head,
const Annotation* tail)
: curr_(head), tail_(tail) {}
AnnotationList::ConstIterator::~ConstIterator() = default;
const Annotation* AnnotationList::ConstIterator::operator*() const {
CHECK_NE(curr_, tail_);
return curr_;
}
AnnotationList::ConstIterator& AnnotationList::ConstIterator::operator++() {
CHECK_NE(curr_, tail_);
curr_ = curr_->GetLinkNode();
return *this;
}
bool AnnotationList::ConstIterator::operator==(
const AnnotationList::ConstIterator& other) const {
return curr_ == other.curr_;
}
AnnotationList::Iterator AnnotationList::begin() {
return Iterator(head_.link_node(), tail_pointer_);
return Iterator(head_.GetLinkNode(), tail_pointer_);
}
AnnotationList::ConstIterator AnnotationList::cbegin() const {
return ConstIterator(head_.GetLinkNode(), tail_pointer_);
}
AnnotationList::Iterator AnnotationList::end() {
return Iterator(&tail_, tail_pointer_);
}
AnnotationList::ConstIterator AnnotationList::cend() const {
return ConstIterator(&tail_, tail_pointer_);
}
} // namespace crashpad

View File

@ -80,11 +80,37 @@ class AnnotationList {
// Copy and assign are required.
};
//! \brief An InputIterator for iterating a const AnnotationList.
class ConstIterator {
public:
~ConstIterator();
const Annotation* operator*() const;
ConstIterator& operator++();
bool operator==(const ConstIterator& other) const;
bool operator!=(const ConstIterator& other) const {
return !(*this == other);
}
private:
friend class AnnotationList;
ConstIterator(const Annotation* head, const Annotation* tail);
const Annotation* curr_;
const Annotation* const tail_;
// Copy and assign are required.
};
//! \brief Returns an iterator to the first element of the annotation list.
Iterator begin();
ConstIterator begin() const { return cbegin(); }
ConstIterator cbegin() const;
//! \brief Returns an iterator past the last element of the annotation list.
Iterator end();
ConstIterator end() const { return cend(); }
ConstIterator cend() const;
protected:
#if BUILDFLAG(IS_IOS)

View File

@ -128,6 +128,100 @@ TEST_F(AnnotationList, DuplicateKeys) {
EXPECT_EQ(1u, annotations.size());
}
TEST_F(AnnotationList, IteratorSingleAnnotation) {
ASSERT_EQ(annotations_.begin(), annotations_.end());
ASSERT_EQ(annotations_.cbegin(), annotations_.cend());
one_.Set("1");
auto iterator = annotations_.begin();
auto const_iterator = annotations_.cbegin();
ASSERT_NE(iterator, annotations_.end());
ASSERT_NE(const_iterator, annotations_.cend());
EXPECT_EQ(*iterator, &one_);
EXPECT_EQ(*const_iterator, &one_);
++iterator;
++const_iterator;
EXPECT_EQ(iterator, annotations_.end());
EXPECT_EQ(const_iterator, annotations_.cend());
}
TEST_F(AnnotationList, IteratorMultipleAnnotationsInserted) {
ASSERT_EQ(annotations_.begin(), annotations_.end());
ASSERT_EQ(annotations_.cbegin(), annotations_.cend());
one_.Set("1");
two_.Set("2");
// New annotations are inserted to the beginning of the list. Hence, |two_|
// must be the first annotation, followed by |one_|.
{
auto iterator = annotations_.begin();
auto const_iterator = annotations_.cbegin();
ASSERT_NE(iterator, annotations_.end());
ASSERT_NE(const_iterator, annotations_.cend());
EXPECT_EQ(*iterator, &two_);
EXPECT_EQ(*const_iterator, &two_);
++iterator;
++const_iterator;
ASSERT_NE(iterator, annotations_.end());
ASSERT_NE(const_iterator, annotations_.cend());
EXPECT_EQ(*iterator, &one_);
EXPECT_EQ(*const_iterator, &one_);
++iterator;
++const_iterator;
EXPECT_EQ(iterator, annotations_.end());
EXPECT_EQ(const_iterator, annotations_.cend());
}
}
TEST_F(AnnotationList, IteratorMultipleAnnotationsInsertedAndRemoved) {
ASSERT_EQ(annotations_.begin(), annotations_.end());
ASSERT_EQ(annotations_.cbegin(), annotations_.cend());
one_.Set("1");
two_.Set("2");
one_.Clear();
two_.Clear();
// Even after clearing, Annotations are still inserted in the list and
// reachable via the iterators.
auto iterator = annotations_.begin();
auto const_iterator = annotations_.cbegin();
ASSERT_NE(iterator, annotations_.end());
ASSERT_NE(const_iterator, annotations_.cend());
EXPECT_EQ(*iterator, &two_);
EXPECT_EQ(*const_iterator, &two_);
++iterator;
++const_iterator;
ASSERT_NE(iterator, annotations_.end());
ASSERT_NE(const_iterator, annotations_.cend());
EXPECT_EQ(*iterator, &one_);
EXPECT_EQ(*const_iterator, &one_);
++iterator;
++const_iterator;
EXPECT_EQ(iterator, annotations_.end());
EXPECT_EQ(const_iterator, annotations_.cend());
}
class RaceThread : public Thread {
public:
explicit RaceThread(test::AnnotationList* test) : Thread(), test_(test) {}

View File

@ -22,6 +22,7 @@
#include <tuple>
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "client/settings.h"

View File

@ -34,8 +34,8 @@
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/scoped_generic.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "client/settings.h"
#include "util/file/directory_reader.h"
@ -116,9 +116,9 @@ bool CreateOrEnsureDirectoryExists(const base::FilePath& path) {
// have changed, and new_name determines whether the returned xattr name will be
// the old name or its new equivalent.
std::string XattrNameInternal(const base::StringPiece& name, bool new_name) {
return base::StringPrintf(new_name ? "org.chromium.crashpad.database.%s"
: "com.googlecode.crashpad.%s",
name.data());
return base::StrCat({new_name ? "org.chromium.crashpad.database."
: "com.googlecode.crashpad.",
name});
}
} // namespace

View File

@ -25,6 +25,7 @@
#include <tuple>
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "base/strings/utf_string_conversions.h"
@ -545,8 +546,7 @@ void Metadata::Write() {
for (const auto& report : reports_) {
const base::FilePath& path = report.file_path;
if (path.DirName() != report_dir_) {
LOG(ERROR) << path.value().c_str() << " expected to start with "
<< base::WideToUTF8(report_dir_.value());
LOG(ERROR) << path << " expected to start with " << report_dir_;
return;
}
records.push_back(MetadataFileReportRecord(report, &string_table));
@ -590,12 +590,11 @@ OperationStatus Metadata::VerifyReport(const ReportDisk& report_disk,
bool EnsureDirectory(const base::FilePath& path) {
DWORD fileattr = GetFileAttributes(path.value().c_str());
if (fileattr == INVALID_FILE_ATTRIBUTES) {
PLOG(ERROR) << "GetFileAttributes " << base::WideToUTF8(path.value());
PLOG(ERROR) << "GetFileAttributes " << path;
return false;
}
if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
LOG(ERROR) << "GetFileAttributes " << base::WideToUTF8(path.value())
<< ": not a directory";
LOG(ERROR) << "GetFileAttributes " << path << ": not a directory";
return false;
}
return true;
@ -877,7 +876,7 @@ OperationStatus CrashReportDatabaseWin::DeleteReport(const UUID& uuid) {
return os;
if (!DeleteFile(report_path.value().c_str())) {
PLOG(ERROR) << "DeleteFile " << base::WideToUTF8(report_path.value());
PLOG(ERROR) << "DeleteFile " << report_path;
return kFileSystemError;
}
@ -1021,8 +1020,7 @@ void CrashReportDatabaseWin::CleanOrphanedAttachments() {
if (IsDirectory(path, false)) {
UUID uuid;
if (!uuid.InitializeFromString(filename.value())) {
LOG(ERROR) << "unexpected attachment dir name "
<< filename.value().c_str();
LOG(ERROR) << "unexpected attachment dir name " << filename;
continue;
}

View File

@ -835,11 +835,17 @@ class CrashpadClient {
#endif
private:
#if BUILDFLAG(IS_WIN)
//! \brief Registers process handlers for the client.
void RegisterHandlers();
#endif
#if BUILDFLAG(IS_APPLE)
base::apple::ScopedMachSendRight exception_port_;
#elif BUILDFLAG(IS_WIN)
std::wstring ipc_pipe_;
ScopedKernelHANDLE handler_start_thread_;
ScopedVectoredExceptionRegistration vectored_handler_;
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
std::set<int> unhandled_signals_;
#endif // BUILDFLAG(IS_APPLE)

View File

@ -20,6 +20,7 @@
#include <lib/zx/process.h>
#include <zircon/processargs.h>
#include "base/check_op.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
#include "client/client_argv_handling.h"

View File

@ -30,6 +30,7 @@
#include <atomic>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"

View File

@ -25,6 +25,7 @@
#include <utility>
#include "base/apple/mach_logging.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "util/mac/mac_util.h"

View File

@ -23,8 +23,10 @@
#include <string.h>
#include <memory>
#include <string_view>
#include "base/atomicops.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "base/scoped_generic.h"
#include "base/strings/stringprintf.h"
@ -203,6 +205,7 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
return EXCEPTION_CONTINUE_SEARCH;
}
#if !defined(ADDRESS_SANITIZER)
LONG WINAPI HandleHeapCorruption(EXCEPTION_POINTERS* exception_pointers) {
if (exception_pointers->ExceptionRecord->ExceptionCode ==
STATUS_HEAP_CORRUPTION) {
@ -211,6 +214,7 @@ LONG WINAPI HandleHeapCorruption(EXCEPTION_POINTERS* exception_pointers) {
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
void HandleAbortSignal(int signum) {
DCHECK_EQ(signum, SIGABRT);
@ -537,7 +541,7 @@ bool StartHandlerProcess(
// invalid command line where the first argument needed by rundll32 is not in
// the correct format as required in:
// https://support.microsoft.com/en-ca/help/164787/info-windows-rundll-and-rundll32-interface
const base::WStringPiece kRunDll32Exe(L"rundll32.exe");
const std::wstring_view kRunDll32Exe(L"rundll32.exe");
bool is_embedded_in_dll = false;
if (data->handler.value().size() >= kRunDll32Exe.size() &&
_wcsicmp(data->handler.value()
@ -609,45 +613,10 @@ void CommonInProcessInitialization() {
g_non_crash_dump_lock = new base::Lock();
}
void RegisterHandlers() {
SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
// Windows swallows heap corruption failures but we can intercept them with
// a vectored exception handler.
#if defined(ADDRESS_SANITIZER)
// Let ASAN have first go.
bool go_first = false;
#else
bool go_first = true;
#endif
AddVectoredExceptionHandler(go_first, HandleHeapCorruption);
// The Windows CRT's signal.h lists:
// - SIGINT
// - SIGILL
// - SIGFPE
// - SIGSEGV
// - SIGTERM
// - SIGBREAK
// - SIGABRT
// SIGILL and SIGTERM are documented as not being generated. SIGBREAK and
// SIGINT are for Ctrl-Break and Ctrl-C, and aren't something for which
// capturing a dump is warranted. SIGFPE and SIGSEGV are captured as regular
// exceptions through the unhandled exception filter. This leaves SIGABRT. In
// the standard CRT, abort() is implemented as a synchronous call to the
// SIGABRT signal handler if installed, but after doing so, the unhandled
// exception filter is not triggered (it instead __fastfail()s). So, register
// to handle SIGABRT to catch abort() calls, as client code might use this and
// expect it to cause a crash dump. This will only work when the abort()
// that's called in client code is the same (or has the same behavior) as the
// one in use here.
void (*rv)(int) = signal(SIGABRT, HandleAbortSignal);
DCHECK_NE(rv, SIG_ERR);
}
} // namespace
CrashpadClient::CrashpadClient() : ipc_pipe_(), handler_start_thread_() {}
CrashpadClient::CrashpadClient()
: ipc_pipe_(), handler_start_thread_(), vectored_handler_() {}
CrashpadClient::~CrashpadClient() {}
@ -723,6 +692,42 @@ bool CrashpadClient::StartHandler(
}
}
void CrashpadClient::RegisterHandlers() {
SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
// Windows swallows heap corruption failures but we can intercept them with
// a vectored exception handler. Note that a vectored exception handler is
// not compatible with or generally helpful in ASAN builds (ASAN inserts a
// bad dereference at the beginning of the handler, leading to recursive
// invocation of the handler).
#if !defined(ADDRESS_SANITIZER)
PVOID handler = AddVectoredExceptionHandler(true, HandleHeapCorruption);
vectored_handler_.reset(handler);
#endif
// The Windows CRT's signal.h lists:
// - SIGINT
// - SIGILL
// - SIGFPE
// - SIGSEGV
// - SIGTERM
// - SIGBREAK
// - SIGABRT
// SIGILL and SIGTERM are documented as not being generated. SIGBREAK and
// SIGINT are for Ctrl-Break and Ctrl-C, and aren't something for which
// capturing a dump is warranted. SIGFPE and SIGSEGV are captured as regular
// exceptions through the unhandled exception filter. This leaves SIGABRT. In
// the standard CRT, abort() is implemented as a synchronous call to the
// SIGABRT signal handler if installed, but after doing so, the unhandled
// exception filter is not triggered (it instead __fastfail()s). So, register
// to handle SIGABRT to catch abort() calls, as client code might use this and
// expect it to cause a crash dump. This will only work when the abort()
// that's called in client code is the same (or has the same behavior) as the
// one in use here.
void (*rv)(int) = signal(SIGABRT, HandleAbortSignal);
DCHECK_NE(rv, SIG_ERR);
}
bool CrashpadClient::SetHandlerIPCPipe(const std::wstring& ipc_pipe) {
DCHECK(ipc_pipe_.empty());
DCHECK(!ipc_pipe.empty());

View File

@ -324,6 +324,20 @@ bool ModulePathMatchesSinkhole(const char* path, const char* sinkhole) {
#endif
}
//! \brief Helper to release memory from calls to __cxa_allocate_exception.
class ScopedException {
public:
explicit ScopedException(objc_exception* exception) : exception_(exception) {}
ScopedException(const ScopedException&) = delete;
ScopedException& operator=(const ScopedException&) = delete;
~ScopedException() { __cxxabiv1::__cxa_free_exception(exception_); }
private:
objc_exception* exception_; // weak
};
id ObjcExceptionPreprocessor(id exception) {
// Some sinkholes don't use objc_exception_rethrow when they should, which
// would otherwise prevent the exception_preprocessor from getting called
@ -384,6 +398,7 @@ id ObjcExceptionPreprocessor(id exception) {
// From 10.15.0 objc4-779.1/runtime/objc-exception.mm objc_exception_throw.
objc_exception* exception_objc = reinterpret_cast<objc_exception*>(
__cxxabiv1::__cxa_allocate_exception(sizeof(objc_exception)));
ScopedException exception_objc_owner(exception_objc);
exception_objc->obj = exception;
exception_objc->tinfo.vtable = objc_ehtype_vtable + 2;
exception_objc->tinfo.name = object_getClassName(exception);

View File

@ -24,6 +24,7 @@
#include <iterator>
#include <optional>
#include "base/check_op.h"
#include "build/build_config.h"
#include "snapshot/snapshot_constants.h"
#include "util/ios/ios_intermediate_dump_writer.h"

View File

@ -15,6 +15,7 @@
#include <dlfcn.h>
#include <pthread.h>
#include "base/check.h"
#include "base/logging.h"
#include "client/crashpad_client.h"
#include "util/misc/no_cfi_icall.h"

View File

@ -0,0 +1,6 @@
# Toolchain file that should provide required and non-conflicting build-
# parameters to allow normal and cross-compilation to ARM64 targets on
# Windows using any generator.
SET(CMAKE_GENERATOR_PLATFORM "ARM64")
SET(CMAKE_SYSTEM_PROCESSOR "ARM64")
SET(CMAKE_SYSTEM_NAME "Windows")

View File

@ -123,7 +123,7 @@ if(NOT IOS)
)
endif()
if(CRASHPAD_WER_ENABLED)
if (WIN32)
add_library(crashpad_wer SHARED
win/wer/crashpad_wer.cc
win/wer/crashpad_wer.h
@ -147,4 +147,4 @@ if(CRASHPAD_WER_ENABLED)
install(TARGETS crashpad_wer EXPORT crashpad_export
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
endif()
endif()

View File

@ -25,6 +25,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"

View File

@ -253,7 +253,10 @@ class ExceptionHandlerServerTest : public testing::TestWithParam<bool> {
pid_t last_client;
ASSERT_TRUE(server_test_->Delegate()->WaitForException(
5.0, &last_client, &last_address));
EXPECT_EQ(last_address, info.exception_information_address);
// `exception_information_address` is underaligned and `EXPECT_EQ`
// internally takes arguments by reference. Copy it into a temporary
// before comparing to avoid undefined behavior.
EXPECT_EQ(last_address, VMAddress{info.exception_information_address});
EXPECT_EQ(last_client, ChildPID());
} else {
CheckedReadFileAtEOF(ReadPipeHandle());

View File

@ -17,6 +17,7 @@
#include <utility>
#include "base/apple/mach_logging.h"
#include "base/check.h"
#include "base/logging.h"
#include "util/mach/composite_mach_message_server.h"
#include "util/mach/mach_extensions.h"

View File

@ -115,7 +115,7 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException(
for (const auto& attachment : (*attachments_)) {
FileReader file_reader;
if (!file_reader.Open(attachment)) {
LOG(ERROR) << "attachment " << attachment.value().c_str()
LOG(ERROR) << "attachment " << attachment
<< " couldn't be opened, skipping";
continue;
}
@ -124,7 +124,7 @@ unsigned int CrashReportExceptionHandler::ExceptionHandlerServerException(
FileWriter* file_writer =
new_report->AddAttachment(base::WideToUTF8(filename.value()));
if (file_writer == nullptr) {
LOG(ERROR) << "attachment " << filename.value().c_str()
LOG(ERROR) << "attachment " << filename
<< " couldn't be created, skipping";
continue;
}

View File

@ -25,6 +25,7 @@
#include <type_traits>
#include <vector>
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "build/build_config.h"

View File

@ -14,6 +14,7 @@
#include <string.h>
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "client/crashpad_client.h"

View File

@ -17,6 +17,7 @@
#include <iterator>
#include "base/check.h"
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/notreached.h"

View File

@ -14,6 +14,7 @@
#include <string.h>
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "client/crashpad_client.h"

View File

@ -16,6 +16,7 @@
#include <memory>
#include "base/check_op.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"

View File

@ -14,6 +14,7 @@
#include "minidump/minidump_byte_array_writer.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"

View File

@ -19,6 +19,7 @@
#include <stdint.h>
#include <string.h>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "build/build_config.h"

View File

@ -16,6 +16,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "minidump/minidump_crashpad_info_writer.h"
#include "minidump/minidump_exception_writer.h"

View File

@ -16,6 +16,7 @@
#include <string>
#include "base/check_op.h"
#include "base/logging.h"
#include "minidump/minidump_extensions.h"
#include "util/file/file_writer.h"

View File

@ -19,6 +19,7 @@
#include <utility>
#include "base/auto_reset.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"

View File

@ -145,7 +145,7 @@ class MinidumpMiscInfoWriter final : public internal::MinidumpStreamWriter {
//! \brief Conversion functions from a native UTF16 C-string to a char16_t
//! C-string. No-op where the native UTF16 string is std::u16string.
#if defined(WCHAR_T_IS_UTF16) || DOXYGEN
#if defined(WCHAR_T_IS_16_BIT) || DOXYGEN
inline const char16_t* AsU16CStr(const wchar_t* str) {
return reinterpret_cast<const char16_t*>(str);
}

View File

@ -178,8 +178,11 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_5>(
expected_misc_info.XStateData.SizeOfInfo);
EXPECT_EQ(observed_misc_info.XStateData.ContextSize,
expected_misc_info.XStateData.ContextSize);
EXPECT_EQ(observed_misc_info.XStateData.EnabledFeatures,
expected_misc_info.XStateData.EnabledFeatures);
// `EnabledFeatures` is underaligned and `EXPECT_EQ` internally takes
// arguments by reference. Copy it into a temporary before comparing to avoid
// undefined behavior.
EXPECT_EQ(uint64_t{observed_misc_info.XStateData.EnabledFeatures},
uint64_t{expected_misc_info.XStateData.EnabledFeatures});
for (size_t feature_index = 0;
feature_index < std::size(observed_misc_info.XStateData.Features);
++feature_index) {

View File

@ -16,6 +16,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "minidump/minidump_annotation_writer.h"
#include "minidump/minidump_simple_string_dictionary_writer.h"

View File

@ -19,6 +19,7 @@
#include <limits>
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "minidump/minidump_string_writer.h"

View File

@ -16,6 +16,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"

View File

@ -16,6 +16,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"

View File

@ -6,6 +6,7 @@
#include <limits>
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "snapshot/exception_snapshot.h"
#include "snapshot/thread_snapshot.h"

View File

@ -16,6 +16,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "minidump/minidump_writer_util.h"
#include "util/file/file_writer.h"

View File

@ -16,6 +16,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "minidump/minidump_thread_id_map.h"
#include "snapshot/thread_snapshot.h"

View File

@ -16,6 +16,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "minidump/minidump_context_writer.h"
#include "minidump/minidump_memory_writer.h"

View File

@ -17,6 +17,7 @@
#include <limits>
#include <utility>
#include "base/check_op.h"
#include "minidump/minidump_writer_util.h"
#include "util/file/file_writer.h"
#include "util/numeric/in_range_cast.h"

View File

@ -18,6 +18,7 @@
#include <iterator>
#include "base/check_op.h"
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"

View File

@ -21,6 +21,7 @@
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "build/build_config.h"

View File

@ -18,6 +18,7 @@
#include <link.h>
#include <zircon/syscalls.h>
#include "base/check_op.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
#include "util/fuchsia/koid_utilities.h"

View File

@ -15,6 +15,7 @@
#include "snapshot/ios/exception_snapshot_ios_intermediate_dump.h"
#include "base/apple/mach_logging.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "snapshot/cpu_context.h"
#include "snapshot/ios/intermediate_dump_reader_util.h"

View File

@ -14,6 +14,8 @@
#include "snapshot/ios/memory_snapshot_ios_intermediate_dump.h"
#include "base/check_op.h"
namespace crashpad {
namespace internal {

View File

@ -20,6 +20,7 @@
#include <algorithm>
#include "base/check_op.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/notreached.h"

View File

@ -22,6 +22,7 @@
#include <limits>
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "client/crashpad_info.h"

View File

@ -20,6 +20,7 @@
#include <utility>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
@ -39,38 +40,26 @@ std::string SizeLimitedCString(const char* c_string, size_t max_length) {
} // namespace
bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type,
const std::string& module_name,
bool* has_timestamp) {
const std::string& module_name) {
#if defined(ARCH_CPU_X86_FAMILY)
if (mach_o_file_type != MH_BUNDLE) {
return false;
}
if (module_name == "cl_kernels") {
if (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10 ||
MacOSVersionNumber() >= 10'10'00) {
if (has_timestamp) {
*has_timestamp = false;
}
return true;
}
return false;
return __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10 ||
MacOSVersionNumber() >= 10'10'00;
}
static const char kCvmsObjectPathPrefix[] =
"/private/var/db/CVMS/cvmsCodeSignObj";
if (module_name.compare(
0, strlen(kCvmsObjectPathPrefix), kCvmsObjectPathPrefix) == 0 &&
(__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_14 ||
MacOSVersionNumber() >= 10'14'00)) {
if (has_timestamp) {
*has_timestamp = true;
}
return true;
}
#endif // ARCH_CPU_X86_FAMILY
return module_name.compare(
0, strlen(kCvmsObjectPathPrefix), kCvmsObjectPathPrefix) == 0 &&
(__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_14 ||
MacOSVersionNumber() >= 10'14'00);
#else
return false;
#endif // ARCH_CPU_X86_FAMILY
}
MachOImageSegmentReader::MachOImageSegmentReader()
@ -165,9 +154,8 @@ bool MachOImageSegmentReader::Initialize(ProcessReaderMac* process_reader,
//
// https://openradar.appspot.com/20239912
if (section_segment_name != segment_name &&
!(IsMalformedCLKernelsModule(file_type, module_name, nullptr) &&
segment_name == SEG_TEXT &&
section_segment_name == "__LD" &&
!(IsMalformedCLKernelsModule(file_type, module_name) &&
segment_name == SEG_TEXT && section_segment_name == "__LD" &&
section_name == "__compact_unwind" &&
(section.flags & S_ATTR_DEBUG))) {
LOG(WARNING) << "section.segname incorrect in segment " << segment_name

View File

@ -53,18 +53,11 @@ namespace crashpad {
//! \param[in] mach_o_file_type The Mach-O type of the module being examined.
//! \param[in] module_name The pathname that `dyld` reported having loaded the
//! module from.
//! \param[out] has_timestamp Optional, may be `nullptr`. If provided, and the
//! module is a maformed `cl_kernels` module, this will be set to `true` if
//! the module was loaded from the filesystem (as is the case when loaded
//! from the CVMS directory) and is expected to have a timestamp, and
//! `false` otherwise. Note that even when loaded from the filesystem, these
//! modules are unlinked from the filesystem after loading.
//!
//! \return `true` if the module appears to be a malformed `cl_kernels` module
//! based on the provided information, `false` otherwise.
bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type,
const std::string& module_name,
bool* has_timestamp);
const std::string& module_name);
//! \brief A reader for `LC_SEGMENT` or `LC_SEGMENT_64` load commands in Mach-O
//! images mapped into another process.

View File

@ -24,6 +24,7 @@
#include "base/apple/mach_logging.h"
#include "base/apple/scoped_mach_port.h"
#include "base/apple/scoped_mach_vm.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "snapshot/mac/mach_o_image_reader.h"
@ -509,26 +510,27 @@ void ProcessReaderMac::InitializeModules() {
}
if (file_type == MH_EXECUTE) {
// On Mac OS X 10.6, the main executable does not normally show up at
// index 0. This is because of how 10.6.8 dyld-132.13/src/dyld.cpp
// notifyGDB(), the function resposible for causing
// dyld_all_image_infos::infoArray to be updated, is called. It is
// registered to be called when all dependents of an image have been
// mapped (dyld_image_state_dependents_mapped), meaning that the main
// executable wont be added to the list until all of the libraries it
// depends on are, even though dyld begins looking at the main executable
// first. This changed in later versions of dyld, including those present
// in 10.7. 10.9.4 dyld-239.4/src/dyld.cpp updateAllImages() (renamed from
// notifyGDB()) is registered to be called when an image itself has been
// mapped (dyld_image_state_mapped), regardless of the libraries that it
// depends on.
// On macOS 14, the main executable does not normally show up at
// index 0. In previous versions of dyld, each loaded image was
// appended to the all image info vector as it was loaded.
// (For example, see RuntimeState::notifyDebuggerLoad in dyld-1066.8).
// Starting from dyld-1122.1, notifyDebuggerLoad calls
// ExternallyViewableState::addImages for all but the main executable
// (which has already been added). ExternallyViewableState::addImages
// inserts all new image infos at the front of the vector, leaving the
// main executable as the last item.
//
// The interface requires that the main executable be first in the list,
// so swap it into the right position.
size_t index = modules_.size() - 1;
if (main_executable_count == 0) {
std::swap(modules_[0], modules_[index]);
} else {
if (index > 0) {
CHECK_EQ(index, image_info_vector.size() - 1);
if (main_executable_count == 0) {
std::rotate(
modules_.rbegin(), modules_.rbegin() + 1, modules_.rend());
}
}
if (main_executable_count > 0) {
LOG(WARNING) << base::StringPrintf(
"multiple MH_EXECUTE modules (%s, %s)",
modules_[0].name.c_str(),

View File

@ -28,6 +28,7 @@
#include <iterator>
#include <map>
#include <unordered_set>
#include <utility>
#include "base/apple/mach_logging.h"
@ -54,6 +55,15 @@ namespace crashpad {
namespace test {
namespace {
using ModulePathAndAddress = std::pair<std::string, mach_vm_address_t>;
struct PathAndAddressHash {
std::size_t operator()(const ModulePathAndAddress& pair) const {
return std::hash<std::string>()(pair.first) ^
std::hash<mach_vm_address_t>()(pair.second);
}
};
using ModuleSet = std::unordered_set<ModulePathAndAddress, PathAndAddressHash>;
constexpr char kDyldPath[] = "/usr/lib/dyld";
TEST(ProcessReaderMac, SelfBasic) {
@ -654,9 +664,8 @@ T GetDyldFunction(const char* symbol) {
return reinterpret_cast<T>(dlsym(dl_handle, symbol));
}
void VerifyImageExistenceAndTimestamp(const char* path, time_t timestamp) {
void VerifyImageExistence(const char* path) {
const char* stat_path;
bool timestamp_may_be_0;
#if __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_16
static auto _dyld_shared_cache_contains_path =
@ -686,18 +695,13 @@ void VerifyImageExistenceAndTimestamp(const char* path, time_t timestamp) {
}();
stat_path = dyld_shared_cache_file_path;
timestamp_may_be_0 = true;
} else {
stat_path = path;
timestamp_may_be_0 = false;
}
struct stat stat_buf;
int rv = stat(stat_path, &stat_buf);
EXPECT_EQ(rv, 0) << ErrnoMessage("stat");
if (rv == 0 && (!timestamp_may_be_0 || timestamp != 0)) {
EXPECT_EQ(timestamp, stat_buf.st_mtime);
}
}
// cl_kernels images (OpenCL kernels) are weird. Theyre not ld output and dont
@ -839,67 +843,57 @@ TEST(ProcessReaderMac, SelfModules) {
ASSERT_TRUE(process_reader.Initialize(mach_task_self()));
uint32_t dyld_image_count = _dyld_image_count();
const std::vector<ProcessReaderMac::Module>& modules =
process_reader.Modules();
// There needs to be at least an entry for the main executable, for a dylib,
// and for dyld.
ASSERT_GE(modules.size(), 3u);
// dyld_image_count doesnt include an entry for dyld itself, but |modules|
// does.
ASSERT_EQ(modules.size(), dyld_image_count + 1);
bool found_cl_kernels = false;
for (uint32_t index = 0; index < dyld_image_count; ++index) {
SCOPED_TRACE(base::StringPrintf(
"index %u, name %s", index, modules[index].name.c_str()));
const char* dyld_image_name = _dyld_get_image_name(index);
EXPECT_EQ(modules[index].name, dyld_image_name);
ASSERT_TRUE(modules[index].reader);
EXPECT_EQ(
modules[index].reader->Address(),
FromPointerCast<mach_vm_address_t>(_dyld_get_image_header(index)));
bool expect_timestamp;
if (index == 0 && MacOSVersionNumber() < 12'00'00) {
// Pre-dyld4, dyld didnt set the main executable's timestamp, and it was
// reported as 0.
EXPECT_EQ(modules[index].timestamp, 0);
} else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(),
modules[index].name,
&expect_timestamp)) {
// cl_kernels doesnt exist as a file, but may still have a timestamp.
if (!expect_timestamp) {
EXPECT_EQ(modules[index].timestamp, 0);
} else {
EXPECT_NE(modules[index].timestamp, 0);
std::set<std::string> cl_kernel_names;
auto modules = process_reader.Modules();
ModuleSet actual_modules;
for (size_t i = 0; i < modules.size(); ++i) {
auto& module = modules[i];
ASSERT_TRUE(module.reader);
if (i == modules.size() - 1) {
EXPECT_EQ(module.name, kDyldPath);
const dyld_all_image_infos* dyld_image_infos = DyldGetAllImageInfos();
if (dyld_image_infos->version >= 2) {
EXPECT_EQ(module.reader->Address(),
FromPointerCast<mach_vm_address_t>(
dyld_image_infos->dyldImageLoadAddress));
}
found_cl_kernels = true;
// Don't include dyld, since dyld image APIs will not have an entry for
// dyld itself.
continue;
}
// Ensure executable is first, and that there's only one.
uint32_t file_type = module.reader->FileType();
if (i == 0) {
EXPECT_EQ(file_type, static_cast<uint32_t>(MH_EXECUTE));
} else {
// Hope that the module didnt change on disk.
VerifyImageExistenceAndTimestamp(dyld_image_name,
modules[index].timestamp);
EXPECT_NE(file_type, static_cast<uint32_t>(MH_EXECUTE));
}
if (IsMalformedCLKernelsModule(module.reader->FileType(), module.name)) {
cl_kernel_names.insert(module.name);
}
actual_modules.insert(
std::make_pair(module.name, module.reader->Address()));
}
EXPECT_EQ(cl_kernel_names.size() > 0,
ExpectCLKernels() && ensure_cl_kernels.success());
// There needs to be at least an entry for the main executable and a dylib.
ASSERT_GE(actual_modules.size(), 2u);
ASSERT_EQ(actual_modules.size(), dyld_image_count);
ModuleSet expect_modules;
for (uint32_t index = 0; index < dyld_image_count; ++index) {
const char* dyld_image_name = _dyld_get_image_name(index);
mach_vm_address_t dyld_image_address =
FromPointerCast<mach_vm_address_t>(_dyld_get_image_header(index));
expect_modules.insert(
std::make_pair(std::string(dyld_image_name), dyld_image_address));
if (cl_kernel_names.find(dyld_image_name) == cl_kernel_names.end()) {
VerifyImageExistence(dyld_image_name);
}
}
EXPECT_EQ(found_cl_kernels, ExpectCLKernels() && ensure_cl_kernels.success());
size_t index = modules.size() - 1;
EXPECT_EQ(modules[index].name, kDyldPath);
// dyld didnt load itself either, so it couldnt record its timestamp, and it
// is also reported as 0.
EXPECT_EQ(modules[index].timestamp, 0);
const dyld_all_image_infos* dyld_image_infos = DyldGetAllImageInfos();
if (dyld_image_infos->version >= 2) {
ASSERT_TRUE(modules[index].reader);
EXPECT_EQ(modules[index].reader->Address(),
FromPointerCast<mach_vm_address_t>(
dyld_image_infos->dyldImageLoadAddress));
}
EXPECT_EQ(actual_modules, expect_modules);
}
class ProcessReaderModulesChild final : public MachMultiprocess {
@ -918,27 +912,45 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
void MachMultiprocessParent() override {
ProcessReaderMac process_reader;
ASSERT_TRUE(process_reader.Initialize(ChildTask()));
const std::vector<ProcessReaderMac::Module>& modules =
process_reader.Modules();
ModuleSet actual_modules;
std::set<std::string> cl_kernel_names;
for (size_t i = 0; i < modules.size(); ++i) {
auto& module = modules[i];
ASSERT_TRUE(module.reader);
uint32_t file_type = module.reader->FileType();
if (i == 0) {
EXPECT_EQ(file_type, static_cast<uint32_t>(MH_EXECUTE));
} else if (i == modules.size() - 1) {
EXPECT_EQ(file_type, static_cast<uint32_t>(MH_DYLINKER));
} else {
EXPECT_NE(file_type, static_cast<uint32_t>(MH_EXECUTE));
EXPECT_NE(file_type, static_cast<uint32_t>(MH_DYLINKER));
}
if (IsMalformedCLKernelsModule(module.reader->FileType(), module.name)) {
cl_kernel_names.insert(module.name);
}
actual_modules.insert(
std::make_pair(module.name, module.reader->Address()));
}
// There needs to be at least an entry for the main executable, for a dylib,
// and for dyld.
ASSERT_GE(modules.size(), 3u);
ASSERT_GE(actual_modules.size(), 3u);
FileHandle read_handle = ReadPipeHandle();
uint32_t expect_modules;
uint32_t expect_modules_size;
CheckedReadFileExactly(
read_handle, &expect_modules, sizeof(expect_modules));
read_handle, &expect_modules_size, sizeof(expect_modules_size));
ASSERT_EQ(modules.size(), expect_modules);
bool found_cl_kernels = false;
for (size_t index = 0; index < modules.size(); ++index) {
SCOPED_TRACE(base::StringPrintf(
"index %zu, name %s", index, modules[index].name.c_str()));
ASSERT_EQ(actual_modules.size(), expect_modules_size);
ModuleSet expect_modules;
for (size_t index = 0; index < expect_modules_size; ++index) {
uint32_t expect_name_length;
CheckedReadFileExactly(
read_handle, &expect_name_length, sizeof(expect_name_length));
@ -946,40 +958,18 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
// The NUL terminator is not read.
std::string expect_name(expect_name_length, '\0');
CheckedReadFileExactly(read_handle, &expect_name[0], expect_name_length);
EXPECT_EQ(modules[index].name, expect_name);
mach_vm_address_t expect_address;
CheckedReadFileExactly(
read_handle, &expect_address, sizeof(expect_address));
ASSERT_TRUE(modules[index].reader);
EXPECT_EQ(modules[index].reader->Address(), expect_address);
bool expect_timestamp;
if ((index == 0 && MacOSVersionNumber() < 12'00'00) ||
index == modules.size() - 1) {
// Pre-dyld4, dyld didnt set the main executable's timestamp, and it
// was reported as 0.
// The last module is dyld.
EXPECT_EQ(modules[index].timestamp, 0);
} else if (IsMalformedCLKernelsModule(modules[index].reader->FileType(),
modules[index].name,
&expect_timestamp)) {
// cl_kernels doesnt exist as a file, but may still have a timestamp.
if (!expect_timestamp) {
EXPECT_EQ(modules[index].timestamp, 0);
} else {
EXPECT_NE(modules[index].timestamp, 0);
}
found_cl_kernels = true;
} else {
// Hope that the module didnt change on disk.
VerifyImageExistenceAndTimestamp(expect_name.c_str(),
modules[index].timestamp);
expect_modules.insert(std::make_pair(expect_name, expect_address));
if (cl_kernel_names.find(expect_name) == cl_kernel_names.end()) {
VerifyImageExistence(expect_name.c_str());
}
}
EXPECT_EQ(found_cl_kernels,
EXPECT_EQ(cl_kernel_names.size() > 0,
ExpectCLKernels() && ensure_cl_kernels_success_);
EXPECT_EQ(expect_modules, actual_modules);
}
void MachMultiprocessChild() override {

View File

@ -17,6 +17,7 @@
#include <stddef.h>
#include <string.h>
#include "base/check_op.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "minidump/minidump_extensions.h"

View File

@ -346,7 +346,7 @@ bool ProcessSnapshotMinidump::InitializeMiscInfo() {
switch (stream_it->second->DataSize) {
case sizeof(MINIDUMP_MISC_INFO_5):
case sizeof(MINIDUMP_MISC_INFO_4):
#if defined(WCHAR_T_IS_UTF16)
#if defined(WCHAR_T_IS_16_BIT)
full_version_ = base::WideToUTF8(info.BuildString);
#else
full_version_ = base::UTF16ToUTF8(info.BuildString);

View File

@ -868,8 +868,9 @@ TEST(ProcessSnapshotMinidump, ThreadsWithNames) {
}
TEST(ProcessSnapshotMinidump, System) {
const char* cpu_info = "GenuineIntel";
const uint32_t* cpu_info_bytes = reinterpret_cast<const uint32_t*>(cpu_info);
const char cpu_info[] = "GenuineIntel";
uint32_t cpu_info_bytes[3];
memcpy(cpu_info_bytes, cpu_info, sizeof(cpu_info_bytes));
StringFile string_file;
MINIDUMP_HEADER header = {};

View File

@ -14,6 +14,8 @@
#include "snapshot/sanitized/module_snapshot_sanitized.h"
#include "base/strings/pattern.h"
namespace crashpad {
namespace internal {
@ -22,7 +24,7 @@ namespace {
bool KeyIsAllowed(const std::string& name,
const std::vector<std::string>& allowed_keys) {
for (const auto& key : allowed_keys) {
if (name == key) {
if (base::MatchPattern(name, key)) {
return true;
}
}

View File

@ -53,6 +53,7 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot {
//! \param[in] allowed_annotations A list of annotations names to allow to
//! be returned by AnnotationsSimpleMap() or from this object's module
//! snapshots. If `nullptr`, all annotations will be returned.
// These annotation names support pattern matching, eg: "switch-*"
//! \param[in] allowed_memory_ranges A list of memory ranges to allow to be
//! accessible via Memory(), or `nullptr` to allow all ranges.
//! \param[in] target_module_address An address in the target process'

View File

@ -79,6 +79,8 @@ class ExceptionGenerator {
};
constexpr char kAllowedAnnotationName[] = "name_of_allowed_anno";
constexpr char kAllowedAnnotationNamePattern[] = "name_of_another_*";
constexpr char kAllowedAnnotationNamePatternActual[] = "name_of_another_anno";
constexpr char kAllowedAnnotationValue[] = "some_value";
constexpr char kNonAllowedAnnotationName[] = "non_allowed_anno";
constexpr char kNonAllowedAnnotationValue[] = "private_annotation";
@ -99,6 +101,10 @@ void ChildTestFunction() {
static StringAnnotation<32> allowed_annotation(kAllowedAnnotationName);
allowed_annotation.Set(kAllowedAnnotationValue);
static StringAnnotation<32> allowed_matched_annotation(
kAllowedAnnotationNamePatternActual);
allowed_matched_annotation.Set(kAllowedAnnotationValue);
static StringAnnotation<32> non_allowed_annotation(kNonAllowedAnnotationName);
non_allowed_annotation.Set(kNonAllowedAnnotationValue);
@ -129,11 +135,15 @@ CRASHPAD_CHILD_TEST_MAIN(ChildToBeSanitized) {
void ExpectAnnotations(ProcessSnapshot* snapshot, bool sanitized) {
bool found_allowed = false;
bool found_matched_allowed = false;
bool found_non_allowed = false;
for (auto module : snapshot->Modules()) {
for (const auto& anno : module->AnnotationObjects()) {
if (anno.name == kAllowedAnnotationName) {
found_allowed = true;
}
if (anno.name == kAllowedAnnotationNamePatternActual) {
found_matched_allowed = true;
} else if (anno.name == kNonAllowedAnnotationName) {
found_non_allowed = true;
}
@ -141,6 +151,7 @@ void ExpectAnnotations(ProcessSnapshot* snapshot, bool sanitized) {
}
EXPECT_TRUE(found_allowed);
EXPECT_TRUE(found_matched_allowed);
if (sanitized) {
EXPECT_FALSE(found_non_allowed);
} else {
@ -279,6 +290,7 @@ class SanitizeTest : public MultiprocessExec {
auto allowed_annotations = std::make_unique<std::vector<std::string>>();
allowed_annotations->push_back(kAllowedAnnotationName);
allowed_annotations->push_back(kAllowedAnnotationNamePattern);
auto allowed_memory_ranges =
std::make_unique<std::vector<std::pair<VMAddress, VMAddress>>>();

View File

@ -22,6 +22,7 @@
#include <memory>
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/utf_string_conversions.h"
@ -173,9 +174,12 @@ void DoStackWalk(ProcessReaderWin::Thread* thread,
// ctx = (LPVOID)ctx_;
// }
// TODO: we dont support this right away, maybe in the future
// #elif defined(ARCH_CPU_ARM64)
// machine_type = IMAGE_FILE_MACHINE_ARM64;
#elif defined(ARCH_CPU_ARM64)
machine_type = IMAGE_FILE_MACHINE_ARM64;
ctx = *thread->context.context<CONTEXT>();
stack_frame.AddrPC.Offset = ctx.Pc;
stack_frame.AddrFrame.Offset = ctx.Fp;
stack_frame.AddrStack.Offset = ctx.Sp;
#else
#error Unsupported Windows Arch
#endif // ARCH_CPU_X86

View File

@ -19,6 +19,7 @@
#include <algorithm>
#include <iterator>
#include <string_view>
#include <utility>
#include "base/logging.h"
@ -329,7 +330,7 @@ void ProcessSnapshotWin::InitializeUnloadedModules() {
uet.SizeOfImage,
uet.CheckSum,
uet.TimeDateStamp,
base::WideToUTF8(base::WStringPiece(
base::WideToUTF8(std::wstring_view(
uet.ImageName,
wcsnlen(uet.ImageName, std::size(uet.ImageName))))));
}

View File

@ -65,8 +65,11 @@ bundle_data("crashy_module_bundle") {
}
ios_app_bundle("ios_crash_xcuitests") {
info_plist = "Info.plist"
testonly = true
info_plist = "Info.plist"
if (crashpad_is_in_chromium) {
bundle_identifier = shared_bundle_id_for_test_apps
}
deps = [
":app_host_sources",
":crashy_module_bundle",

View File

@ -9,7 +9,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${IOS_BUNDLE_ID_PREFIX}.googletest.${EXECUTABLE_NAME:rfc1034identifier}</string>
<string>${BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

View File

@ -17,9 +17,11 @@
#include <CoreFoundation/CoreFoundation.h>
#include <malloc/malloc.h>
#include <pthread.h>
#include <limits>
#include "base/apple/mach_logging.h"
#include "base/check_op.h"
#include "client/crashpad_client.h"
#include "util/ios/raw_logging.h"

View File

@ -17,6 +17,7 @@
#include <stdlib.h>
#include <sys/stat.h>
#include "base/check.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "util/misc/paths.h"

View File

@ -20,6 +20,7 @@
#include <string>
#include <utility>
#include "base/check.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"

View File

@ -15,7 +15,7 @@ mc_append_sources(
check.h
check_op.h
compiler_specific.h
cxx17_backports.h
containers/span.h
debug/alias.cc
debug/alias.h
files/file_path.cc
@ -52,6 +52,9 @@ mc_append_sources(
scoped_generic.h
strings/pattern.cc
strings/pattern.h
strings/strcat.cc
strings/strcat.h
strings/strcat_internal.h
strings/string_number_conversions.cc
strings/string_number_conversions.h
strings/string_piece.h
@ -72,6 +75,7 @@ mc_append_sources(
third_party/icu/icu_utf.h
threading/thread_local_storage.cc
threading/thread_local_storage.h
types/cxx23_to_underlying.h
)
if(NOT MINGW)
@ -84,26 +88,7 @@ else()
)
endif()
if(APPLE AND NOT IOS)
mc_append_sources(
mac/close_nocancel.cc
mac/scoped_ioobject.h
mac/scoped_launch_data.h
apple/bridging.h
apple/foundation_util.h
apple/foundation_util.mm
apple/mach_logging.cc
apple/mach_logging.h
apple/scoped_cftyperef.h
apple/scoped_mach_port.cc
apple/scoped_mach_port.h
apple/scoped_mach_vm.cc
apple/scoped_mach_vm.h
apple/scoped_nsautorelease_pool.h
apple/scoped_nsautorelease_pool.mm
strings/sys_string_conversions_mac.mm
)
elseif(IOS)
if(APPLE)
mc_append_sources(
apple/bridging.h
apple/foundation_util.h
@ -120,6 +105,13 @@ elseif(IOS)
apple/scoped_typeref.h
strings/sys_string_conversions_mac.mm
)
if (NOT IOS)
mc_append_sources(
mac/close_nocancel.cc
mac/scoped_ioobject.h
mac/scoped_launch_data.h
)
endif()
endif()
if(WIN32)

View File

@ -14,6 +14,7 @@ static_library("base") {
"check.h",
"check_op.h",
"compiler_specific.h",
"containers/span.h",
"debug/alias.cc",
"debug/alias.h",
"files/file_path.cc",
@ -50,6 +51,9 @@ static_library("base") {
"scoped_generic.h",
"strings/pattern.cc",
"strings/pattern.h",
"strings/strcat.cc",
"strings/strcat.h",
"strings/strcat_internal.h",
"strings/string_number_conversions.cc",
"strings/string_number_conversions.h",
"strings/string_piece.h",

View File

@ -4,6 +4,8 @@
#include "base/apple/foundation_util.h"
#include "base/check.h"
#if !BUILDFLAG(IS_IOS)
extern "C" {
CFTypeID SecACLGetTypeID();

View File

@ -9,7 +9,7 @@
#include <algorithm>
#include "base/logging.h"
#include "base/check.h"
// Use ScopedMachVM to supervise ownership of pages in the current process
// through the Mach VM subsystem. Pages allocated with vm_allocate can be

View File

@ -5,7 +5,7 @@
#ifndef MINI_CHROMIUM_BASE_APPLE_SCOPED_TYPEREF_H_
#define MINI_CHROMIUM_BASE_APPLE_SCOPED_TYPEREF_H_
#include "base/logging.h"
#include "base/check.h"
#include "base/memory/scoped_policy.h"
namespace base {
@ -17,68 +17,125 @@ struct ScopedTypeRefTraits;
template <typename T, typename Traits = ScopedTypeRefTraits<T>>
class ScopedTypeRef {
public:
typedef T element_type;
using element_type = T;
ScopedTypeRef(
T object = Traits::InvalidValue(),
// Construction from underlying type
explicit constexpr ScopedTypeRef(
element_type object = Traits::InvalidValue(),
base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
: object_(object) {
if (object_ && policy == base::scoped_policy::RETAIN)
if (object_ != Traits::InvalidValue() &&
policy == base::scoped_policy::RETAIN) {
object_ = Traits::Retain(object_);
}
}
ScopedTypeRef(const ScopedTypeRef<T, Traits>& that) : object_(that.object_) {
if (object_)
// Copy construction
ScopedTypeRef(const ScopedTypeRef<T, Traits>& that) : object_(that.get()) {
if (object_ != Traits::InvalidValue()) {
object_ = Traits::Retain(object_);
}
}
~ScopedTypeRef() {
if (object_)
Traits::Release(object_);
template <typename R, typename RTraits>
ScopedTypeRef(const ScopedTypeRef<R, RTraits>& that) : object_(that.get()) {
if (object_ != Traits::InvalidValue()) {
object_ = Traits::Retain(object_);
}
}
// Copy assignment
ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& that) {
reset(that.get(), base::scoped_policy::RETAIN);
return *this;
}
[[nodiscard]] T* InitializeInto() {
DCHECK(!object_);
return &object_;
template <typename R, typename RTraits>
ScopedTypeRef& operator=(const ScopedTypeRef<R, RTraits>& that) {
reset(that.get(), base::scoped_policy::RETAIN);
return *this;
}
void reset(T object = Traits::InvalidValue(),
// Move construction
ScopedTypeRef(ScopedTypeRef<T, Traits>&& that) : object_(that.release()) {}
template <typename R, typename RTraits>
ScopedTypeRef(ScopedTypeRef<R, RTraits>&& that) : object_(that.release()) {}
// Move assignment
ScopedTypeRef& operator=(ScopedTypeRef<T, Traits>&& that) {
reset(that.release(), base::scoped_policy::ASSUME);
return *this;
}
template <typename R, typename RTraits>
ScopedTypeRef& operator=(ScopedTypeRef<R, RTraits>&& that) {
reset(that.release(), base::scoped_policy::ASSUME);
return *this;
}
// Resetting
template <typename R, typename RTraits>
void reset(const ScopedTypeRef<R, RTraits>& that) {
reset(that.get(), base::scoped_policy::RETAIN);
}
void reset(element_type object = Traits::InvalidValue(),
base::scoped_policy::OwnershipPolicy policy =
base::scoped_policy::ASSUME) {
if (object && policy == base::scoped_policy::RETAIN)
if (object != Traits::InvalidValue() &&
policy == base::scoped_policy::RETAIN) {
object = Traits::Retain(object);
if (object_)
}
if (object_ != Traits::InvalidValue()) {
Traits::Release(object_);
}
object_ = object;
}
bool operator==(T that) const { return object_ == that; }
// Destruction
bool operator!=(T that) const { return object_ != that; }
~ScopedTypeRef() {
if (object_ != Traits::InvalidValue()) {
Traits::Release(object_);
}
}
operator T() const { return object_; }
[[nodiscard]] element_type* InitializeInto() {
CHECK_EQ(object_, Traits::InvalidValue());
return &object_;
}
T get() const { return object_; }
bool operator==(const ScopedTypeRef& that) const {
return object_ == that.object_;
}
bool operator!=(const ScopedTypeRef& that) const {
return object_ != that.object_;
}
explicit operator bool() const { return object_ != Traits::InvalidValue(); }
element_type get() const { return object_; }
void swap(ScopedTypeRef& that) {
T temp = that.object_;
element_type temp = that.object_;
that.object_ = object_;
object_ = temp;
}
[[nodiscard]] T release() {
T temp = object_;
[[nodiscard]] element_type release() {
element_type temp = object_;
object_ = Traits::InvalidValue();
return temp;
}
private:
T object_;
element_type object_;
};
} // namespace apple

View File

@ -5,6 +5,7 @@
#ifndef MINI_CHROMIUM_BASE_CHECK_OP_H_
#define MINI_CHROMIUM_BASE_CHECK_OP_H_
#include "base/check.h"
#include "base/logging.h"
namespace logging {

View File

@ -0,0 +1,516 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CONTAINERS_SPAN_H_
#define BASE_CONTAINERS_SPAN_H_
#include <stddef.h>
#include <stdint.h>
#include <array>
#include <iterator>
#include <limits>
#include <type_traits>
#include <utility>
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/numerics/safe_conversions.h"
#include "base/template_util.h"
namespace base {
// [views.constants]
constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
template <typename T,
size_t Extent = dynamic_extent,
typename InternalPtrType = T*>
class span;
namespace internal {
template <size_t I>
using size_constant = std::integral_constant<size_t, I>;
template <typename T>
struct ExtentImpl : size_constant<dynamic_extent> {};
template <typename T, size_t N>
struct ExtentImpl<T[N]> : size_constant<N> {};
template <typename T, size_t N>
struct ExtentImpl<std::array<T, N>> : size_constant<N> {};
template <typename T, size_t N>
struct ExtentImpl<base::span<T, N>> : size_constant<N> {};
template <typename T>
using Extent = ExtentImpl<remove_cvref_t<T>>;
template <typename T>
struct IsSpanImpl : std::false_type {};
template <typename T, size_t Extent>
struct IsSpanImpl<span<T, Extent>> : std::true_type {};
template <typename T>
using IsNotSpan = std::negation<IsSpanImpl<std::decay_t<T>>>;
template <typename T>
struct IsStdArrayImpl : std::false_type {};
template <typename T, size_t N>
struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
template <typename T>
using IsNotStdArray = std::negation<IsStdArrayImpl<std::decay_t<T>>>;
template <typename T>
using IsNotCArray = std::negation<std::is_array<std::remove_reference_t<T>>>;
template <typename From, typename To>
using IsLegalDataConversion = std::is_convertible<From (*)[], To (*)[]>;
template <typename Container, typename T>
using ContainerHasConvertibleData = IsLegalDataConversion<
std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>,
T>;
template <typename Container>
using ContainerHasIntegralSize =
std::is_integral<decltype(std::size(std::declval<Container>()))>;
template <typename From, size_t FromExtent, typename To, size_t ToExtent>
using EnableIfLegalSpanConversion =
std::enable_if_t<(ToExtent == dynamic_extent || ToExtent == FromExtent) &&
IsLegalDataConversion<From, To>::value>;
// SFINAE check if Array can be converted to a span<T>.
template <typename Array, typename T, size_t Extent>
using EnableIfSpanCompatibleArray =
std::enable_if_t<(Extent == dynamic_extent ||
Extent == internal::Extent<Array>::value) &&
ContainerHasConvertibleData<Array, T>::value>;
// SFINAE check if Container can be converted to a span<T>.
template <typename Container, typename T>
using IsSpanCompatibleContainer =
std::conjunction<IsNotSpan<Container>,
IsNotStdArray<Container>,
IsNotCArray<Container>,
ContainerHasConvertibleData<Container, T>,
ContainerHasIntegralSize<Container>>;
template <typename Container, typename T>
using EnableIfSpanCompatibleContainer =
std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value>;
template <typename Container, typename T, size_t Extent>
using EnableIfSpanCompatibleContainerAndSpanIsDynamic =
std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value &&
Extent == dynamic_extent>;
// A helper template for storing the size of a span. Spans with static extents
// don't require additional storage, since the extent itself is specified in the
// template parameter.
template <size_t Extent>
class ExtentStorage {
public:
constexpr explicit ExtentStorage(size_t size) noexcept {}
constexpr size_t size() const noexcept { return Extent; }
};
// Specialization of ExtentStorage for dynamic extents, which do require
// explicit storage for the size.
template <>
struct ExtentStorage<dynamic_extent> {
constexpr explicit ExtentStorage(size_t size) noexcept : size_(size) {}
constexpr size_t size() const noexcept { return size_; }
private:
size_t size_;
};
// must_not_be_dynamic_extent prevents |dynamic_extent| from being returned in a
// constexpr context.
template <size_t kExtent>
constexpr size_t must_not_be_dynamic_extent() {
static_assert(
kExtent != dynamic_extent,
"EXTENT should only be used for containers with a static extent.");
return kExtent;
}
} // namespace internal
// A span is a value type that represents an array of elements of type T. Since
// it only consists of a pointer to memory with an associated size, it is very
// light-weight. It is cheap to construct, copy, move and use spans, so that
// users are encouraged to use it as a pass-by-value parameter. A span does not
// own the underlying memory, so care must be taken to ensure that a span does
// not outlive the backing store.
//
// span is somewhat analogous to StringPiece, but with arbitrary element types,
// allowing mutation if T is non-const.
//
// span is implicitly convertible from C++ arrays, as well as most [1]
// container-like types that provide a data() and size() method (such as
// std::vector<T>). A mutable span<T> can also be implicitly converted to an
// immutable span<const T>.
//
// Consider using a span for functions that take a data pointer and size
// parameter: it allows the function to still act on an array-like type, while
// allowing the caller code to be a bit more concise.
//
// For read-only data access pass a span<const T>: the caller can supply either
// a span<const T> or a span<T>, while the callee will have a read-only view.
// For read-write access a mutable span<T> is required.
//
// Without span:
// Read-Only:
// // std::string HexEncode(const uint8_t* data, size_t size);
// std::vector<uint8_t> data_buffer = GenerateData();
// std::string r = HexEncode(data_buffer.data(), data_buffer.size());
//
// Mutable:
// // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
// char str_buffer[100];
// SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
//
// With span:
// Read-Only:
// // std::string HexEncode(base::span<const uint8_t> data);
// std::vector<uint8_t> data_buffer = GenerateData();
// std::string r = HexEncode(data_buffer);
//
// Mutable:
// // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
// char str_buffer[100];
// SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
//
// Spans with "const" and pointers
// -------------------------------
//
// Const and pointers can get confusing. Here are vectors of pointers and their
// corresponding spans:
//
// const std::vector<int*> => base::span<int* const>
// std::vector<const int*> => base::span<const int*>
// const std::vector<const int*> => base::span<const int* const>
//
// Differences from the C++20 draft
// --------------------------------
//
// http://eel.is/c++draft/views contains the latest C++20 draft of std::span.
// Chromium tries to follow the draft as close as possible. Differences between
// the draft and the implementation are documented in subsections below.
//
// Differences from [span.objectrep]:
// - as_bytes() and as_writable_bytes() return spans of uint8_t instead of
// std::byte (std::byte is a C++17 feature)
//
// Differences from [span.cons]:
// - Constructing a static span (i.e. Extent != dynamic_extent) from a dynamic
// sized container (e.g. std::vector) requires an explicit conversion (in the
// C++20 draft this is simply UB)
//
// Furthermore, all constructors and methods are marked noexcept due to the lack
// of exceptions in Chromium.
//
// Due to the lack of class template argument deduction guides in C++14
// appropriate make_span() utility functions are provided.
// [span], class template span
template <typename T, size_t Extent, typename InternalPtrType>
class span : public internal::ExtentStorage<Extent> {
private:
using ExtentStorage = internal::ExtentStorage<Extent>;
public:
using element_type = T;
using value_type = std::remove_cv_t<T>;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = T*;
using reverse_iterator = std::reverse_iterator<iterator>;
static constexpr size_t extent = Extent;
// [span.cons], span constructors, copy, assignment, and destructor
constexpr span() noexcept : ExtentStorage(0), data_(nullptr) {
static_assert(Extent == dynamic_extent || Extent == 0, "Invalid Extent");
}
constexpr span(T* data, size_t size) noexcept
: ExtentStorage(size), data_(data) {
CHECK(Extent == dynamic_extent || Extent == size);
}
// Artificially templatized to break ambiguity for span(ptr, 0).
template <typename = void>
constexpr span(T* begin, T* end) noexcept : span(begin, end - begin) {
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
CHECK(begin <= end);
}
template <
size_t N,
typename = internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>>
constexpr span(T (&array)[N]) noexcept : span(std::data(array), N) {}
template <
typename U,
size_t N,
typename =
internal::EnableIfSpanCompatibleArray<std::array<U, N>&, T, Extent>>
constexpr span(std::array<U, N>& array) noexcept
: span(std::data(array), N) {}
template <typename U,
size_t N,
typename = internal::
EnableIfSpanCompatibleArray<const std::array<U, N>&, T, Extent>>
constexpr span(const std::array<U, N>& array) noexcept
: span(std::data(array), N) {}
// Conversion from a container that has compatible std::data() and integral
// std::size().
template <
typename Container,
typename =
internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&,
T,
Extent>>
constexpr span(Container& container) noexcept
: span(std::data(container), std::size(container)) {}
template <
typename Container,
typename = internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<
const Container&,
T,
Extent>>
constexpr span(const Container& container) noexcept
: span(std::data(container), std::size(container)) {}
constexpr span(const span& other) noexcept = default;
// Conversions from spans of compatible types and extents: this allows a
// span<T> to be seamlessly used as a span<const T>, but not the other way
// around. If extent is not dynamic, OtherExtent has to be equal to Extent.
template <
typename U,
size_t OtherExtent,
typename =
internal::EnableIfLegalSpanConversion<U, OtherExtent, T, Extent>>
constexpr span(const span<U, OtherExtent>& other)
: span(other.data(), other.size()) {}
constexpr span& operator=(const span& other) noexcept = default;
~span() noexcept = default;
// [span.sub], span subviews
template <size_t Count>
constexpr span<T, Count> first() const noexcept {
static_assert(Count <= Extent, "Count must not exceed Extent");
CHECK(Extent != dynamic_extent || Count <= size());
return {data(), Count};
}
template <size_t Count>
constexpr span<T, Count> last() const noexcept {
static_assert(Count <= Extent, "Count must not exceed Extent");
CHECK(Extent != dynamic_extent || Count <= size());
return {data() + (size() - Count), Count};
}
template <size_t Offset, size_t Count = dynamic_extent>
constexpr span<T,
(Count != dynamic_extent
? Count
: (Extent != dynamic_extent ? Extent - Offset
: dynamic_extent))>
subspan() const noexcept {
static_assert(Offset <= Extent, "Offset must not exceed Extent");
static_assert(Count == dynamic_extent || Count <= Extent - Offset,
"Count must not exceed Extent - Offset");
CHECK(Extent != dynamic_extent || Offset <= size());
CHECK(Extent != dynamic_extent || Count == dynamic_extent ||
Count <= size() - Offset);
return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
}
constexpr span<T, dynamic_extent> first(size_t count) const noexcept {
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
CHECK(count <= size());
return {data(), count};
}
constexpr span<T, dynamic_extent> last(size_t count) const noexcept {
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
CHECK(count <= size());
return {data() + (size() - count), count};
}
constexpr span<T, dynamic_extent> subspan(size_t offset,
size_t count = dynamic_extent) const
noexcept {
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
CHECK(offset <= size());
CHECK(count == dynamic_extent || count <= size() - offset);
return {data() + offset, count != dynamic_extent ? count : size() - offset};
}
// [span.obs], span observers
constexpr size_t size() const noexcept { return ExtentStorage::size(); }
constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
[[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
// [span.elem], span element access
constexpr T& operator[](size_t idx) const noexcept {
// Note: CHECK_LT is not constexpr, hence regular CHECK must be used.
CHECK(idx < size());
return *(data() + idx);
}
constexpr T& front() const noexcept {
static_assert(Extent == dynamic_extent || Extent > 0,
"Extent must not be 0");
CHECK(Extent != dynamic_extent || !empty());
return *data();
}
constexpr T& back() const noexcept {
static_assert(Extent == dynamic_extent || Extent > 0,
"Extent must not be 0");
CHECK(Extent != dynamic_extent || !empty());
return *(data() + size() - 1);
}
constexpr T* data() const noexcept { return data_; }
// [span.iter], span iterator support
constexpr iterator begin() const noexcept {
return data();
}
constexpr iterator end() const noexcept {
return data() + size();
}
constexpr reverse_iterator rbegin() const noexcept {
return reverse_iterator(end());
}
constexpr reverse_iterator rend() const noexcept {
return reverse_iterator(begin());
}
private:
// This field is not a raw_ptr<> because it was filtered by the rewriter
// for: #constexpr-ctor-field-initializer, #global-scope, #union
InternalPtrType data_;
};
// span<T, Extent>::extent can not be declared inline prior to C++17, hence this
// definition is required.
template <class T, size_t Extent, typename InternalPtrType>
constexpr size_t span<T, Extent, InternalPtrType>::extent;
template <typename It,
typename T = std::remove_reference_t<iter_reference_t<It>>>
span(It, StrictNumeric<size_t>) -> span<T>;
template <typename It,
typename End,
typename = std::enable_if_t<!std::is_convertible_v<End, size_t>>,
typename T = std::remove_reference_t<iter_reference_t<It>>>
span(It, End) -> span<T>;
template <typename T, size_t N>
span(T (&)[N]) -> span<T, N>;
template <typename T, size_t N>
span(std::array<T, N>&) -> span<T, N>;
template <typename T, size_t N>
span(const std::array<T, N>&) -> span<const T, N>;
template <typename Container,
typename T = std::remove_pointer_t<
decltype(std::data(std::declval<Container>()))>,
size_t X = internal::Extent<Container>::value>
span(Container&&) -> span<T, X>;
// [span.objectrep], views of object representation
template <typename T, size_t X>
span<const uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
as_bytes(span<T, X> s) noexcept {
return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()};
}
template <typename T,
size_t X,
typename = std::enable_if_t<!std::is_const_v<T>>>
span<uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
as_writable_bytes(span<T, X> s) noexcept {
return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()};
}
// Type-deducing helpers for constructing a span.
template <int&... ExplicitArgumentBarrier, typename T>
constexpr span<T> make_span(T* data, size_t size) noexcept {
return {data, size};
}
template <int&... ExplicitArgumentBarrier, typename T>
constexpr span<T> make_span(T* begin, T* end) noexcept {
return {begin, end};
}
// make_span utility function that deduces both the span's value_type and extent
// from the passed in argument.
//
// Usage: auto span = base::make_span(...);
template <int&... ExplicitArgumentBarrier, typename Container>
constexpr auto make_span(Container&& container) noexcept {
using T =
std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
using Extent = internal::Extent<Container>;
return span<T, Extent::value>(std::forward<Container>(container));
}
// make_span utility functions that allow callers to explicit specify the span's
// extent, the value_type is deduced automatically. This is useful when passing
// a dynamically sized container to a method expecting static spans, when the
// container is known to have the correct size.
//
// Note: This will CHECK that N indeed matches size(container).
//
// Usage: auto static_span = base::make_span<N>(...);
template <size_t N, int&... ExplicitArgumentBarrier, typename Container>
constexpr auto make_span(Container&& container) noexcept {
using T =
std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
return span<T, N>(std::data(container), std::size(container));
}
} // namespace base
// EXTENT returns the size of any type that can be converted to a |base::span|
// with definite extent, i.e. everything that is a contiguous storage of some
// sort with static size. Specifically, this works for std::array in a constexpr
// context. Note:
// * |std::size| should be preferred for plain arrays.
// * In run-time contexts, functions such as |std::array::size| should be
// preferred.
#define EXTENT(x) \
::base::internal::must_not_be_dynamic_extent<decltype( \
::base::make_span(x))::extent>()
#endif // BASE_CONTAINERS_SPAN_H_

View File

@ -6,8 +6,15 @@
#include <ctype.h>
#include <ostream>
#include "base/check.h"
#include "base/logging.h"
#if defined(FILE_PATH_USES_WIDE_CHARACTERS)
#include "base/strings/utf_string_conversions.h"
#endif // FILE_PATH_USES_WIDE_CHARACTERS
namespace base {
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
@ -284,6 +291,10 @@ void FilePath::StripTrailingSeparatorsInternal() {
} // namespace base
void PrintTo(const base::FilePath& path, std::ostream* out) {
*out << path.value().c_str();
std::ostream& operator<<(std::ostream& os, const base::FilePath& file_path) {
#ifdef FILE_PATH_USES_WIDE_CHARACTERS
return os << base::WideToUTF8(file_path.value());
#else
return os << file_path.value();
#endif
}

View File

@ -116,6 +116,7 @@
#if BUILDFLAG(IS_WIN)
#define FILE_PATH_USES_DRIVE_LETTERS
#define FILE_PATH_USES_WIN_SEPARATORS
#define FILE_PATH_USES_WIDE_CHARACTERS
#endif // BUILDFLAG(IS_WIN)
namespace base {
@ -225,8 +226,11 @@ class FilePath {
} // namespace base
// This is required by googletest to print a readable output on test failures.
extern void PrintTo(const base::FilePath& path, std::ostream* out);
// Streams `file_path`'s value to a byte stream, converting from wide
// characters if called for. (also lets googletest print a readable output on
// test failures)
extern std::ostream& operator<<(std::ostream& os,
const base::FilePath& file_path);
// Macros for string literal initialization of FilePath::CharType[], and for
// using a FilePath::CharType[] in a printf-style format string.

View File

@ -10,6 +10,8 @@
#if BUILDFLAG(IS_POSIX)
#include <unistd.h>
#include "base/check.h"
#include "base/posix/eintr_wrapper.h"
#endif

View File

@ -23,25 +23,18 @@
#include "build/build_config.h"
#if BUILDFLAG(IS_POSIX)
#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64)
#if BUILDFLAG(IS_POSIX) && \
(defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64)
#error "inttypes.h has already been included before this header file, but "
#error "without __STDC_FORMAT_MACROS defined."
#endif
#if !defined(__STDC_FORMAT_MACROS)
#if BUILDFLAG(IS_POSIX) && !defined(__STDC_FORMAT_MACROS)
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
// GCC will concatenate wide and narrow strings correctly, so nothing needs to
// be done here.
#define WidePRId64 PRId64
#define WidePRIu64 PRIu64
#define WidePRIx64 PRIx64
#if !defined(PRIuS)
#define PRIuS "zu"
#endif
@ -74,28 +67,4 @@
#endif
#endif // BUILDFLAG(IS_APPLE)
#else // BUILDFLAG(IS_WIN)
#if !defined(PRId64)
#define PRId64 "I64d"
#endif
#if !defined(PRIu64)
#define PRIu64 "I64u"
#endif
#if !defined(PRIx64)
#define PRIx64 "I64x"
#endif
#define WidePRId64 L"I64d"
#define WidePRIu64 L"I64u"
#define WidePRIx64 L"I64x"
#if !defined(PRIuS)
#define PRIuS "Iu"
#endif
#endif
#endif // BASE_FORMAT_MACROS_H_

View File

@ -54,6 +54,7 @@
#include <lib/syslog/global.h>
#endif
#include "base/check_op.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"

View File

@ -12,9 +12,6 @@
#include <sstream>
#include <string>
#include "base/check.h"
#include "base/check_op.h"
#include "base/notreached.h"
#include "build/build_config.h"
namespace logging {

View File

@ -11,8 +11,8 @@
#include <cmath>
#include <limits>
#include "base/check_op.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_FUCHSIA)

View File

@ -0,0 +1,17 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/strings/strcat.h"
#include <string>
#include "base/strings/strcat_internal.h"
namespace base {
std::string StrCat(span<const StringPiece> pieces) {
return internal::StrCatT(pieces);
}
} // namespace base

View File

@ -0,0 +1,66 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_STRINGS_STRCAT_H_
#define BASE_STRINGS_STRCAT_H_
#include <initializer_list>
#include "base/containers/span.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN)
// Guard against conflict with Win32 API StrCat macro:
// check StrCat wasn't and will not be redefined.
#define StrCat StrCat
#endif
namespace base {
// StrCat ----------------------------------------------------------------------
//
// StrCat is a function to perform concatenation on a sequence of strings.
// It is preferrable to a sequence of "a + b + c" because it is both faster and
// generates less code.
//
// std::string result = base::StrCat({"foo ", result, "\nfoo ", bar});
//
// MORE INFO
//
// StrCat can see all arguments at once, so it can allocate one return buffer
// of exactly the right size and copy once, as opposed to a sequence of
// operator+ which generates a series of temporary strings, copying as it goes.
// And by using StringPiece arguments, StrCat can avoid creating temporary
// string objects for char* constants.
//
// ALTERNATIVES
//
// Internal Google / Abseil has a similar StrCat function. That version takes
// an overloaded number of arguments instead of initializer list (overflowing
// to initializer list for many arguments). We don't have any legacy
// requirements and using only initializer_list is simpler and generates
// roughly the same amount of code at the call sites.
//
// Abseil's StrCat also allows numbers by using an intermediate class that can
// be implicitly constructed from either a string or various number types. This
// class formats the numbers into a static buffer for increased performance,
// and the call sites look nice.
//
// As-written Abseil's helper class for numbers generates slightly more code
// than the raw StringPiece version. We can de-inline the helper class'
// constructors which will cause the StringPiece constructors to be de-inlined
// for this call and generate slightly less code. This is something we can
// explore more in the future.
[[nodiscard]] std::string StrCat(span<const StringPiece> pieces);
// Initializer list forwards to the array version.
inline std::string StrCat(std::initializer_list<StringPiece> pieces) {
return StrCat(make_span(pieces));
}
} // namespace base
#endif // BASE_STRINGS_STRCAT_H_

View File

@ -0,0 +1,76 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_STRINGS_STRCAT_INTERNAL_H_
#define BASE_STRINGS_STRCAT_INTERNAL_H_
#include <string>
#include "base/containers/span.h"
#include "base/template_util.h"
namespace base {
namespace internal {
// Optimized version of `std::basic_string::resize()` that skips zero
// initialization of appended characters. Reading from the newly allocated
// characters results in undefined behavior if they are not explicitly
// initialized afterwards. Currently proposed for standardization as
// std::basic_string::resize_and_overwrite: https://wg21.link/P1072R6
template <typename CharT>
auto Resize(std::basic_string<CharT>& str, size_t total_size, priority_tag<1>)
-> decltype(str.__resize_default_init(total_size)) {
str.__resize_default_init(total_size);
}
// Fallback to regular std::basic_string::resize() if invoking
// __resize_default_init is ill-formed.
template <typename CharT>
void Resize(std::basic_string<CharT>& str, size_t total_size, priority_tag<0>) {
str.resize(total_size);
}
// Appends `pieces` to `dest`. Instead of simply calling `dest.append()`
// `pieces.size()` times, this method first resizes `dest` to be of the desired
// size, and then appends each piece via `std::char_traits::copy`. This achieves
// two goals:
// 1) Allocating the desired size all at once avoids other allocations that
// could happen if intermediate allocations did not reserve enough capacity.
// 2) Invoking std::char_traits::copy instead of std::basic_string::append
// avoids having to write the terminating '\0' character n times.
template <typename CharT, typename StringT>
void StrAppendT(std::basic_string<CharT>& dest, span<const StringT> pieces) {
const size_t initial_size = dest.size();
size_t total_size = initial_size;
for (const auto& cur : pieces)
total_size += cur.size();
// Note: As opposed to `reserve()` calling `resize()` with an argument smaller
// than the current `capacity()` does not result in the string releasing spare
// capacity. Furthermore, common std::string implementations apply a geometric
// growth strategy if the current capacity is not sufficient for the newly
// added characters. Since this codepath is also triggered by `resize()`, we
// don't have to manage the std::string's capacity ourselves here to avoid
// performance hits in case `StrAppend()` gets called in a loop.
Resize(dest, total_size, priority_tag<1>());
CharT* dest_char = &dest[initial_size];
for (const auto& cur : pieces) {
std::char_traits<CharT>::copy(dest_char, cur.data(), cur.size());
dest_char += cur.size();
}
}
template <typename StringT>
auto StrCatT(span<const StringT> pieces) {
std::basic_string<typename StringT::value_type> result;
StrAppendT(result, pieces);
return result;
}
} // namespace internal
} // namespace base
#endif // BASE_STRINGS_STRCAT_INTERNAL_H_

View File

@ -160,7 +160,6 @@ std::ostream& operator<<(std::ostream& ostream,
typedef BasicStringPiece<std::string> StringPiece;
typedef BasicStringPiece<std::u16string> StringPiece16;
typedef BasicStringPiece<std::wstring> WStringPiece;
inline bool operator==(const StringPiece& x, const StringPiece& y) {
if (x.size() != y.size())

View File

@ -5,7 +5,7 @@
#include "base/strings/sys_string_conversions.h"
#include "base/apple/bridging.h"
#include "base/logging.h"
#include "base/check_op.h"
namespace base {

View File

@ -32,10 +32,13 @@ bool ReadUnicodeCharacter(const char* src,
int32_t src_len,
int32_t* char_index,
uint32_t* code_point_out) {
int32_t code_point;
CBU8_NEXT(src, *char_index, src_len, code_point);
*code_point_out = static_cast<uint32_t>(code_point);
base_icu::UChar32 code_point;
CBU8_NEXT(reinterpret_cast<const uint8_t*>(src), *char_index, src_len,
code_point);
*code_point_out = code_point;
// The ICU macro above moves to the next char, we want to point to the last
// char consumed.
(*char_index)--;
return IsValidCodepoint(code_point);

View File

@ -7,6 +7,7 @@
#include <stdint.h>
#include <string>
#include <string_view>
#include "base/strings/utf_string_conversion_utils.h"
#include "build/build_config.h"
@ -58,8 +59,8 @@ std::string UTF16ToUTF8(const StringPiece16& utf16) {
return ret;
}
#if defined(WCHAR_T_IS_UTF16)
std::string WideToUTF8(WStringPiece wide) {
#if defined(WCHAR_T_IS_16_BIT)
std::string WideToUTF8(std::wstring_view wide) {
std::string ret;
UTF16ToUTF8(
reinterpret_cast<const char16_t*>(wide.data()), wide.size(), &ret);
@ -71,6 +72,6 @@ std::wstring UTF8ToWide(StringPiece utf8) {
return std::wstring(reinterpret_cast<const wchar_t*>(utf16.data()),
utf16.size());
}
#endif // defined(WCHAR_T_IS_UTF16)
#endif // defined(WCHAR_T_IS_16_BIT)
} // namespace

View File

@ -6,6 +6,7 @@
#define MINI_CHROMIUM_BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
#include <string>
#include <string_view>
#include "base/strings/string_piece.h"
#include "build/build_config.h"
@ -17,10 +18,10 @@ std::u16string UTF8ToUTF16(const StringPiece& utf8);
bool UTF16ToUTF8(const char16_t* src, size_t src_len, std::string* output);
std::string UTF16ToUTF8(const StringPiece16& utf16);
#if defined(WCHAR_T_IS_UTF16)
std::string WideToUTF8(WStringPiece wide);
#if defined(WCHAR_T_IS_16_BIT)
std::string WideToUTF8(std::wstring_view wide);
std::wstring UTF8ToWide(StringPiece utf8);
#endif // defined(WCHAR_T_IS_UTF16)
#endif // defined(WCHAR_T_IS_16_BIT)
} // namespace

View File

@ -4,7 +4,7 @@
#include "base/synchronization/condition_variable.h"
#include "base/logging.h"
#include "base/check_op.h"
namespace base {

View File

@ -8,7 +8,7 @@
#include "base/synchronization/lock.h"
#include "base/logging.h"
#include "base/check_op.h"
#ifndef NDEBUG

View File

@ -6,7 +6,7 @@
#include <errno.h>
#include "base/logging.h"
#include "base/check_op.h"
namespace base {
namespace internal {

View File

@ -5,123 +5,48 @@
#ifndef MINI_CHROMIUM_BASE_TEMPLATE_UTIL_H_
#define MINI_CHROMIUM_BASE_TEMPLATE_UTIL_H_
#include <stddef.h>
#include "build/build_config.h"
#include <type_traits>
namespace base {
// template definitions from tr1
template<class T, T v>
struct integral_constant {
static const T value = v;
typedef T value_type;
typedef integral_constant<T, v> type;
};
template <class T, T v> const T integral_constant<T, v>::value;
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template <class T> struct is_pointer : false_type {};
template <class T> struct is_pointer<T*> : true_type {};
// Member function pointer detection. This is built-in to C++ 11's stdlib, and
// we can remove this when we switch to it.
template<typename T>
struct is_member_function_pointer : false_type {};
template <typename R, typename Z, typename... A>
struct is_member_function_pointer<R(Z::*)(A...)> : true_type {};
template <typename R, typename Z, typename... A>
struct is_member_function_pointer<R(Z::*)(A...) const> : true_type {};
template <class T, class U> struct is_same : public false_type {};
template <class T> struct is_same<T,T> : true_type {};
template<class> struct is_array : public false_type {};
template<class T, size_t n> struct is_array<T[n]> : public true_type {};
template<class T> struct is_array<T[]> : public true_type {};
template <class T> struct is_non_const_reference : false_type {};
template <class T> struct is_non_const_reference<T&> : true_type {};
template <class T> struct is_non_const_reference<const T&> : false_type {};
template <class T> struct is_const : false_type {};
template <class T> struct is_const<const T> : true_type {};
template <class T> struct is_void : false_type {};
template <> struct is_void<void> : true_type {};
namespace internal {
// Types YesType and NoType are guaranteed such that sizeof(YesType) <
// sizeof(NoType).
typedef char YesType;
// Helper to express preferences in an overload set. If more than one overload
// are available for a given set of parameters the overload with the higher
// priority will be chosen.
template <size_t I>
struct priority_tag : priority_tag<I - 1> {};
struct NoType {
YesType dummy[2];
};
// This class is an implementation detail for is_convertible, and you
// don't need to know how it works to use is_convertible. For those
// who care: we declare two different functions, one whose argument is
// of type To and one with a variadic argument list. We give them
// return types of different size, so we can use sizeof to trick the
// compiler into telling us which function it would have chosen if we
// had called it with an argument of type From. See Alexandrescu's
// _Modern C++ Design_ for more details on this sort of trick.
struct ConvertHelper {
template <typename To>
static YesType Test(To);
template <typename To>
static NoType Test(...);
template <typename From>
static From& Create();
};
// Used to determine if a type is a struct/union/class. Inspired by Boost's
// is_class type_trait implementation.
struct IsClassHelper {
template <typename C>
static YesType Test(void(C::*)(void));
template <typename C>
static NoType Test(...);
};
template <>
struct priority_tag<0> {};
} // namespace internal
// Inherits from true_type if From is convertible to To, false_type otherwise.
// Implementation of C++20's std::remove_cvref.
//
// Note that if the type is convertible, this will be a true_type REGARDLESS
// of whether or not the conversion would emit a warning.
template <typename From, typename To>
struct is_convertible
: integral_constant<bool,
sizeof(internal::ConvertHelper::Test<To>(
internal::ConvertHelper::Create<From>())) ==
sizeof(internal::YesType)> {
};
// References:
// - https://en.cppreference.com/w/cpp/types/remove_cvref
// - https://wg21.link/meta.trans.other#lib:remove_cvref
template <typename T>
struct is_class
: integral_constant<bool,
sizeof(internal::IsClassHelper::Test<T>(0)) ==
sizeof(internal::YesType)> {
struct remove_cvref {
using type = std::remove_cv_t<std::remove_reference_t<T>>;
};
template<bool B, class T = void>
struct enable_if {};
// Implementation of C++20's std::remove_cvref_t.
//
// References:
// - https://en.cppreference.com/w/cpp/types/remove_cvref
// - https://wg21.link/meta.type.synop#lib:remove_cvref_t
template <typename T>
using remove_cvref_t = typename remove_cvref<T>::type;
template<class T>
struct enable_if<true, T> { typedef T type; };
// Simplified implementation of C++20's std::iter_reference_t.
// As opposed to std::iter_reference_t, this implementation does not restrict
// the type of `Iter`.
//
// Reference: https://wg21.link/iterator.synopsis#:~:text=iter_reference_t
template <typename Iter>
using iter_reference_t = decltype(*std::declval<Iter&>());
} // namespace base

Some files were not shown because too many files have changed in this diff Show More