Compare commits

...

No commits in common. "9d972a87da01118c2926a54604bdd10b51ea7a4f" and "31f169a0b21190627ab144906820a4310097e54c" have entirely different histories.

1313 changed files with 22609 additions and 13328 deletions

View File

@ -1 +1 @@
108.0.5359.94 109.0.5414.74

View File

@ -58,7 +58,7 @@ default_args = {
# Overwrite default args declared in the Fuchsia sdk # Overwrite default args declared in the Fuchsia sdk
fuchsia_sdk_readelf_exec = fuchsia_sdk_readelf_exec =
"//third_party/llvm-build/Release+Asserts/bin/llvm-readelf" "//third_party/llvm-build/Release+Asserts/bin/llvm-readelf"
fuchsia_target_api_level = 9 fuchsia_target_api_level = 10
devtools_visibility = [ "*" ] devtools_visibility = [ "*" ]
} }

View File

@ -134,6 +134,7 @@ Arnaud Mandy <arnaud.mandy@intel.com>
Arnaud Renevier <a.renevier@samsung.com> Arnaud Renevier <a.renevier@samsung.com>
Arpita Bahuguna <a.bah@samsung.com> Arpita Bahuguna <a.bah@samsung.com>
Arthur Lussos <developer0420@gmail.com> Arthur Lussos <developer0420@gmail.com>
Artur Akerberg <artur.aker@gmail.com>
Arun Kulkarni <kulkarni.a@samsung.com> Arun Kulkarni <kulkarni.a@samsung.com>
Arun Kumar <arun87.kumar@samsung.com> Arun Kumar <arun87.kumar@samsung.com>
Arun Mankuzhi <arun.m@samsung.com> Arun Mankuzhi <arun.m@samsung.com>
@ -315,6 +316,7 @@ Dmitry Sokolov <dimanne@gmail.com>
Dominic Farolino <domfarolino@gmail.com> Dominic Farolino <domfarolino@gmail.com>
Dominic Jodoin <dominic.jodoin@gmail.com> Dominic Jodoin <dominic.jodoin@gmail.com>
Dominik Röttsches <dominik.rottsches@intel.com> Dominik Röttsches <dominik.rottsches@intel.com>
Dominik Schütz <do.sch.dev@gmail.com>
Don Woodward <woodward@adobe.com> Don Woodward <woodward@adobe.com>
Donghee Na <corona10@gmail.com> Donghee Na <corona10@gmail.com>
Dong-hee Na <donghee.na92@gmail.com> Dong-hee Na <donghee.na92@gmail.com>
@ -514,6 +516,7 @@ Jan Grulich <grulja@gmail.com>
Jan Keitel <jan.keitel@gmail.com> Jan Keitel <jan.keitel@gmail.com>
Jan Rucka <ruckajan10@gmail.com> Jan Rucka <ruckajan10@gmail.com>
Jan Sauer <jan@jansauer.de> Jan Sauer <jan@jansauer.de>
Jan-Michael Brummer <jan.brummer@tabos.org>
Janusz Majnert <jmajnert@gmail.com> Janusz Majnert <jmajnert@gmail.com>
Janwar Dinata <j.dinata@gmail.com> Janwar Dinata <j.dinata@gmail.com>
Jared Shumway <jaredshumway94@gmail.com> Jared Shumway <jaredshumway94@gmail.com>
@ -598,6 +601,7 @@ Jongdeok Kim <jongdeok.kim@navercorp.com>
Jongheon Kim <sapzape@gmail.com> Jongheon Kim <sapzape@gmail.com>
JongKwon Lee <jongkwon.lee@navercorp.com> JongKwon Lee <jongkwon.lee@navercorp.com>
Jongmok Kim <jongmok.kim@navercorp.com> Jongmok Kim <jongmok.kim@navercorp.com>
Jongmok Kim <johny.kimc@gmail.com>
Jongsoo Lee <leejongsoo@gmail.com> Jongsoo Lee <leejongsoo@gmail.com>
Joone Hur <joone.hur@intel.com> Joone Hur <joone.hur@intel.com>
Joonghun Park <pjh0718@gmail.com> Joonghun Park <pjh0718@gmail.com>
@ -1448,6 +1452,7 @@ Synaptics <*@synaptics.com>
Tableau Software <*@tableau.com> Tableau Software <*@tableau.com>
Talon Cyber Security Ltd. <*@talon-sec.com> Talon Cyber Security Ltd. <*@talon-sec.com>
TeamSpeak Systems GmbH <*@teamspeak.com> TeamSpeak Systems GmbH <*@teamspeak.com>
The Browser Company <*@thebrowser.company>
The Chromium Authors <*@chromium.org> The Chromium Authors <*@chromium.org>
The MathWorks, Inc. <binod.pant@mathworks.com> The MathWorks, Inc. <binod.pant@mathworks.com>
THEO Technologies <*@theoplayer.com> THEO Technologies <*@theoplayer.com>

271
src/DEPS
View File

@ -43,6 +43,7 @@ gclient_gn_args = [
'checkout_nacl', 'checkout_nacl',
'checkout_openxr', 'checkout_openxr',
'checkout_rts_model', 'checkout_rts_model',
'checkout_src_internal',
'cros_boards', 'cros_boards',
'cros_boards_with_qemu_images', 'cros_boards_with_qemu_images',
'generate_location_tags', 'generate_location_tags',
@ -103,8 +104,10 @@ vars = {
# restricted to Googlers only. # restricted to Googlers only.
'checkout_chromium_fsc_test_dependencies': False, 'checkout_chromium_fsc_test_dependencies': False,
# By default, src-internal checks out //clank. # By default, check out //clank in chromium instead of src-internal. This is
'checkout_clank_via_src_internal': True, # part of an internal migration (see http://go/clank>src) and will be removed
# after the migration completes. See https://crbug.com/1315715 for context.
'checkout_clank_via_src_internal': False,
# By default, do not check out Google Benchmark. The library is only used by a # By default, do not check out Google Benchmark. The library is only used by a
# few specialized benchmarks that most developers do not interact with. Will # few specialized benchmarks that most developers do not interact with. Will
@ -171,7 +174,6 @@ vars = {
# support for other platforms may be added in the future. # support for other platforms may be added in the future.
'checkout_openxr' : 'checkout_win', 'checkout_openxr' : 'checkout_win',
'checkout_traffic_annotation_tools': 'checkout_configuration != "small"',
'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration != "small"', 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration != "small"',
# By default bot checkouts the WPR archive files only when this # By default bot checkouts the WPR archive files only when this
@ -185,32 +187,32 @@ vars = {
# Fetches only the SDK boot images that match at least one of the # Fetches only the SDK boot images that match at least one of the
# entries in a comma-separated list. # entries in a comma-separated list.
# Wildcards are supported (e.g. "qemu.*").
# #
# Available images: # Available images:
# Emulation: # Emulation:
# - qemu.x64 (pulls terminal.qemu-x64-release) # - core.x64-dfv2
# - qemu.arm64 (pulls terminal.qemu-arm64-release) # - terminal.qemu-x64
# - workstation.qemu-x64-release # - terminal.qemu-arm64
# - workstation.qemu-x64
# Hardware: # Hardware:
# - generic.x64 (pulls terminal.x64-debug) # - workstation_eng.chromebook-x64
# - generic.arm64 (pulls terminal.arm64-debug) # - workstation_eng.chromebook-x64-dfv2
# - chromebook.x64 (pulls terminal.chromebook-x64-debug)
# #
# Since the images are hundreds of MB, default to only downloading the image # Since the images are hundreds of MB, default to only downloading the image
# most commonly useful for developers. Bots and developers that need to use # most commonly useful for developers. Bots and developers that need to use
# other images (e.g., qemu.arm64) can override this with additional images. # other images can override this with additional images.
'checkout_fuchsia_boot_images': "qemu.x64", 'checkout_fuchsia_boot_images': "terminal.qemu-x64",
'checkout_fuchsia_product_bundles': '"{checkout_fuchsia_boot_images}" != ""',
# By default, do not check out files required to run fuchsia tests in # By default, do not check out files required to run fuchsia tests in
# qemu on linux-arm64 machines. # qemu on linux-arm64 machines.
'checkout_fuchsia_for_arm64_host': False, 'checkout_fuchsia_for_arm64_host': False,
# Revision of Crubit (trunk on 2022-08-26). This should typically be the # Revision of Crubit (trunk on 2022-10-15). This should typically be the
# same as the revision specified in CRUBIT_REVISION in # same as the revision specified in CRUBIT_REVISION in
# tools/rust/update_rust.py. More details and roll instructions can be # tools/rust/update_rust.py. More details and roll instructions can be
# found in tools/rust/README.md. # found in tools/rust/README.md.
'crubit_revision': '2c34caee7c3b4c2dfbcb0e935efcbc05ebc0f61d', 'crubit_revision': 'f5cbdf4b54b0e6b9f63a4464a2c901c82e0f0209',
# By default, download the fuchsia sdk from the public sdk directory. # By default, download the fuchsia sdk from the public sdk directory.
'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/gn/', 'fuchsia_sdk_cipd_prefix': 'fuchsia/sdk/gn/',
@ -250,7 +252,7 @@ vars = {
# luci-go CIPD package version. # luci-go CIPD package version.
# Make sure the revision is uploaded by infra-packagers builder. # Make sure the revision is uploaded by infra-packagers builder.
# https://ci.chromium.org/p/infra-internal/g/infra-packagers/console # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
'luci_go': 'git_revision:9f65ffe719f73af390727d369b342c22fa37ea54', 'luci_go': 'git_revision:f8f64a8c560d2bf68a3ad1137979d17cffb36d30',
# This can be overridden, e.g. with custom_vars, to build clang from HEAD # This can be overridden, e.g. with custom_vars, to build clang from HEAD
# instead of downloading the prebuilt pinned revision. # instead of downloading the prebuilt pinned revision.
@ -281,7 +283,7 @@ vars = {
'dawn_standalone': False, 'dawn_standalone': False,
# reclient CIPD package version # reclient CIPD package version
'reclient_version': 're_client_version:0.81.1.0853992-gomaip', 'reclient_version': 're_client_version:0.85.0.91db7be-gomaip',
# Fetch Rust-related packages. # Fetch Rust-related packages.
'use_rust': False, 'use_rust': False,
@ -304,34 +306,34 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Skia # the commit queue can handle CLs rolling Skia
# and whatever else without interference from each other. # and whatever else without interference from each other.
'skia_revision': '7c55be996a81ff9c5c66984c9d4ef85d12a44c8c', 'skia_revision': '9f5ce0f89e2ba479fdb57eebd13204bbed86922b',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling V8 # the commit queue can handle CLs rolling V8
# and whatever else without interference from each other. # and whatever else without interference from each other.
'v8_revision': '3155b0d10c058d2a9f1d7bba00ad398b3e03b841', 'v8_revision': '4b4e473387ed62f7fcbc95a3bf05244ea0e76a0a',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ANGLE # the commit queue can handle CLs rolling ANGLE
# and whatever else without interference from each other. # and whatever else without interference from each other.
'angle_revision': 'ceec659ac60b0c8ee9d9c602ca1a878ec1d3a88f', 'angle_revision': 'aa63ea230e0c507e7b4b164a30e502fb17168c17',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling SwiftShader # the commit queue can handle CLs rolling SwiftShader
# and whatever else without interference from each other. # and whatever else without interference from each other.
'swiftshader_revision': 'b22b1b1f2dddcf5eacc8d2a37e7d27f650e1c1e2', 'swiftshader_revision': 'dd7bb92b9a7a813ebc2da9fe3f6484c34cc69363',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling PDFium # the commit queue can handle CLs rolling PDFium
# and whatever else without interference from each other. # and whatever else without interference from each other.
'pdfium_revision': '9d2c662f557544e5edb74a60b52fb297f4c5dfee', 'pdfium_revision': '89aa9f9ebe803480ec697fb39470ed106869e272',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling BoringSSL # the commit queue can handle CLs rolling BoringSSL
# and whatever else without interference from each other. # and whatever else without interference from each other.
# #
# Note this revision should be updated with # Note this revision should be updated with
# third_party/boringssl/roll_boringssl.py, not roll-dep. # third_party/boringssl/roll_boringssl.py, not roll-dep.
'boringssl_revision': '1ee71185a2322dc354bee5e5a0abfb1810a27dc6', 'boringssl_revision': '1ccef4908ce04adc6d246262846f3cd8a111fa44',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Fuchsia sdk # the commit queue can handle CLs rolling Fuchsia sdk
# and whatever else without interference from each other. # and whatever else without interference from each other.
'fuchsia_version': 'version:9.20221006.5.1', 'fuchsia_version': 'version:10.20221110.0.1',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling google-toolbox-for-mac # the commit queue can handle CLs rolling google-toolbox-for-mac
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -351,11 +353,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling NaCl # the commit queue can handle CLs rolling NaCl
# and whatever else without interference from each other. # and whatever else without interference from each other.
'nacl_revision': '7d275eb5878e29cf3d7338617c1e0c5e5856195a', 'nacl_revision': '9b5a059df9f0015af4a013b6dc217581abf5ce49',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling freetype # the commit queue can handle CLs rolling freetype
# and whatever else without interference from each other. # and whatever else without interference from each other.
'freetype_revision': '0b62c1e43dc4b0e3c50662aac757e4f7321e5466', 'freetype_revision': 'dea2e6358b2f963008d447d27564dd79890b61f0',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling freetype # the commit queue can handle CLs rolling freetype
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -363,7 +365,7 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling HarfBuzz # the commit queue can handle CLs rolling HarfBuzz
# and whatever else without interference from each other. # and whatever else without interference from each other.
'harfbuzz_revision': '56c467093598ec559a7148b61e112e9de52b7076', 'harfbuzz_revision': '2822b589bc837fae6f66233e2cf2eef0f6ce8470',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Emoji Segmenter # the commit queue can handle CLs rolling Emoji Segmenter
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -375,7 +377,7 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling catapult # the commit queue can handle CLs rolling catapult
# and whatever else without interference from each other. # and whatever else without interference from each other.
'catapult_revision': '4793433248183dd073e608f655204d4acfdc7193', 'catapult_revision': '037b0ac25d75c1274af5aa2e3c8316f81b99d5be',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling libFuzzer # the commit queue can handle CLs rolling libFuzzer
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -383,7 +385,7 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling devtools-frontend # the commit queue can handle CLs rolling devtools-frontend
# and whatever else without interference from each other. # and whatever else without interference from each other.
'devtools_frontend_revision': '33bb29b551b54b0ac67025e8b3e0ce69352c9504', 'devtools_frontend_revision': '74ceee1e9a0f73b817709ee8acdf08608a6f0f6f',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling libprotobuf-mutator # the commit queue can handle CLs rolling libprotobuf-mutator
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -419,11 +421,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'dawn_revision': 'c84d06e8603ce9c4b5c8d86e42e9ec0acf3bd689', 'dawn_revision': 'd905232daafd9501ac1ff322b0eafb0cf92137a1',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'quiche_revision': 'a338ea8277642f6d78022dc8e3aaed182a804413', 'quiche_revision': 'a17968ca8acf183aa58529312f7a888d1157075f',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ios_webkit # the commit queue can handle CLs rolling ios_webkit
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -439,11 +441,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling libavif # the commit queue can handle CLs rolling libavif
# and whatever else without interference from each other. # and whatever else without interference from each other.
'libavif_revision': 'de7e6c0d98abcd6843c4a9bf4cee731141dca566', 'libavif_revision': 'cd03eef10a7cc6081ee98e3911e21d977a2bf17b',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling nearby # the commit queue can handle CLs rolling nearby
# and whatever else without interference from each other. # and whatever else without interference from each other.
'nearby_revision': '4bd0337c105c502de845ba9501ad6e0350f613b9', 'nearby_revision': '8c8e5d7e6f72dacd0917fdf5a3fab3e5b19ce93c',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling securemessage # the commit queue can handle CLs rolling securemessage
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -455,7 +457,7 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'cros_components_revision': 'a0979aacb8744f42ed7abd966a6b0ac7578a73e9', 'cros_components_revision': '97e45e933f8f9f584a4a8caf59b0e517a0dd5324',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -463,11 +465,11 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'libcxxabi_revision': '9572e56a12c88c011d504a707ca94952be4664f9', 'libcxxabi_revision': '1a32724f721e1c3b6c590a07fe4a954344f15e48',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
'libunwind_revision': '1111799723f6a003e6f52202b9bf84387c552081', 'libunwind_revision': '86213b7902ad64cad566fc4878024ad26654d56a',
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling feed # the commit queue can handle CLs rolling feed
# and whatever else without interference from each other. # and whatever else without interference from each other.
@ -483,14 +485,14 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ffmpeg # the commit queue can handle CLs rolling ffmpeg
# and whatever else without interference from each other. # and whatever else without interference from each other.
'ffmpeg_revision': 'b9f01c3c54576330b2cf8918c54d5ee5be8faefe', 'ffmpeg_revision': 'fd5b30c4bcf95ee607caf47ef65c3b96210867a4',
# If you change this, also update the libc++ revision in # If you change this, also update the libc++ revision in
# //buildtools/deps_revisions.gni. # //buildtools/deps_revisions.gni.
'libcxx_revision': '64d36e572d3f9719c5d75011a718f33f11126851', 'libcxx_revision': '4218f3525ad438b22b0e173d963515a09d143398',
# GN CIPD package version. # GN CIPD package version.
'gn_version': 'git_revision:b9c6c19be95a3863e02f00f1fe403b2502e345b6', 'gn_version': 'git_revision:1c4151ff5c1d6fbf7fa800b8d4bb34d3abc03a41',
# ninja CIPD package version. # ninja CIPD package version.
# https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja # https://chrome-infra-packages.appspot.com/p/infra/3pp/tools/ninja
@ -583,7 +585,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_rust_toolchain/linux-amd64', 'package': 'chromium/third_party/android_rust_toolchain/linux-amd64',
'version': 'rMU9JFlwRfB-5VEWgDPRFYme5sXSnsHPSE3uQXf1xBQC', 'version': 'version:2@1.64.0.cr2',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -594,7 +596,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/rust_src', 'package': 'chromium/third_party/rust_src',
'version': 'version:2@2022-09-14', 'version': 'version:2@2022-11-01',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -663,7 +665,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chrome_mac_universal', 'package': 'chromium/third_party/updater/chrome_mac_universal',
'version': '29MbwZukN0c7nlUhmVKLU6ecK99dCu-ZwYa3ICqbwB0C', 'version': 'Tq8hROm9IzgBhhsDQWSUldygcSqjDL6WtdDdH9GR1iEC',
}, },
], ],
} }
@ -674,7 +676,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chrome_mac_universal_prod', 'package': 'chromium/third_party/updater/chrome_mac_universal_prod',
'version': 'E3rEUfkgLutRcZKGPJN_yWoC1G-4rTIhzpXGcsUNqCsC', 'version': 'owuQ3SVzmABohvT4jYdn9RVH3gKn107su-8SrUO5Xc0C',
}, },
], ],
}, },
@ -685,7 +687,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chrome_win_x86', 'package': 'chromium/third_party/updater/chrome_win_x86',
'version': 'rqP-urpwa5NOuHhuLVNHyT9d_Psk1xDc8ELSstaIkUUC', 'version': '6VUdLZPVaa6OooJAO-6YWG2e7xR413E2OYukrtvM59sC',
}, },
], ],
}, },
@ -696,7 +698,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chrome_win_x86_64', 'package': 'chromium/third_party/updater/chrome_win_x86_64',
'version': '7nSN9jjsZ507lwEcJQKUFM_Z2wHmjJmU3nzo1s-r8-UC', 'version': 'SGIHWG5UocK__HcIUQA3wN_Web_G8Vad6N7Qv_G-E7UC',
}, },
], ],
}, },
@ -708,7 +710,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_mac_amd64', 'package': 'chromium/third_party/updater/chromium_mac_amd64',
'version': 'PAJDUVfx7D-m1AKSaBeX8wQEyyQZcIkgXlD3owmRYk0C', 'version': 'K1bKNzAlTMt_EyMNYVUvaED4IX5DnVlVWtgHRoglNOAC',
}, },
], ],
}, },
@ -720,7 +722,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_mac_arm64', 'package': 'chromium/third_party/updater/chromium_mac_arm64',
'version': '_N_FWxzXW2IQSQ8OPbpCphEWyNwYs4LKR2gMQzpjhekC', 'version': 'lRa4lm3yGtDVOKin75GKxFu1BZFF3aNadGkm8gow4iYC',
}, },
], ],
}, },
@ -731,7 +733,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_win_x86', 'package': 'chromium/third_party/updater/chromium_win_x86',
'version': '2yELAOdPaRyB3HuFsiecHXc4zcXVupx9cLa9ZAh-Z2wC', 'version': 'EYKR6SE965eKhz9JBv_pfJol97nN5UdqymhpRRU2w2YC',
}, },
], ],
}, },
@ -742,7 +744,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/updater/chromium_win_x86_64', 'package': 'chromium/third_party/updater/chromium_win_x86_64',
'version': 'vuc_q-ghg3H11b1O-ENURYlDO8hrcpCc4AuN1Expx3gC', 'version': 'MkKzihmknEOqtwuFmCdXA-TsgU0FBh7jWl3LHGLptYcC',
}, },
], ],
}, },
@ -751,7 +753,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/chrome/test/data/autofill/captured_sites', 'package': 'chromium/chrome/test/data/autofill/captured_sites',
'version': 'JT0XFwfg09pcNqt5n56Ki9hpRPgfGDSuDd1DRGBSpoYC', 'version': '9irVgwFBxE4NZ2CLPRDV_-kx70oN-BhhTAWqdFFBD3oC',
} }
], ],
'condition': 'checkout_chromium_autofill_test_dependencies', 'condition': 'checkout_chromium_autofill_test_dependencies',
@ -814,16 +816,16 @@ deps = {
'src/clank': { 'src/clank': {
'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' + 'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' +
'cf43b2bf3206ff908b2d17be5baba31b7b19f5d3', '63df73663f14a3236a32a3a7f006a9b0cf474467',
'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal', 'condition': 'checkout_android and checkout_src_internal and not checkout_clank_via_src_internal',
}, },
'src/docs/website': { 'src/docs/website': {
'url': Var('chromium_git') + '/website.git' + '@' + '7da061134f35c390ac1549a82704a1762f9a5261', 'url': Var('chromium_git') + '/website.git' + '@' + '5bef1125e998d33bfb101ac0da9a6bc445121955',
}, },
'src/ios/third_party/earl_grey2/src': { 'src/ios/third_party/earl_grey2/src': {
'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'abd4e95736740cf61d2c63223396e163d3f08415', 'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '99ba3b6ed7b8489899f06a0d602e84fc657e8338',
'condition': 'checkout_ios', 'condition': 'checkout_ios',
}, },
@ -838,7 +840,7 @@ deps = {
}, },
'src/ios/third_party/material_components_ios/src': { 'src/ios/third_party/material_components_ios/src': {
'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'e7619686aab6b4e438ab51cd3fe03396b2f872c6', 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '71dbf5f8aedb89064e40d0004427ea56c359d2f0',
'condition': 'checkout_ios', 'condition': 'checkout_ios',
}, },
@ -908,7 +910,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/rts/model/linux-amd64', 'package': 'chromium/rts/model/linux-amd64',
'version': 'gjjgFT1JcYKD-SV0nFWRTeGr2kufiafn_rvDI-gFW0QC', 'version': 'i5oOPUG4rt853hoMLBIzWPppsZTMIg11aeqwZyfJ0W4C',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -919,7 +921,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/rts/model/mac-amd64', 'package': 'chromium/rts/model/mac-amd64',
'version': 'xH8MfShB-S7HYkM3gLOUa916ukoEtDJa-8X1bOwfevsC', 'version': 'j7fpwOzWh0F-x9h9dV5tf36WBes999-jw_Swy93vPvEC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -930,7 +932,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/rts/model/windows-amd64', 'package': 'chromium/rts/model/windows-amd64',
'version': 'SWCvrm3LQO_Y0XbcVVs0q2CJOVKn0ImNLJ0WPQDKx5YC', 'version': 'ktlIC4pstyfRj9NB4gQNSuNijjGLYkcrsrfkXrzxHt8C',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -998,7 +1000,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/androidx', 'package': 'chromium/third_party/androidx',
'version': 'H4XoDJ7V7LZUIhvV2qwFHWYJoIY4MJkGQK-Q2vv-dq4C', 'version': '7fcu-OXUt3YtkM5bJ799qvx1sFSQAWOsynLMt9Z2NR4C',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1031,7 +1033,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_build_tools/aapt2', 'package': 'chromium/third_party/android_build_tools/aapt2',
'version': 'nSnWUNu6ssPA-kPMvFQj4JjDXRWj2iubvvjfT1F6HCMC', 'version': '-QrdsGmvVhHeoRc5wKCnU2LXEjk1s0ocheitXWf5dhYC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1053,7 +1055,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_build_tools/bundletool', 'package': 'chromium/third_party/android_build_tools/bundletool',
'version': 'IEZQhHFQzO9Ci1QxWZmssKqGmt2r_nCDMKr8t4cKY34C', 'version': 'nrReBqFfE2B7DUv3RveTRIE4K9O3MJft7pP-iRhoRQ4C',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1064,7 +1066,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_build_tools/lint', 'package': 'chromium/third_party/android_build_tools/lint',
'version': 'DO1bMH_JFEfZXSkAknIs7AfgNh4IwLtJaeMJTdzfuJwC', 'version': 'PwX3e0EPv-j0ip-tcNNfhy3YcFHle4vxKVo-IbTCtZYC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1075,7 +1077,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/android_build_tools/manifest_merger', 'package': 'chromium/third_party/android_build_tools/manifest_merger',
'version': 'bUREd_PkCqlp2ww6zmyOLGf0jhqgbnf6GT4V1xkAZ10C', 'version': '1_tPfyswsXgfbNegip6nTy55E2ASlhsRqA2sKhUo01YC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1146,7 +1148,7 @@ deps = {
}, },
'src/third_party/barhopper': { 'src/third_party/barhopper': {
'url': 'https://chrome-internal.googlesource.com/chrome/deps/barhopper.git' + '@' + '5830f9acc68275805d60d4b02bf8e1e3c600740d', 'url': 'https://chrome-internal.googlesource.com/chrome/deps/barhopper.git' + '@' + '865bd06ef4a839b0a15d17e38e25f8911e4cdf9f',
'condition': 'checkout_src_internal and checkout_chromeos', 'condition': 'checkout_src_internal and checkout_chromeos',
}, },
@ -1159,7 +1161,7 @@ deps = {
Var('boringssl_git') + '/boringssl.git' + '@' + Var('boringssl_revision'), Var('boringssl_git') + '/boringssl.git' + '@' + Var('boringssl_revision'),
'src/third_party/breakpad/breakpad': 'src/third_party/breakpad/breakpad':
Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'e085b3b50bde862d0cf3ce4594e3f391bcf5faec', Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'e059dad5ea3e781786f155ff9806602a4374b5fa',
'src/third_party/byte_buddy': { 'src/third_party/byte_buddy': {
'packages': [ 'packages': [
@ -1184,7 +1186,7 @@ deps = {
}, },
'src/third_party/cast_core/public/src': 'src/third_party/cast_core/public/src':
Var('chromium_git') + '/cast_core/public' + '@' + '469e045e514c09701ab674d023cbaa6562866f83', Var('chromium_git') + '/cast_core/public' + '@' + 'f4628fda1b370eb238ae69545024d256ca62d719',
'src/third_party/catapult': 'src/third_party/catapult':
Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'), Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'),
@ -1213,7 +1215,7 @@ deps = {
# Tools used when building Chrome for Chrome OS. This affects both the Simple # Tools used when building Chrome for Chrome OS. This affects both the Simple
# Chrome workflow, as well as the chromeos-chrome ebuild. # Chrome workflow, as well as the chromeos-chrome ebuild.
'src/third_party/chromite': { 'src/third_party/chromite': {
'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '6ebc1b94de0dc73bba385f70ddffab9798fd59e5', 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '84153a0e264617a1a9054318ad32d4810f003acd',
'condition': 'checkout_chromeos', 'condition': 'checkout_chromeos',
}, },
@ -1231,7 +1233,7 @@ deps = {
# For Linux and Chromium OS. # For Linux and Chromium OS.
'src/third_party/cros_system_api': { 'src/third_party/cros_system_api': {
'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '67bca80707449bad87a17de8c937634ff1ab3272', 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'ca1cd5d1bb30fbbd5c8b3eddeac77f0892b38516',
'condition': 'checkout_linux', 'condition': 'checkout_linux',
}, },
@ -1241,13 +1243,13 @@ deps = {
}, },
'src/third_party/depot_tools': 'src/third_party/depot_tools':
Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2c0a8c736a59044e4acc7be9e172343adc5c4310', Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9d351f8b5aa6d0362eae0c6d32b4e9b6ef3207bf',
'src/third_party/devtools-frontend/src': 'src/third_party/devtools-frontend/src':
Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
'src/third_party/devtools-frontend-internal': { 'src/third_party/devtools-frontend-internal': {
'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '5b416729821b589991d492f0707a087f5a47bb1f', 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '01820318125c27714865061c28bd1c17e0ff08f4',
'condition': 'checkout_src_internal', 'condition': 'checkout_src_internal',
}, },
@ -1255,7 +1257,7 @@ deps = {
Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d', Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d',
'src/third_party/eigen3/src': 'src/third_party/eigen3/src':
Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + 'b3bf8d6a13585ff248c079402654647d298de60b', Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '3bb6a48d8c171cf20b5f8e48bfb4e424fbd4f79e',
'src/third_party/emoji-metadata/src': { 'src/third_party/emoji-metadata/src': {
'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06', 'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06',
@ -1283,7 +1285,7 @@ deps = {
Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596', Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596',
'src/third_party/flatbuffers/src': 'src/third_party/flatbuffers/src':
Var('chromium_git') + '/external/github.com/google/flatbuffers.git' + '@' + '0fe13cb28ce5a3fb81f654b21cb37c9821194962', Var('chromium_git') + '/external/github.com/google/flatbuffers.git' + '@' + 'e3017029647a88eb6f509ee9744012fffeb0d371',
# Used for embedded builds. CrOS & Linux use the system version. # Used for embedded builds. CrOS & Linux use the system version.
'src/third_party/fontconfig/src': { 'src/third_party/fontconfig/src': {
@ -1292,7 +1294,7 @@ deps = {
}, },
'src/third_party/fp16/src': 'src/third_party/fp16/src':
Var('chromium_git') + '/external/github.com/Maratyszcza/FP16.git' + '@' + '4dfe081cf6bcd15db339cf2680b9281b8451eeb3', Var('chromium_git') + '/external/github.com/Maratyszcza/FP16.git' + '@' + '0a92994d729ff76a58f692d3028ca1b64b145d91',
'src/third_party/gemmlowp/src': 'src/third_party/gemmlowp/src':
Var('chromium_git') + '/external/github.com/google/gemmlowp.git' + '@' + '13d57703abca3005d97b19df1f2db731607a7dc2', Var('chromium_git') + '/external/github.com/google/gemmlowp.git' + '@' + '13d57703abca3005d97b19df1f2db731607a7dc2',
@ -1448,7 +1450,7 @@ deps = {
+ '@' + '42e892d96e47b1f6e29844cc705e148ec4856448', # release 1.9.4 + '@' + '42e892d96e47b1f6e29844cc705e148ec4856448', # release 1.9.4
'src/third_party/junit/src': { 'src/third_party/junit/src': {
'url': Var('chromium_git') + '/external/junit.git' + '@' + '64155f8a9babcfcf4263cf4d08253a1556e75481', 'url': Var('chromium_git') + '/external/junit.git' + '@' + '05fe2a64f59127c02135be22f416e91260d6ede6',
'condition': 'checkout_android', 'condition': 'checkout_android',
}, },
@ -1462,7 +1464,7 @@ deps = {
Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'df35d6c42da4fa2759e4cfb592afe33817993b89', Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'df35d6c42da4fa2759e4cfb592afe33817993b89',
'src/third_party/libaom/source/libaom': 'src/third_party/libaom/source/libaom':
Var('aomedia_git') + '/aom.git' + '@' + '4ebecefe77953f226e620821fe441e24547a121f', Var('aomedia_git') + '/aom.git' + '@' + 'b42e001a9ca9805aff7aaaa270b364a8298c33b4',
'src/third_party/libavif/src': 'src/third_party/libavif/src':
Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'), Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'),
@ -1518,12 +1520,12 @@ deps = {
}, },
'src/third_party/libunwindstack': { 'src/third_party/libunwindstack': {
'url': Var('chromium_git') + '/chromium/src/third_party/libunwindstack.git' + '@' + '8740b09bd1f8b81bdba92766afcb9df1d6a1f14e', 'url': Var('chromium_git') + '/chromium/src/third_party/libunwindstack.git' + '@' + '4dbfa0e8c844c8e243b297bc185e54a99ff94f9e',
'condition': 'checkout_android', 'condition': 'checkout_android',
}, },
'src/third_party/libvpx/source/libvpx': 'src/third_party/libvpx/source/libvpx':
Var('chromium_git') + '/webm/libvpx.git' + '@' + '9d6d0624d7943a09cc0be9df1a7402522989ac1a', Var('chromium_git') + '/webm/libvpx.git' + '@' + '5245f6e9cb7e6bb68ab45fe4d8b00bc9b16857e1',
'src/third_party/libwebm/source': 'src/third_party/libwebm/source':
Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da', Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4fbea0c9751ae8aa86629b197a28d8276a2b0da',
@ -1532,7 +1534,7 @@ deps = {
Var('chromium_git') + '/webm/libwebp.git' + '@' + '7366f7f394af26de814296152c50e673ed0a832f', Var('chromium_git') + '/webm/libwebp.git' + '@' + '7366f7f394af26de814296152c50e673ed0a832f',
'src/third_party/libyuv': 'src/third_party/libyuv':
Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '00950840d1c9bcbb3eb6ebc5aac5793e71166c8b', Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'fe9ced6e3c8ae6c69bcc3ebb8505a650d2df30e0',
'src/third_party/lighttpd': { 'src/third_party/lighttpd': {
'url': Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'), 'url': Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'),
@ -1614,7 +1616,7 @@ deps = {
'src/third_party/nasm': { 'src/third_party/nasm': {
'url': Var('chromium_git') + '/chromium/deps/nasm.git' + '@' + 'url': Var('chromium_git') + '/chromium/deps/nasm.git' + '@' +
'9215e8e1d0fe474ffd3e16c1a07a0f97089e6224' '0873b2bae6a5388a1c55deac8456e3c60a47ca08'
}, },
'src/third_party/neon_2_sse/src': 'src/third_party/neon_2_sse/src':
@ -1642,10 +1644,10 @@ deps = {
}, },
'src/third_party/openh264/src': 'src/third_party/openh264/src':
Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'fac04ceb3e966f613ed17e98178e9d690280bba6', Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'db956674bbdfbaab5acdd3fdb4117c2fef5527e9',
'src/third_party/openscreen/src': 'src/third_party/openscreen/src':
Var('chromium_git') + '/openscreen' + '@' + '940f6edf1274146fa1bfbda146b98d6aa16a0887', Var('chromium_git') + '/openscreen' + '@' + '9be5eefa2605408a671cc11c695849400caecbbb',
'src/third_party/openxr/src': { 'src/third_party/openxr/src': {
'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245', 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'bf21ccb1007bb531b45d9978919a56ea5059c245',
@ -1662,7 +1664,7 @@ deps = {
}, },
'src/third_party/perfetto': 'src/third_party/perfetto':
Var('android_git') + '/platform/external/perfetto.git' + '@' + '280f0b23c5c8b98248cf0ccf3d011c4fd4bb74f5', Var('android_git') + '/platform/external/perfetto.git' + '@' + '10498394b9f4b302ee5f56a08e41e7ba7016be44',
'src/third_party/perl': { 'src/third_party/perl': {
'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@ -1679,7 +1681,7 @@ deps = {
}, },
'src/third_party/quic_trace/src': 'src/third_party/quic_trace/src':
Var('chromium_git') + '/external/github.com/google/quic-trace.git' + '@' + 'c7b993eb750e60c307e82f75763600d9c06a6de1', Var('chromium_git') + '/external/github.com/google/quic-trace.git' + '@' + 'caa0a6eaba816ecb737f9a70782b7c80b8ac8dbc',
'src/third_party/pywebsocket3/src': 'src/third_party/pywebsocket3/src':
Var('chromium_git') + '/external/github.com/GoogleChromeLabs/pywebsocket3.git' + '@' + '50602a14f1b6da17e0b619833a13addc6ea78bc2', Var('chromium_git') + '/external/github.com/GoogleChromeLabs/pywebsocket3.git' + '@' + '50602a14f1b6da17e0b619833a13addc6ea78bc2',
@ -1696,13 +1698,13 @@ deps = {
}, },
'src/third_party/re2/src': 'src/third_party/re2/src':
Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'd2836d1b1c34c4e330a85a1006201db474bf2c8a', Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '7a65faf439295e941baa6640a717d89c1f13e9cd',
'src/third_party/r8': { 'src/third_party/r8': {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/r8', 'package': 'chromium/third_party/r8',
'version': 'szXK3tCGU7smsNs4r2mGqxme7d9KWLaOk0_ghbCJxUQC', 'version': '2rVb5rDMAwVnV9ra0CSpHAjMqBI4eDQNz_EQ9XFf_60C',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1716,7 +1718,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/r8', 'package': 'chromium/third_party/r8',
'version': 'Q3q0H5fP-O3El4ZE6Mg7vrySyorEF6YrGFs1gRr_PekC', 'version': 'qGtBu6TtxyR5XNy4cmsslb7c946YtkZF5_QCjVP-wc8C',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
@ -1740,7 +1742,7 @@ deps = {
}, },
'src/third_party/ruy/src': 'src/third_party/ruy/src':
Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '841ea4172ba904fe3536789497f9565f2ef64129', Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '3286a34cc8de6149ac6844107dfdffac91531e72',
'src/third_party/skia': 'src/third_party/skia':
Var('skia_git') + '/skia.git' + '@' + Var('skia_revision'), Var('skia_git') + '/skia.git' + '@' + Var('skia_revision'),
@ -1794,20 +1796,20 @@ deps = {
Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f', Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
'src/third_party/tflite/src': 'src/third_party/tflite/src':
Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '14b52bb67edccf9f250085f83cc0e8aad03824f0', Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '11eaf0880146cdd6af17b38fb1361dd031ee0f8c',
'src/third_party/turbine': { 'src/third_party/turbine': {
'packages': [ 'packages': [
{ {
'package': 'chromium/third_party/turbine', 'package': 'chromium/third_party/turbine',
'version': 'rrpgWQ-uylo8c5IPgUVP464LwcVOmt29MqwsR59O_zkC', 'version': 'HqLybI_r3dCgRJywsqJ3xkp2D6vQAI4-8D7zdqNiyxcC',
}, },
], ],
'condition': 'checkout_android', 'condition': 'checkout_android',
'dep_type': 'cipd', 'dep_type': 'cipd',
}, },
'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@f310d85385dfddbe1deeb05deda1045593225710', 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@16939fbb2bf748d2edd3ecf99eb2d8bf0a3ab382',
'src/third_party/vulkan_memory_allocator': 'src/third_party/vulkan_memory_allocator':
Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@ -1844,10 +1846,10 @@ deps = {
Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2', Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
'src/third_party/webgpu-cts/src': 'src/third_party/webgpu-cts/src':
Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'eba1a78f3d741241b0dbee728561b61e9587a686', Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '9eb57da4a0252044feac56418f4a306f5c66880a',
'src/third_party/webrtc': 'src/third_party/webrtc':
Var('webrtc_git') + '/src.git' + '@' + '93081d594f7efff72958a79251f53731b99e902b', Var('webrtc_git') + '/src.git' + '@' + '4e8a5ac68e8a4ae0588f54f2fdb8cbd1eb5fa50d',
# Wuffs' canonical repository is at github.com/google/wuffs, but we use # Wuffs' canonical repository is at github.com/google/wuffs, but we use
# Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@ -1865,7 +1867,7 @@ deps = {
}, },
'src/third_party/xnnpack/src': 'src/third_party/xnnpack/src':
Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'e8f74a9763aa36559980a0c2f37f587794995622', Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'a50369c0fdd15f0f35b1a91c964644327a88d480',
'src/tools/page_cycler/acid3': 'src/tools/page_cycler/acid3':
Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + '6be0a66a1ebd7ebc5abc1b2f405a945f6d871521', Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + '6be0a66a1ebd7ebc5abc1b2f405a945f6d871521',
@ -1874,7 +1876,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/linux-amd64', 'package': 'skia/tools/goldctl/linux-amd64',
'version': 'c-P40DdzhvukIRQ1DgesE2cEEU8bTLcd4p_e3LL1--sC', 'version': 'VJBQvPCDWNHadBXHtx4iViP5ju0oF2ZlEK5Zle80ZVUC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1884,7 +1886,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/windows-amd64', 'package': 'skia/tools/goldctl/windows-amd64',
'version': 'wql7tuE1euGE1rj5JPT6w6ev6KYL3hWzY6HggTHgKZ8C', 'version': 'GXa5gfPznAu49j4sXrqFvYWFSD0LTIB_TVal2oqGlAIC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1895,7 +1897,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/mac-amd64', 'package': 'skia/tools/goldctl/mac-amd64',
'version': 'OJJWEma6n1Cw5Ja1DQfdwbOFoFVp6071BB8VjklDcyYC', 'version': '1EpS2K-VevNOMzNiw1LmYktlqKVv1SyqDm2q4DRQtNkC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1906,7 +1908,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'skia/tools/goldctl/mac-arm64', 'package': 'skia/tools/goldctl/mac-arm64',
'version': '9sTZ5XDqsy_Dj_v4NU3u4fLI_AGANp-zAJ3sof4rkwQC', 'version': 'SXjqn6JoFOUmIaVPnyQWa19dyUeEb00rdwMuL9feyvoC',
}, },
], ],
'dep_type': 'cipd', 'dep_type': 'cipd',
@ -1917,7 +1919,7 @@ deps = {
Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'),
'src-internal': { 'src-internal': {
'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a63cd655ad37984fa08e1c95ca73acf55550f10d', 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9d9a9db6849a20f032629df0ffd56f1e964a330f',
'condition': 'checkout_src_internal', 'condition': 'checkout_src_internal',
}, },
@ -1925,7 +1927,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/assistant/ambient', 'package': 'chromeos_internal/assistant/ambient',
'version': 'version:feel_the_breeze_tree_shadow_improvement', 'version': 'version:feel_the_breeze_with_frame_rate_markers',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -1936,7 +1938,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/eche_app/app', 'package': 'chromeos_internal/apps/eche_app/app',
'version': '9yLWNtuRvV_dzod1dEYo01glLiFRGZ2yqhtYQapXSm4C', 'version': 'DGjNF7K8HNgqAoCrNTLYaL1cwGsGpgyMYJHLSIrCkQsC',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -1947,7 +1949,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/help_app/app', 'package': 'chromeos_internal/apps/help_app/app',
'version': '5MAo0K1bcfWGI4F8OuSplMAOM13HLHbGLL85j8dVU7AC', 'version': 'nuBoTiVJnFg80DmCLFis-iioSzVfiEk4pK-juQ656QIC',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -1958,7 +1960,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/media_app/app', 'package': 'chromeos_internal/apps/media_app/app',
'version': 'HfCwnAI0440kMmt917E1v9QJdzsNuNVfQQ86ehaVDscC', 'version': 'fDMFUaVLxpDUliwvnwpNTNwhgVxwtX0LF2diuVfN4FcC',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -1969,7 +1971,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromeos_internal/apps/projector_app/app', 'package': 'chromeos_internal/apps/projector_app/app',
'version': 'TaHxBUmYiVurXIHHo8Y5mOh7-SEnHbSCW7fn60_Wm54C', 'version': 'BTIRR9os86YFvgh31Ufk0iak_hl3Zn-G19MwY5yMFFsC',
}, },
], ],
'condition': 'checkout_chromeos and checkout_src_internal', 'condition': 'checkout_chromeos and checkout_src_internal',
@ -3098,17 +3100,6 @@ deps = {
'dep_type': 'cipd', 'dep_type': 'cipd',
}, },
'src/third_party/android_deps/libs/com_google_flatbuffers_flatbuffers_java': {
'packages': [
{
'package': 'chromium/third_party/android_deps/libs/com_google_flatbuffers_flatbuffers_java',
'version': 'version:2@2.0.3.cr1',
},
],
'condition': 'checkout_android',
'dep_type': 'cipd',
},
'src/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format': { 'src/third_party/android_deps/libs/com_google_googlejavaformat_google_java_format': {
'packages': [ 'packages': [
{ {
@ -3871,13 +3862,11 @@ include_rules = [
'-third_party/shell-encryption', '-third_party/shell-encryption',
'-third_party/private_membership', '-third_party/private_membership',
# Abseil features must be allowlisted explicitly for now. See # Abseil features are allowlisted explicitly. See
# //styleguide/c++/c++11.html. Allowed features' headers will be listed # //styleguide/c++/c++-features.md.
# explicitly here.
'-absl', '-absl',
'-third_party/abseil-cpp', '-third_party/abseil-cpp',
'+third_party/abseil-cpp/absl/base/attributes.h', '+third_party/abseil-cpp/absl/base/attributes.h',
"+third_party/abseil-cpp/absl/functional/function_ref.h",
"+third_party/abseil-cpp/absl/numeric/int128.h", "+third_party/abseil-cpp/absl/numeric/int128.h",
'+third_party/abseil-cpp/absl/types/optional.h', '+third_party/abseil-cpp/absl/types/optional.h',
'+third_party/abseil-cpp/absl/types/variant.h', '+third_party/abseil-cpp/absl/types/variant.h',
@ -4130,10 +4119,11 @@ hooks = [
}, },
{ {
# Should run after the clang hook. Used on mac, as well as for orderfile # Should run after the clang hook. Used on mac, as well as for orderfile
# generation on Android. # generation and size tooling on Android. Used by
# dump-static-initializers.py on linux.
'name': 'objdump', 'name': 'objdump',
'pattern': '.', 'pattern': '.',
'condition': 'checkout_mac or checkout_android and host_os != "mac"', 'condition': 'checkout_linux or checkout_mac or checkout_android and host_os != "mac"',
'action': ['python3', 'src/tools/clang/scripts/update.py', 'action': ['python3', 'src/tools/clang/scripts/update.py',
'--package=objdump'], '--package=objdump'],
}, },
@ -4516,38 +4506,6 @@ hooks = [
], ],
}, },
# This is used to ensure that all network operations are properly
# annotated so we can document what they're for.
{
'name': 'tools_traffic_annotation_linux',
'pattern': '.',
'condition': 'host_os == "linux" and checkout_traffic_annotation_tools',
'action': [ 'python3',
'src/third_party/depot_tools/download_from_google_storage.py',
'--no_resume',
'--no_auth',
'--num_threads=4',
'--bucket', 'chromium-tools-traffic_annotation',
'-d', 'src/tools/traffic_annotation/bin/linux64',
],
},
# This is used to ensure that all network operations are properly
# annotated so we can document what they're for.
{
'name': 'tools_traffic_annotation_windows',
'pattern': '.',
'condition': 'host_os == "win" and checkout_traffic_annotation_tools',
'action': [ 'python3',
'src/third_party/depot_tools/download_from_google_storage.py',
'--no_resume',
'--no_auth',
'--num_threads=4',
'--bucket', 'chromium-tools-traffic_annotation',
'-d', 'src/tools/traffic_annotation/bin/win32',
],
},
# Pull down Zucchini test data. # Pull down Zucchini test data.
{ {
'name': 'zucchini_testdata', 'name': 'zucchini_testdata',
@ -4731,12 +4689,11 @@ hooks = [
{ {
'name': 'Download Fuchsia system images', 'name': 'Download Fuchsia system images',
'pattern': '.', 'pattern': '.',
'condition': 'checkout_fuchsia', 'condition': 'checkout_fuchsia and checkout_fuchsia_product_bundles',
'action': [ 'action': [
'python3', 'python3',
'src/build/fuchsia/update_images.py', 'src/build/fuchsia/update_product_bundles.py',
'--boot-images={checkout_fuchsia_boot_images}', '{checkout_fuchsia_boot_images}',
'--default-bucket={fuchsia_images_bucket}',
], ],
}, },
@ -5002,7 +4959,7 @@ recursedeps = [
'src/third_party/vulkan-deps', 'src/third_party/vulkan-deps',
# src-internal has its own DEPS file to pull additional internal repos # src-internal has its own DEPS file to pull additional internal repos
'src-internal', 'src-internal',
# clank has its own DEPS file. This needs to be enabled only when it is # clank has its own DEPS file, does not need to be in trybot_analyze_config
# removed from src-internal's recursedeps. # since the roller does not run tests.
#'src/clank', 'src/clank',
] ]

View File

@ -18,6 +18,7 @@
# huge sequence of random-looking conditionals. # huge sequence of random-looking conditionals.
import("//base/allocator/allocator.gni") import("//base/allocator/allocator.gni")
import("//base/allocator/partition_allocator/partition_alloc.gni")
import("//base/trace_event/tracing.gni") import("//base/trace_event/tracing.gni")
import("//build/buildflag_header.gni") import("//build/buildflag_header.gni")
import("//build/config/arm.gni") import("//build/config/arm.gni")
@ -49,9 +50,6 @@ declare_args() {
# file name) is saved. # file name) is saved.
enable_location_source = true enable_location_source = true
# Whether or not the FROM_HERE macro uses base::Location::Current().
from_here_uses_location_builtins = true
# Unsafe developer build. Has developer-friendly features that may weaken or # Unsafe developer build. Has developer-friendly features that may weaken or
# disable security measures like sandboxing or ASLR. # disable security measures like sandboxing or ASLR.
# IMPORTANT: Unsafe developer builds should never be distributed to end users. # IMPORTANT: Unsafe developer builds should never be distributed to end users.
@ -88,7 +86,7 @@ dep_libevent = !is_fuchsia && !is_win && !is_mac && !is_nacl
# Determines whether message_pump_libevent should be used. # Determines whether message_pump_libevent should be used.
use_libevent = dep_libevent && !is_ios use_libevent = dep_libevent && !is_ios
if (is_android) { if (is_android || is_robolectric) {
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
} }
@ -154,6 +152,12 @@ config("perfetto_config") {
} }
} }
if (enable_pkeys && is_debug) {
config("no_stack_protector") {
cflags = [ "-fno-stack-protector" ]
}
}
buildflag_header("ios_cronet_buildflags") { buildflag_header("ios_cronet_buildflags") {
header = "ios_cronet_buildflags.h" header = "ios_cronet_buildflags.h"
header_dir = "base/message_loop" header_dir = "base/message_loop"
@ -359,6 +363,7 @@ mixed_component("base") {
"functional/callback_helpers.h", "functional/callback_helpers.h",
"functional/callback_internal.cc", "functional/callback_internal.cc",
"functional/callback_internal.h", "functional/callback_internal.h",
"functional/callback_tags.h",
"functional/function_ref.h", "functional/function_ref.h",
"functional/identity.h", "functional/identity.h",
"functional/invoke.h", "functional/invoke.h",
@ -564,6 +569,9 @@ mixed_component("base") {
"power_monitor/sampling_event_source.h", "power_monitor/sampling_event_source.h",
"power_monitor/timer_sampling_event_source.cc", "power_monitor/timer_sampling_event_source.cc",
"power_monitor/timer_sampling_event_source.h", "power_monitor/timer_sampling_event_source.h",
"process/current_process.cc",
"process/current_process.h",
"process/current_process_test.h",
"process/environment_internal.cc", "process/environment_internal.cc",
"process/environment_internal.h", "process/environment_internal.h",
"process/kill.cc", "process/kill.cc",
@ -603,8 +611,6 @@ mixed_component("base") {
"profiler/stack_copier_suspend.h", "profiler/stack_copier_suspend.h",
"profiler/stack_sampler.cc", "profiler/stack_sampler.cc",
"profiler/stack_sampler.h", "profiler/stack_sampler.h",
"profiler/stack_sampler_impl.cc",
"profiler/stack_sampler_impl.h",
"profiler/stack_sampling_profiler.cc", "profiler/stack_sampling_profiler.cc",
"profiler/stack_sampling_profiler.h", "profiler/stack_sampling_profiler.h",
"profiler/suspendable_thread_delegate.h", "profiler/suspendable_thread_delegate.h",
@ -635,6 +641,8 @@ mixed_component("base") {
"scoped_native_library.cc", "scoped_native_library.cc",
"scoped_native_library.h", "scoped_native_library.h",
"scoped_observation.h", "scoped_observation.h",
"scoped_observation_traits.h",
"scoped_observation_traits_internal.h",
"sequence_checker.cc", "sequence_checker.cc",
"sequence_checker.h", "sequence_checker.h",
"sequence_checker_impl.cc", "sequence_checker_impl.cc",
@ -671,6 +679,7 @@ mixed_component("base") {
"strings/string_util.cc", "strings/string_util.cc",
"strings/string_util.h", "strings/string_util.h",
"strings/string_util_constants.cc", "strings/string_util_constants.cc",
"strings/string_util_impl_helpers.h",
"strings/string_util_internal.h", "strings/string_util_internal.h",
"strings/stringize_macros.h", "strings/stringize_macros.h",
"strings/stringprintf.cc", "strings/stringprintf.cc",
@ -696,6 +705,7 @@ mixed_component("base") {
"synchronization/lock.cc", "synchronization/lock.cc",
"synchronization/lock.h", "synchronization/lock.h",
"synchronization/lock_impl.h", "synchronization/lock_impl.h",
"synchronization/waitable_event.cc",
"synchronization/waitable_event.h", "synchronization/waitable_event.h",
"synchronization/waitable_event_watcher.h", "synchronization/waitable_event_watcher.h",
"sys_byteorder.h", "sys_byteorder.h",
@ -765,7 +775,6 @@ mixed_component("base") {
"task/sequence_manager/task_queue_impl.h", "task/sequence_manager/task_queue_impl.h",
"task/sequence_manager/task_queue_selector.cc", "task/sequence_manager/task_queue_selector.cc",
"task/sequence_manager/task_queue_selector.h", "task/sequence_manager/task_queue_selector.h",
"task/sequence_manager/task_queue_selector_logic.h",
"task/sequence_manager/task_time_observer.h", "task/sequence_manager/task_time_observer.h",
"task/sequence_manager/tasks.cc", "task/sequence_manager/tasks.cc",
"task/sequence_manager/tasks.h", "task/sequence_manager/tasks.h",
@ -889,6 +898,7 @@ mixed_component("base") {
"threading/scoped_thread_priority.cc", "threading/scoped_thread_priority.cc",
"threading/scoped_thread_priority.h", "threading/scoped_thread_priority.h",
"threading/sequence_bound.h", "threading/sequence_bound.h",
"threading/sequence_bound_internal.h",
"threading/sequence_local_storage_map.cc", "threading/sequence_local_storage_map.cc",
"threading/sequence_local_storage_map.h", "threading/sequence_local_storage_map.h",
"threading/sequence_local_storage_slot.cc", "threading/sequence_local_storage_slot.cc",
@ -959,6 +969,7 @@ mixed_component("base") {
"traits_bag.h", "traits_bag.h",
"tuple.h", "tuple.h",
"types/always_false.h", "types/always_false.h",
"types/cxx23_to_underlying.h",
"types/expected.h", "types/expected.h",
"types/expected_internal.h", "types/expected_internal.h",
"types/id_type.h", "types/id_type.h",
@ -1402,7 +1413,6 @@ mixed_component("base") {
"debug/proc_maps_linux.cc", "debug/proc_maps_linux.cc",
"debug/proc_maps_linux.h", "debug/proc_maps_linux.h",
"files/dir_reader_linux.h", "files/dir_reader_linux.h",
"files/file_util_linux.cc",
"files/scoped_file_linux.cc", "files/scoped_file_linux.cc",
"process/internal_linux.cc", "process/internal_linux.cc",
"process/internal_linux.h", "process/internal_linux.h",
@ -1549,7 +1559,7 @@ mixed_component("base") {
"//third_party/abseil-cpp:absl", "//third_party/abseil-cpp:absl",
] ]
if (use_custom_libcxx && !is_debug) { if (use_custom_libcxx && enable_safe_libcxx && !is_debug) {
public_deps += [ ":nodebug_assertion" ] public_deps += [ ":nodebug_assertion" ]
} }
@ -1603,7 +1613,7 @@ mixed_component("base") {
] ]
} }
if (use_allocator == "none") { if (!use_partition_alloc_as_malloc) {
if (is_android) { if (is_android) {
sources += [ "allocator/partition_allocator/shim/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc" ] sources += [ "allocator/partition_allocator/shim/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc" ]
} }
@ -1729,7 +1739,45 @@ mixed_component("base") {
# This is actually a linker script, but it can be added to the link in the # This is actually a linker script, but it can be added to the link in the
# same way as a library. # same way as a library.
libs += [ "android/library_loader/anchor_functions.lds" ] libs += [ "android/library_loader/anchor_functions.lds" ]
} # is_android
if (is_robolectric) {
# Make jni.h available.
configs += [ "//third_party/jdk" ]
} }
if (is_robolectric) {
sources += [
"android/base_jni_onload.cc",
"android/base_jni_onload.h",
"android/callback_android.cc",
"android/callback_android.h",
"android/command_line_android.cc",
"android/java_exception_reporter.cc",
"android/java_exception_reporter.h",
"android/jni_android.cc",
"android/jni_android.h",
"android/jni_array.cc",
"android/jni_array.h",
"android/jni_generator/jni_generator_helper.h",
"android/jni_int_wrapper.h",
"android/jni_registrar.cc",
"android/jni_registrar.h",
"android/jni_string.cc",
"android/jni_string.h",
"android/jni_utils.cc",
"android/jni_utils.h",
"android/jni_weak_ref.cc",
"android/jni_weak_ref.h",
"android/library_loader/library_loader_hooks.cc",
"android/library_loader/library_loader_hooks.h",
"android/native_uma_recorder.cc",
"android/scoped_java_ref.cc",
"android/scoped_java_ref.h",
"android/trace_event_binding.cc",
"android/trace_event_binding.h",
]
deps += [ ":base_jni_headers" ]
} # is_android || is_robolectric
# Chromeos. # Chromeos.
if (is_chromeos) { if (is_chromeos) {
@ -1842,6 +1890,7 @@ mixed_component("base") {
# by public //base headers, which requires they be on the include path. # by public //base headers, which requires they be on the include path.
# TODO(https://crbug.com/841171): Move these back to |deps|. # TODO(https://crbug.com/841171): Move these back to |deps|.
public_deps += [ public_deps += [
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component.runner",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.intl", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.intl",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.io", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.io",
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.logger", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.logger",
@ -2417,7 +2466,7 @@ mixed_component("base") {
] ]
} }
if (use_allocator == "partition") { if (use_partition_alloc_as_malloc) {
sources += [ sources += [
"trace_event/address_space_dump_provider.cc", "trace_event/address_space_dump_provider.cc",
"trace_event/address_space_dump_provider.h", "trace_event/address_space_dump_provider.h",
@ -2450,6 +2499,7 @@ buildflag_header("cfi_buildflags") {
flags = [ flags = [
# TODO(pcc): remove CFI_CAST_CHECK, see https://crbug.com/626794. # TODO(pcc): remove CFI_CAST_CHECK, see https://crbug.com/626794.
"CFI_CAST_CHECK=$is_cfi && $use_cfi_cast", "CFI_CAST_CHECK=$is_cfi && $use_cfi_cast",
"CFI_DIAG=$is_cfi && $use_cfi_diag",
"CFI_ICALL_CHECK=$is_cfi && $use_cfi_icall", "CFI_ICALL_CHECK=$is_cfi && $use_cfi_icall",
"CFI_ENFORCEMENT_TRAP=$is_cfi && !$use_cfi_diag", "CFI_ENFORCEMENT_TRAP=$is_cfi && !$use_cfi_diag",
"CFI_ENFORCEMENT_DIAGNOSTIC=$is_cfi && $use_cfi_diag && !$use_cfi_recover", "CFI_ENFORCEMENT_DIAGNOSTIC=$is_cfi && $use_cfi_diag && !$use_cfi_recover",
@ -2467,7 +2517,6 @@ buildflag_header("debugging_buildflags") {
flags = [ flags = [
"DCHECK_IS_CONFIGURABLE=$dcheck_is_configurable", "DCHECK_IS_CONFIGURABLE=$dcheck_is_configurable",
"ENABLE_LOCATION_SOURCE=$enable_location_source", "ENABLE_LOCATION_SOURCE=$enable_location_source",
"FROM_HERE_USES_LOCATION_BUILTINS=$from_here_uses_location_builtins",
"ENABLE_PROFILING=$enable_profiling", "ENABLE_PROFILING=$enable_profiling",
"CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers", "CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers",
"UNSAFE_DEVELOPER_BUILD=$is_unsafe_developer_build", "UNSAFE_DEVELOPER_BUILD=$is_unsafe_developer_build",
@ -2620,7 +2669,7 @@ static_library("base_static") {
} }
} }
if (use_custom_libcxx && !is_debug) { if (use_custom_libcxx && enable_safe_libcxx && !is_debug) {
# nodebug_assertion.cc has to be in its own source_set instead of being # nodebug_assertion.cc has to be in its own source_set instead of being
# included as a source in //base as otherwise its symbols won't be linked in # included as a source in //base as otherwise its symbols won't be linked in
# if they end up in an archive. # if they end up in an archive.

View File

@ -26,3 +26,10 @@ include_rules = [
# //base/util can use //base but not vice versa. # //base/util can use //base but not vice versa.
"-util", "-util",
] ]
specific_include_rules = {
# Special case
"process/current_process(|_test)\.h": [
"+third_party/perfetto/protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h",
],
}

View File

@ -3,40 +3,29 @@
# found in the LICENSE file. # found in the LICENSE file.
import("//base/allocator/allocator.gni") import("//base/allocator/allocator.gni")
import("//base/allocator/partition_allocator/partition_alloc.gni")
import("//build/buildflag_header.gni") import("//build/buildflag_header.gni")
import("//build/config/compiler/compiler.gni") import("//build/config/compiler/compiler.gni")
import("//build/config/dcheck_always_on.gni") import("//build/config/dcheck_always_on.gni")
buildflag_header("buildflags") { buildflag_header("buildflags") {
header = "buildflags.h" header = "buildflags.h"
_use_partition_alloc_as_malloc = use_allocator == "partition"
assert(use_allocator_shim || !_use_partition_alloc_as_malloc,
"Partition alloc requires the allocator shim")
assert(
!_use_partition_alloc_as_malloc ||
enable_partition_alloc_as_malloc_support,
"Partition alloc as malloc requires enable_partition_alloc_as_malloc_support=true")
# BackupRefPtr(BRP) build flags. assert(use_allocator_shim || !use_partition_alloc_as_malloc,
_use_backup_ref_ptr = use_backup_ref_ptr && use_partition_alloc && !is_nacl "PartitionAlloc-Everywhere requires the allocator shim")
_use_partition_alloc_as_gwp_asan_store = _use_backup_ref_ptr
# MTECheckedPtr is exclusive against BRP (asserted at declaration).
# MTECheckedPtr requires 64-bit pointers (not available in NaCl).
_use_mte_checked_ptr = use_mte_checked_ptr && !is_nacl
flags = [ flags = [
"USE_ALLOCATOR_SHIM=$use_allocator_shim",
"USE_PARTITION_ALLOC=$use_partition_alloc", "USE_PARTITION_ALLOC=$use_partition_alloc",
"USE_PARTITION_ALLOC_AS_MALLOC=$_use_partition_alloc_as_malloc", "USE_ALLOCATOR_SHIM=$use_allocator_shim",
"USE_PARTITION_ALLOC_AS_MALLOC=$use_partition_alloc_as_malloc",
"USE_BACKUP_REF_PTR=$_use_backup_ref_ptr", "USE_BACKUP_REF_PTR=$use_backup_ref_ptr",
"USE_ASAN_BACKUP_REF_PTR=$use_asan_backup_ref_ptr", "USE_ASAN_BACKUP_REF_PTR=$use_asan_backup_ref_ptr",
"USE_PARTITION_ALLOC_AS_GWP_ASAN_STORE=$_use_partition_alloc_as_gwp_asan_store", "USE_PARTITION_ALLOC_AS_GWP_ASAN_STORE=$use_backup_ref_ptr",
# Not to be used directly - see `partition_alloc_config.h`. # Not to be used by itself - use in combination with
"USE_MTE_CHECKED_PTR=$_use_mte_checked_ptr", # defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
"USE_MTE_CHECKED_PTR=$use_mte_checked_ptr",
"FORCE_ENABLE_RAW_PTR_EXCLUSION=$force_enable_raw_ptr_exclusion", "FORCE_ENABLE_RAW_PTR_EXCLUSION=$force_enable_raw_ptr_exclusion",
] ]

View File

@ -1,7 +1,7 @@
This document describes how malloc / new calls are routed in the various Chrome This document describes how malloc / new calls are routed in the various Chrome
platforms. platforms.
Bare in mind that the chromium codebase does not always just use `malloc()`. Bear in mind that the chromium codebase does not always just use `malloc()`.
Some examples: Some examples:
- Large parts of the renderer (Blink) use two home-brewed allocators, - Large parts of the renderer (Blink) use two home-brewed allocators,
PartitionAlloc and BlinkGC (Oilpan). PartitionAlloc and BlinkGC (Oilpan).
@ -15,29 +15,13 @@ Background
---------- ----------
The `allocator` target defines at compile-time the platform-specific choice of The `allocator` target defines at compile-time the platform-specific choice of
the allocator and extra-hooks which services calls to malloc/new. The relevant the allocator and extra-hooks which services calls to malloc/new. The relevant
build-time flags involved are `use_allocator` and `use_allocator_shim`. build-time flags involved are `use_allocator_shim` and
`use_partition_alloc_as_malloc`.
The default choices are as follows: By default, these are true on all platforms except iOS (not yet supported) and
NaCl (no plan to support).
**Windows** Furthermore, when building with a sanitizer (e.g. `asan`, `msan`, ...) both the
`use_allocator: winheap`, the default Windows heap. allocator and the shim layer are disabled.
Additionally, `static_library` (i.e. non-component) builds have a shim
layer wrapping malloc/new, which is controlled by `use_allocator_shim`.
The shim layer provides extra security features, such as preventing large
allocations that can hit signed vs. unsigned bugs in third_party code.
**Android**
`use_allocator: none`, always use the allocator symbols coming from Android's
libc (Bionic). As it is developed as part of the OS, it is considered to be
optimized for small devices and more memory-efficient than other choices.
The actual implementation backing malloc symbols in Bionic is up to the board
config and can vary (typically *dlmalloc* or *jemalloc* on most Nexus devices).
**Mac/iOS**
`use_allocator: none`, we always use the system's allocator implementation.
In addition, when building for `asan` / `msan` both the allocator and the shim
layer are disabled.
Layering and build deps Layering and build deps
@ -86,7 +70,7 @@ a central place.
- Full documentation: [Allocator shim design doc][url-allocator-shim]. - Full documentation: [Allocator shim design doc][url-allocator-shim].
- Current state: Available and enabled by default on Android, CrOS, Linux, - Current state: Available and enabled by default on Android, CrOS, Linux,
Mac OS and Windows. Mac OS and Windows.
- Tracking bug: [https://crbug.com/550886][crbug.com/550886]. - Tracking bug: [crbug.com/550886](https://crbug.com/550886).
- Build-time flag: `use_allocator_shim`. - Build-time flag: `use_allocator_shim`.
**Overview of the unified allocator shim** **Overview of the unified allocator shim**

View File

@ -15,29 +15,11 @@ declare_args() {
# Causes all the allocations to be routed via allocator_shim.cc. # Causes all the allocations to be routed via allocator_shim.cc.
use_allocator_shim = use_allocator_shim_default use_allocator_shim = use_allocator_shim_default
# Whether PartitionAlloc should be available for use or not.
# true makes PartitionAlloc linked to the executable or shared library and
# makes it available for use. It doesn't mean that the default allocator
# is PartitionAlloc, which is governed by |use_allocator|.
#
# This flag is currently set to false only on Cronet bots, because Cronet
# doesn't use PartitionAlloc at all, and doesn't wish to incur the library
# size increase (crbug.com/674570).
use_partition_alloc = true
# RAW_PTR_EXCLUSION macro is disabled on official builds because it increased # RAW_PTR_EXCLUSION macro is disabled on official builds because it increased
# binary size. This flag can be used to enable it for official builds too. # binary size. This flag can be used to enable it for official builds too.
force_enable_raw_ptr_exclusion = false force_enable_raw_ptr_exclusion = false
} }
if (!use_partition_alloc && use_allocator == "partition") {
# If there is a conflict, prioritize |use_partition_alloc| over
# |use_allocator|.
use_allocator = "none"
}
assert(use_allocator == "none" || use_allocator == "partition")
assert( assert(
!use_allocator_shim || is_linux || is_chromeos || is_android || is_win || !use_allocator_shim || is_linux || is_chromeos || is_android || is_win ||
is_fuchsia || is_apple, is_fuchsia || is_apple,
@ -50,27 +32,38 @@ if (is_win && use_allocator_shim) {
"The allocator shim doesn't work for the component build on Windows.") "The allocator shim doesn't work for the component build on Windows.")
} }
declare_args() { # |use_backup_ref_ptr| and |use_mte_checked_ptr|, if true, compile
# If we use PartitionAlloc as default allocator and enable its MTECheckedPtr # BackupRefPtrImpl and MTECheckedPtrImp, respectively, as the implementation of
# support as default, we can use_mte_checked_ptr=true as default. # raw_ptr<T>. They're mutually exclusive.
use_mte_checked_ptr = enable_mte_checked_ptr_support_default && #
use_partition_alloc && use_allocator == "partition" # To enable them, we need:
# - PartitionAlloc to be compiled in to begin with,
# - BackupRefPtr/MTECheckedPtr support to be compiled into PartitionAlloc,
# - PartitionAlloc-Everywhere to be enabled(*),
# - not be built for NaCl, as it doesn't use PartitionAlloc-Everywhere (but is
# somehow part of the build process with all other non-NaCl goods); moreover,
# MTECheckedPtr works only with 64-bit pointers, which NaCl doesn't have.
#
# Note that making BackupRefPtrImpl the implementation of raw_ptr<T> doesn't
# necessarily enable BackupRefPtr (BRP) protection. One has to additionally
# enable PartitionAllocBackupRefPtr feature flag.
#
# (*) In theory, BRP/MTECheckedPtr will work just fine without
# PartitionAlloc-Everywhere, but their scope would be limited to partitions
# that are invoked explicitly (not via malloc). These are only Blink
# partition, where we currently don't even use raw_ptr<T>.
if (!use_partition_alloc_as_malloc) {
# Chromium-specific asserts. External embedders _may_ elect to use
# specific `raw_ptr<T>` implementations even without PA-E.
assert(!enable_backup_ref_ptr_support,
"Chromium does not use BRP without PA-E")
assert(!enable_mte_checked_ptr_support,
"Chromium does not use MTECheckedPtr without PA-E")
} }
use_backup_ref_ptr = use_partition_alloc && enable_backup_ref_ptr_support &&
declare_args() { use_partition_alloc_as_malloc && !is_nacl
# Set use_backup_ref_ptr true to use BackupRefPtr (BRP) as the implementation use_mte_checked_ptr = use_partition_alloc && enable_mte_checked_ptr_support &&
# of raw_ptr<T>, and enable PartitionAlloc support for it. use_partition_alloc_as_malloc && !is_nacl
# We also disable BRP in the presence of MTECheckedPtr, which is almost
# never enabled.
use_backup_ref_ptr = enable_backup_ref_ptr_support_default &&
use_partition_alloc && use_allocator == "partition"
}
assert(!use_backup_ref_ptr || enable_backup_ref_ptr_support,
"BackupRefPtr needs enable_backup_ref_ptr_support.")
assert(!use_mte_checked_ptr || enable_mte_checked_ptr_support,
"MTECheckedPtr needs enable_mte_checked_ptr_support.")
assert(!(use_backup_ref_ptr && use_mte_checked_ptr), assert(!(use_backup_ref_ptr && use_mte_checked_ptr),
"MTECheckedPtr conflicts with BRP.") "MTECheckedPtr conflicts with BRP.")
@ -82,15 +75,6 @@ declare_args() {
use_asan_backup_ref_ptr = is_asan && (is_win || is_android || is_linux) use_asan_backup_ref_ptr = is_asan && (is_win || is_android || is_linux)
} }
# Prevent using BackupRefPtr when PartitionAlloc-Everywhere isn't used.
# In theory, such a configuration is possible, but its scope would be limited to
# only Blink partitions, which is currently not tested. Better to trigger an
# error, than have BackupRefPtr silently disabled while believing it is enabled.
if (!is_nacl) {
assert(!use_backup_ref_ptr || use_allocator == "partition",
"Can't use BackupRefPtr without PartitionAlloc-Everywhere")
}
# BackupRefPtr and AsanBackupRefPtr are mutually exclusive variants of raw_ptr. # BackupRefPtr and AsanBackupRefPtr are mutually exclusive variants of raw_ptr.
assert( assert(
!use_backup_ref_ptr || !use_asan_backup_ref_ptr, !use_backup_ref_ptr || !use_asan_backup_ref_ptr,

View File

@ -36,7 +36,8 @@ template <typename CheckObserverPredicate,
void inline PerformObserverCheck(const std::tuple<ObserverTypes...>& observers, void inline PerformObserverCheck(const std::tuple<ObserverTypes...>& observers,
std::index_sequence<Indices...>, std::index_sequence<Indices...>,
CheckObserverPredicate check_observer) { CheckObserverPredicate check_observer) {
((DCHECK(check_observer(std::get<Indices>(observers)))), ...); ([](bool b) { DCHECK(b); }(check_observer(std::get<Indices>(observers))),
...);
} }
template <typename... ObserverTypes, size_t... Indices> template <typename... ObserverTypes, size_t... Indices>

View File

@ -367,6 +367,12 @@ std::map<std::string, std::string> ProposeSyntheticFinchTrials() {
trials.emplace("PCScan_Effective_Fallback", pcscan_group_name_fallback); trials.emplace("PCScan_Effective_Fallback", pcscan_group_name_fallback);
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
#if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS)
trials.emplace("DanglingPointerDetector", "Enabled");
#else
trials.emplace("DanglingPointerDetector", "Disabled");
#endif
return trials; return trials;
} }
@ -503,7 +509,7 @@ void DanglingRawPtrReleasedCrash(uintptr_t id) {
<< "The dangling raw_ptr was released at:\n" << "The dangling raw_ptr was released at:\n"
<< stack_trace_release << task_trace_release; << stack_trace_release << task_trace_release;
} }
IMMEDIATE_CRASH(); ImmediateCrash();
} }
void ClearDanglingRawPtrBuffer() { void ClearDanglingRawPtrBuffer() {
@ -557,7 +563,7 @@ void UnretainedDanglingRawPtrDetectedCrash(uintptr_t id) {
LOG(ERROR) << "Detected dangling raw_ptr in unretained with id=" LOG(ERROR) << "Detected dangling raw_ptr in unretained with id="
<< StringPrintf("0x%016" PRIxPTR, id) << ":\n\n" << StringPrintf("0x%016" PRIxPTR, id) << ":\n\n"
<< task_trace << stack_trace; << task_trace << stack_trace;
IMMEDIATE_CRASH(); ImmediateCrash();
} }
void InstallUnretainedDanglingRawPtrChecks() { void InstallUnretainedDanglingRawPtrChecks() {

View File

@ -5,3 +5,6 @@
# The python interpreter to use by default. On Windows, this will look # The python interpreter to use by default. On Windows, this will look
# for python3.exe and python3.bat. # for python3.exe and python3.bat.
script_executable = "python3" script_executable = "python3"
# The location of the build configuration file.
buildconfig = "//build/config/BUILDCONFIG.gn"

View File

@ -40,6 +40,12 @@ if (is_fuchsia) {
} }
} }
if (enable_pkeys && is_debug) {
config("no_stack_protector") {
cflags = [ "-fno-stack-protector" ]
}
}
component("partition_alloc") { component("partition_alloc") {
sources = [ sources = [
"address_pool_manager.cc", "address_pool_manager.cc",
@ -74,6 +80,7 @@ component("partition_alloc") {
"partition_alloc.cc", "partition_alloc.cc",
"partition_alloc.h", "partition_alloc.h",
"partition_alloc_base/atomic_ref_count.h", "partition_alloc_base/atomic_ref_count.h",
"partition_alloc_base/augmentations/compiler_specific.h",
"partition_alloc_base/bit_cast.h", "partition_alloc_base/bit_cast.h",
"partition_alloc_base/bits.h", "partition_alloc_base/bits.h",
"partition_alloc_base/check.cc", "partition_alloc_base/check.cc",
@ -125,6 +132,8 @@ component("partition_alloc") {
"partition_alloc_base/time/time_override.cc", "partition_alloc_base/time/time_override.cc",
"partition_alloc_base/time/time_override.h", "partition_alloc_base/time/time_override.h",
"partition_alloc_base/types/strong_alias.h", "partition_alloc_base/types/strong_alias.h",
"partition_alloc_base/win/win_handle_types.h",
"partition_alloc_base/win/win_handle_types_list.inc",
"partition_alloc_base/win/windows_types.h", "partition_alloc_base/win/windows_types.h",
"partition_alloc_check.h", "partition_alloc_check.h",
"partition_alloc_config.h", "partition_alloc_config.h",
@ -153,6 +162,8 @@ component("partition_alloc") {
"partition_tag_bitmap.h", "partition_tag_bitmap.h",
"partition_tag_types.h", "partition_tag_types.h",
"partition_tls.h", "partition_tls.h",
"pkey.cc",
"pkey.h",
"random.cc", "random.cc",
"random.h", "random.h",
"reservation_offset_table.cc", "reservation_offset_table.cc",
@ -346,6 +357,12 @@ component("partition_alloc") {
configs -= [ "//build/config/compiler:default_optimization" ] configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_speed" ] configs += [ "//build/config/compiler:optimize_speed" ]
} }
# We want to be able to test pkey mode without access to the default pkey.
# This is incompatible with stack protectors since the TLS won't be pkey-tagged.
if (enable_pkeys && is_debug) {
configs += [ ":no_stack_protector" ]
}
} }
buildflag_header("partition_alloc_buildflags") { buildflag_header("partition_alloc_buildflags") {
@ -359,6 +376,8 @@ buildflag_header("partition_alloc_buildflags") {
enable_backup_ref_ptr_slow_checks && _enable_backup_ref_ptr_support enable_backup_ref_ptr_slow_checks && _enable_backup_ref_ptr_support
_enable_dangling_raw_ptr_checks = _enable_dangling_raw_ptr_checks =
enable_dangling_raw_ptr_checks && _enable_backup_ref_ptr_support enable_dangling_raw_ptr_checks && _enable_backup_ref_ptr_support
_enable_dangling_raw_ptr_perf_experiment =
enable_dangling_raw_ptr_perf_experiment && _enable_dangling_raw_ptr_checks
# MTECheckedPtr is exclusive against BRP (asserted at declaration). # MTECheckedPtr is exclusive against BRP (asserted at declaration).
# MTECheckedPtr requires 64-bit pointers (not available in NaCl). # MTECheckedPtr requires 64-bit pointers (not available in NaCl).
@ -385,18 +404,22 @@ buildflag_header("partition_alloc_buildflags") {
# defines and partition alloc includes the header file. For chrome, # defines and partition alloc includes the header file. For chrome,
# gen/base/allocator/buildflags.h defines and chrome includes. # gen/base/allocator/buildflags.h defines and chrome includes.
flags = [ flags = [
"ENABLE_PARTITION_ALLOC_AS_MALLOC_SUPPORT=$enable_partition_alloc_as_malloc_support", "ENABLE_PARTITION_ALLOC_AS_MALLOC_SUPPORT=$use_partition_alloc_as_malloc",
"ENABLE_BACKUP_REF_PTR_SUPPORT=$_enable_backup_ref_ptr_support", "ENABLE_BACKUP_REF_PTR_SUPPORT=$_enable_backup_ref_ptr_support",
"ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=$_enable_backup_ref_ptr_slow_checks", "ENABLE_BACKUP_REF_PTR_SLOW_CHECKS=$_enable_backup_ref_ptr_slow_checks",
"ENABLE_DANGLING_RAW_PTR_CHECKS=$_enable_dangling_raw_ptr_checks", "ENABLE_DANGLING_RAW_PTR_CHECKS=$_enable_dangling_raw_ptr_checks",
"ENABLE_DANGLING_RAW_PTR_PERF_EXPERIMENT=$_enable_dangling_raw_ptr_perf_experiment",
"PUT_REF_COUNT_IN_PREVIOUS_SLOT=$_put_ref_count_in_previous_slot", "PUT_REF_COUNT_IN_PREVIOUS_SLOT=$_put_ref_count_in_previous_slot",
"ENABLE_GWP_ASAN_SUPPORT=$_enable_gwp_asan_support", "ENABLE_GWP_ASAN_SUPPORT=$_enable_gwp_asan_support",
# Not to be used directly - instead use
# defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
"ENABLE_MTE_CHECKED_PTR_SUPPORT=$_enable_mte_checked_ptr_support", "ENABLE_MTE_CHECKED_PTR_SUPPORT=$_enable_mte_checked_ptr_support",
"RECORD_ALLOC_INFO=$_record_alloc_info", "RECORD_ALLOC_INFO=$_record_alloc_info",
"USE_FREESLOT_BITMAP=$use_freeslot_bitmap", "USE_FREESLOT_BITMAP=$use_freeslot_bitmap",
"GLUE_CORE_POOLS=$glue_core_pools",
"ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=$_enable_shadow_metadata_for_64_bits_pointers", "ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS=$_enable_shadow_metadata_for_64_bits_pointers",
# *Scan is currently only used by Chromium. # *Scan is currently only used by Chromium.

View File

@ -5,6 +5,8 @@
# PartitionAlloc is planned to be extracted into a standalone library, and # PartitionAlloc is planned to be extracted into a standalone library, and
# therefore dependencies need to be strictly controlled and minimized. # therefore dependencies need to be strictly controlled and minimized.
gclient_gn_args_file = 'partition_allocator/build/config/gclient_args.gni'
# Only these hosts are allowed for dependencies in this DEPS file. # Only these hosts are allowed for dependencies in this DEPS file.
# This is a subset of chromium/src/DEPS's allowed_hosts. # This is a subset of chromium/src/DEPS's allowed_hosts.
allowed_hosts = [ allowed_hosts = [
@ -16,8 +18,13 @@ vars = {
} }
deps = { deps = {
'partition_allocator/build':
Var('chromium_git') + '/chromium/src/build.git',
'partition_allocator/buildtools':
Var('chromium_git') + '/chromium/src/buildtools.git',
'partition_allocator/buildtools/clang_format/script': 'partition_allocator/buildtools/clang_format/script':
Var('chromium_git') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git', Var('chromium_git') +
'/external/github.com/llvm/llvm-project/clang/tools/clang-format.git',
'partition_allocator/buildtools/linux64': { 'partition_allocator/buildtools/linux64': {
'packages': [ 'packages': [
{ {
@ -48,8 +55,79 @@ deps = {
'dep_type': 'cipd', 'dep_type': 'cipd',
'condition': 'host_os == "win"', 'condition': 'host_os == "win"',
}, },
'partition_allocator/buildtools/third_party/libc++/trunk':
Var('chromium_git') + '/external/github.com/llvm/llvm-project/libcxx.git',
'partition_allocator/buildtools/third_party/libc++abi/trunk':
Var('chromium_git') +
'/external/github.com/llvm/llvm-project/libcxxabi.git',
'partition_allocator/tools/clang':
Var('chromium_git') + '/chromium/src/tools/clang.git',
} }
hooks = [
{
'name': 'sysroot_arm',
'pattern': '.',
'condition': 'checkout_linux and checkout_arm',
'action': [
'python3',
'partition_allocator/build/linux/sysroot_scripts/install-sysroot.py',
'--arch=arm'],
},
{
'name': 'sysroot_arm64',
'pattern': '.',
'condition': 'checkout_linux and checkout_arm64',
'action': [
'python3',
'partition_allocator/build/linux/sysroot_scripts/install-sysroot.py',
'--arch=arm64'],
},
{
'name': 'sysroot_x86',
'pattern': '.',
'condition': 'checkout_linux and (checkout_x86 or checkout_x64)',
'action': [
'python3',
'partition_allocator/build/linux/sysroot_scripts/install-sysroot.py',
'--arch=x86'],
},
{
'name': 'sysroot_mips',
'pattern': '.',
'condition': 'checkout_linux and checkout_mips',
'action': [
'python3',
'partition_allocator/build/linux/sysroot_scripts/install-sysroot.py',
'--arch=mips'],
},
{
'name': 'sysroot_mips64',
'pattern': '.',
'condition': 'checkout_linux and checkout_mips64',
'action': [
'python3',
'partition_allocator/build/linux/sysroot_scripts/install-sysroot.py',
'--arch=mips64el'],
},
{
'name': 'sysroot_x64',
'pattern': '.',
'condition': 'checkout_linux and checkout_x64',
'action': [
'python3',
'partition_allocator/build/linux/sysroot_scripts/install-sysroot.py',
'--arch=x64'],
},
{
# Update the prebuilt clang toolchain.
# Note: On Win, this should run after win_toolchain, as it may use it.
'name': 'clang',
'pattern': '.',
'action': ['python3', 'partition_allocator/tools/clang/scripts/update.py'],
},
]
noparent = True noparent = True
include_rules = [ include_rules = [

View File

@ -17,10 +17,11 @@
#include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_alloc_constants.h"
#include "base/allocator/partition_allocator/partition_alloc_notreached.h" #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h" #include "base/allocator/partition_allocator/reservation_offset_table.h"
#include "build/build_config.h" #include "build/build_config.h"
#if BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_APPLE) || BUILDFLAG(ENABLE_PKEYS)
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
@ -50,7 +51,7 @@ void DecommitPages(uintptr_t address, size_t size) {
void AddressPoolManager::Add(pool_handle handle, uintptr_t ptr, size_t length) { void AddressPoolManager::Add(pool_handle handle, uintptr_t ptr, size_t length) {
PA_DCHECK(!(ptr & kSuperPageOffsetMask)); PA_DCHECK(!(ptr & kSuperPageOffsetMask));
PA_DCHECK(!((ptr + length) & kSuperPageOffsetMask)); PA_DCHECK(!((ptr + length) & kSuperPageOffsetMask));
PA_CHECK(handle > 0 && handle <= std::size(pools_)); PA_CHECK(handle > 0 && handle <= std::size(aligned_pools_.pools_));
Pool* pool = GetPool(handle); Pool* pool = GetPool(handle);
PA_CHECK(!pool->IsInitialized()); PA_CHECK(!pool->IsInitialized());
@ -76,8 +77,8 @@ uintptr_t AddressPoolManager::GetPoolBaseAddress(pool_handle handle) {
} }
void AddressPoolManager::ResetForTesting() { void AddressPoolManager::ResetForTesting() {
for (pool_handle i = 0; i < std::size(pools_); ++i) for (pool_handle i = 0; i < std::size(aligned_pools_.pools_); ++i)
pools_[i].Reset(); aligned_pools_.pools_[i].Reset();
} }
void AddressPoolManager::Remove(pool_handle handle) { void AddressPoolManager::Remove(pool_handle handle) {
@ -292,6 +293,9 @@ bool AddressPoolManager::GetStats(AddressSpaceStats* stats) {
if (IsConfigurablePoolAvailable()) { if (IsConfigurablePoolAvailable()) {
GetPoolStats(kConfigurablePoolHandle, &stats->configurable_pool_stats); GetPoolStats(kConfigurablePoolHandle, &stats->configurable_pool_stats);
} }
#if BUILDFLAG(ENABLE_PKEYS)
GetPoolStats(kPkeyPoolHandle, &stats->pkey_pool_stats);
#endif
return true; return true;
} }
@ -341,8 +345,10 @@ uintptr_t AddressPoolManager::Reserve(pool_handle handle,
uintptr_t requested_address, uintptr_t requested_address,
size_t length) { size_t length) {
PA_DCHECK(!(length & DirectMapAllocationGranularityOffsetMask())); PA_DCHECK(!(length & DirectMapAllocationGranularityOffsetMask()));
uintptr_t address = AllocPages(requested_address, length, kSuperPageSize, uintptr_t address =
PageAccessibilityConfiguration::kInaccessible, AllocPages(requested_address, length, kSuperPageSize,
PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc); PageTag::kPartitionAlloc);
return address; return address;
} }

View File

@ -35,17 +35,17 @@ namespace partition_alloc::internal {
// AddressPoolManager takes a reserved virtual address space and manages address // AddressPoolManager takes a reserved virtual address space and manages address
// space allocation. // space allocation.
// //
// AddressPoolManager (currently) supports up to 3 pools. Each pool manages a // AddressPoolManager (currently) supports up to 4 pools. Each pool manages a
// contiguous reserved address space. Alloc() takes a pool_handle and returns // contiguous reserved address space. Alloc() takes a pool_handle and returns
// address regions from the specified pool. Free() also takes a pool_handle and // address regions from the specified pool. Free() also takes a pool_handle and
// returns the address region back to the manager. // returns the address region back to the manager.
// //
// (32bit version) // (32bit version)
// AddressPoolManager wraps AllocPages and FreePages and remembers allocated // AddressPoolManager wraps AllocPages and FreePages and remembers allocated
// address regions using bitmaps. IsManagedByPartitionAllocBRPPool and // address regions using bitmaps. IsManagedByPartitionAlloc*Pool use the bitmaps
// IsManagedByPartitionAllocRegularPool use the bitmaps to judge whether a given // to judge whether a given address is in a pool that supports BackupRefPtr or
// address is in a pool that supports BackupRefPtr or in a pool that doesn't. // in a pool that doesn't. All PartitionAlloc allocations must be in either of
// All PartitionAlloc allocations must be in either of the pools. // the pools.
class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManager { class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManager {
public: public:
static AddressPoolManager& GetInstance(); static AddressPoolManager& GetInstance();
@ -93,6 +93,11 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManager {
private: private:
friend class AddressPoolManagerForTesting; friend class AddressPoolManagerForTesting;
#if BUILDFLAG(ENABLE_PKEYS)
// If we use a pkey pool, we need to tag its metadata with the pkey. Allow the
// function to get access to the pool pointer.
friend void TagGlobalsWithPkey(int pkey);
#endif
constexpr AddressPoolManager() = default; constexpr AddressPoolManager() = default;
~AddressPoolManager() = default; ~AddressPoolManager() = default;
@ -147,14 +152,21 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManager {
PA_ALWAYS_INLINE Pool* GetPool(pool_handle handle) { PA_ALWAYS_INLINE Pool* GetPool(pool_handle handle) {
PA_DCHECK(0 < handle && handle <= kNumPools); PA_DCHECK(0 < handle && handle <= kNumPools);
return &pools_[handle - 1]; return &aligned_pools_.pools_[handle - 1];
} }
// Gets the stats for the pool identified by `handle`, if // Gets the stats for the pool identified by `handle`, if
// initialized. // initialized.
void GetPoolStats(pool_handle handle, PoolStats* stats); void GetPoolStats(pool_handle handle, PoolStats* stats);
// If pkey support is enabled, we need to pkey-tag the pkey pool (which needs
// to be last). For this, we need to add padding in front of the pools so that
// pkey one starts on a page boundary.
struct {
char pad_[PA_PKEY_ARRAY_PAD_SZ(Pool, kNumPools)] = {};
Pool pools_[kNumPools]; Pool pools_[kNumPools];
char pad_after_[PA_PKEY_FILL_PAGE_SZ(sizeof(Pool))] = {};
} aligned_pools_ PA_PKEY_ALIGN;
#endif // defined(PA_HAS_64_BITS_POINTERS) #endif // defined(PA_HAS_64_BITS_POINTERS)

View File

@ -38,6 +38,9 @@ struct AddressSpaceStats {
size_t blocklist_hit_count; size_t blocklist_hit_count;
#endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
#endif // defined(PA_HAS_64_BITS_POINTERS) #endif // defined(PA_HAS_64_BITS_POINTERS)
#if BUILDFLAG(ENABLE_PKEYS)
PoolStats pkey_pool_stats;
#endif
}; };
// Interface passed to `AddressPoolManager::DumpStats()` to mediate // Interface passed to `AddressPoolManager::DumpStats()` to mediate

View File

@ -48,33 +48,20 @@ PartitionAlloc-Everywhere and must be `true` as a prerequisite for
enabling PA-E. enabling PA-E.
*** ***
### `use_allocator` ### `use_partition_alloc_as_malloc`
Does nothing special when value is `"none"`. Enables Does nothing special when value is `false`. Enables
[PartitionAlloc-Everywhere (PA-E)][pae-public-doc] when value is [PartitionAlloc-Everywhere (PA-E)][pae-public-doc] when value is `true`.
`"partition"`.
*** note *** note
* While "everywhere" (in "PartitionAlloc-Everywhere") tautologically * While "everywhere" (in "PartitionAlloc-Everywhere") tautologically
includes Blink where PartitionAlloc originated, setting includes Blink where PartitionAlloc originated, setting
`use_allocator = "none"` does not disable PA usage in Blink. `use_partition_alloc_as_malloc = false` does not disable PA usage in Blink,
* `use_allocator = "partition"` internally sets which invokes PA explicitly (not via malloc).
`use_partition_alloc_as_malloc = true`, which must not be confused * `use_partition_alloc_as_malloc = true` must not be confused
with `use_partition_alloc` (see above). with `use_partition_alloc` (see above).
*** ***
### `use_backup_ref_ptr`
Specifies `BackupRefPtr` as the implementation for `base::raw_ptr<T>`
when `true`. See the [MiraclePtr documentation][miracleptr-doc].
*** aside
BRP requires support from PartitionAlloc, so `use_backup_ref_ptr` also
compiles the relevant code into PA. However, this arg does _not_ govern
whether or not BRP is actually enabled at runtime - that functionality
is controlled by a Finch flag.
***
## Note: Component Builds ## Note: Component Builds
When working on PartitionAlloc, know that `is_debug` defaults to When working on PartitionAlloc, know that `is_debug` defaults to

View File

@ -87,4 +87,11 @@ void SwapInProcessThreadCacheForTesting(ThreadSafePartitionRoot* root) {
#endif // defined(PA_THREAD_CACHE_SUPPORTED) #endif // defined(PA_THREAD_CACHE_SUPPORTED)
} }
ThreadAllocStats GetAllocStatsForCurrentThread() {
ThreadCache* thread_cache = ThreadCache::Get();
if (ThreadCache::IsValid(thread_cache))
return thread_cache->thread_alloc_stats();
return {};
}
} // namespace partition_alloc::internal } // namespace partition_alloc::internal

View File

@ -6,6 +6,7 @@
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_EXTENDED_API_H_ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_EXTENDED_API_H_
#include "base/allocator/partition_allocator/partition_root.h" #include "base/allocator/partition_allocator/partition_root.h"
#include "base/allocator/partition_allocator/partition_stats.h"
#include "base/allocator/partition_allocator/thread_cache.h" #include "base/allocator/partition_allocator/thread_cache.h"
namespace partition_alloc::internal { namespace partition_alloc::internal {
@ -19,6 +20,10 @@ void SwapOutProcessThreadCacheForTesting(ThreadSafePartitionRoot* root);
// process. // process.
void SwapInProcessThreadCacheForTesting(ThreadSafePartitionRoot* root); void SwapInProcessThreadCacheForTesting(ThreadSafePartitionRoot* root);
// Get allocation stats for the thread cache partition on the current
// thread. See the documentation of ThreadAllocStats for details.
ThreadAllocStats GetAllocStatsForCurrentThread();
} // namespace partition_alloc::internal } // namespace partition_alloc::internal
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_EXTENDED_API_H_ #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_EXTENDED_API_H_

View File

@ -25,6 +25,24 @@ PartitionAlloc's build will expect them at
In addition, something must provide `build_with_chromium = false` to In addition, something must provide `build_with_chromium = false` to
the PA build system. the PA build system.
## `use_partition_alloc`
The `use_partition_alloc` GN arg, described in
[`build_config.md`](./build_config.md), provides a GN-level seam that
embedders
1. can set in their GN args and
2. should observe in their GN recipes to conditionally pull in
PartitionAlloc.
I.E. if you have any reason to disable PartitionAlloc, you should do so
with this GN arg. Avoid pulling in PartitionAlloc headers when the
corresponding buildflag is false.
Setting `use_partition_alloc` false will also implicitly disable other
features, e.g. nixing the compilation of BackupRefPtr as the
implementation of `raw_ptr<T>`.
## Periodic Memory Reduction Routines ## Periodic Memory Reduction Routines
PartitionAlloc provides APIs to PartitionAlloc provides APIs to

View File

@ -101,6 +101,8 @@ Buckets consist of slot spans, organized as linked lists (see below).
primary user (the [V8 Sandbox][v8-sandbox]) can configure it at runtime, primary user (the [V8 Sandbox][v8-sandbox]) can configure it at runtime,
providing a pre-existing mapping. Its allocations aren't protected by providing a pre-existing mapping. Its allocations aren't protected by
BackupRefPtr. BackupRefPtr.
* [64-bit only] The pkey pool is returning memory tagged with a memory
protection key on supported platforms. It's primary user is [V8 CFI][v8-cfi].
*** promo *** promo
Pools are downgraded into a logical concept in 32-bit environments, Pools are downgraded into a logical concept in 32-bit environments,
@ -173,3 +175,4 @@ As of 2022, PartitionAlloc-Everywhere is supported on
[max-bucket-comment]: https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/partition_alloc_constants.h;l=345;drc=667e6b001f438521e1c1a1bc3eabeead7aaa1f37 [max-bucket-comment]: https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/partition_alloc_constants.h;l=345;drc=667e6b001f438521e1c1a1bc3eabeead7aaa1f37
[pa-thread-cache]: https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/thread_cache.h [pa-thread-cache]: https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/thread_cache.h
[v8-sandbox]: https://docs.google.com/document/d/1FM4fQmIhEqPG8uGp5o9A-mnPB5BOeScZYpkHjo0KKA8/preview# [v8-sandbox]: https://docs.google.com/document/d/1FM4fQmIhEqPG8uGp5o9A-mnPB5BOeScZYpkHjo0KKA8/preview#
[v8-cfi]: https://docs.google.com/document/d/1O2jwK4dxI3nRcOJuPYkonhTkNQfbmwdvxQMyXgeaRHo/preview#

View File

@ -350,7 +350,9 @@ bool ReserveAddressSpace(size_t size) {
internal::ScopedGuard guard(GetReserveLock()); internal::ScopedGuard guard(GetReserveLock());
if (!s_reservation_address) { if (!s_reservation_address) {
uintptr_t mem = internal::SystemAllocPages( uintptr_t mem = internal::SystemAllocPages(
0, size, PageAccessibilityConfiguration::kInaccessible, 0, size,
PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
PageTag::kChromium); PageTag::kChromium);
if (mem) { if (mem) {
// We guarantee this alignment when reserving address space. // We guarantee this alignment when reserving address space.

View File

@ -34,12 +34,12 @@ struct PageAccessibilityConfiguration {
}; };
#if BUILDFLAG(ENABLE_PKEYS) #if BUILDFLAG(ENABLE_PKEYS)
constexpr PageAccessibilityConfiguration(Permissions permissions) explicit constexpr PageAccessibilityConfiguration(Permissions permissions)
: permissions(permissions), pkey(0) {} : permissions(permissions), pkey(0) {}
constexpr PageAccessibilityConfiguration(Permissions permissions, int pkey) constexpr PageAccessibilityConfiguration(Permissions permissions, int pkey)
: permissions(permissions), pkey(pkey) {} : permissions(permissions), pkey(pkey) {}
#else #else
constexpr PageAccessibilityConfiguration(Permissions permissions) explicit constexpr PageAccessibilityConfiguration(Permissions permissions)
: permissions(permissions) {} : permissions(permissions) {}
#endif // BUILDFLAG(ENABLE_PKEYS) #endif // BUILDFLAG(ENABLE_PKEYS)

View File

@ -187,7 +187,8 @@ void DecommitSystemPagesInternal(
if (accessibility_disposition == if (accessibility_disposition ==
PageAccessibilityDisposition::kRequireUpdate) { PageAccessibilityDisposition::kRequireUpdate) {
SetSystemPagesAccess(address, length, SetSystemPagesAccess(address, length,
PageAccessibilityConfiguration::kInaccessible); PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible));
} }
// TODO(https://crbug.com/1022062): Review whether this implementation is // TODO(https://crbug.com/1022062): Review whether this implementation is
@ -198,7 +199,8 @@ void DecommitSystemPagesInternal(
void DecommitAndZeroSystemPagesInternal(uintptr_t address, size_t length) { void DecommitAndZeroSystemPagesInternal(uintptr_t address, size_t length) {
SetSystemPagesAccess(address, length, SetSystemPagesAccess(address, length,
PageAccessibilityConfiguration::kInaccessible); PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible));
// TODO(https://crbug.com/1022062): this implementation will likely no longer // TODO(https://crbug.com/1022062): this implementation will likely no longer
// be appropriate once DiscardSystemPagesInternal() migrates to a "lazy" // be appropriate once DiscardSystemPagesInternal() migrates to a "lazy"

View File

@ -17,6 +17,7 @@
#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h" #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
#include "base/allocator/partition_allocator/partition_alloc_base/posix/eintr_wrapper.h" #include "base/allocator/partition_allocator/partition_alloc_base/posix/eintr_wrapper.h"
#include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "build/build_config.h" #include "build/build_config.h"
#if BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_APPLE)
@ -200,8 +201,14 @@ bool TrySetSystemPagesAccessInternal(
uintptr_t address, uintptr_t address,
size_t length, size_t length,
PageAccessibilityConfiguration accessibility) { PageAccessibilityConfiguration accessibility) {
#if BUILDFLAG(ENABLE_PKEYS)
return 0 == PkeyMprotectIfEnabled(reinterpret_cast<void*>(address), length,
GetAccessFlags(accessibility),
accessibility.pkey);
#else
return 0 == PA_HANDLE_EINTR(mprotect(reinterpret_cast<void*>(address), length, return 0 == PA_HANDLE_EINTR(mprotect(reinterpret_cast<void*>(address), length,
GetAccessFlags(accessibility))); GetAccessFlags(accessibility)));
#endif
} }
void SetSystemPagesAccessInternal( void SetSystemPagesAccessInternal(
@ -209,8 +216,14 @@ void SetSystemPagesAccessInternal(
size_t length, size_t length,
PageAccessibilityConfiguration accessibility) { PageAccessibilityConfiguration accessibility) {
int access_flags = GetAccessFlags(accessibility); int access_flags = GetAccessFlags(accessibility);
const int ret = PA_HANDLE_EINTR( #if BUILDFLAG(ENABLE_PKEYS)
mprotect(reinterpret_cast<void*>(address), length, access_flags)); int ret =
PkeyMprotectIfEnabled(reinterpret_cast<void*>(address), length,
GetAccessFlags(accessibility), accessibility.pkey);
#else
int ret = PA_HANDLE_EINTR(mprotect(reinterpret_cast<void*>(address), length,
GetAccessFlags(accessibility)));
#endif
// On Linux, man mprotect(2) states that ENOMEM is returned when (1) internal // On Linux, man mprotect(2) states that ENOMEM is returned when (1) internal
// kernel data structures cannot be allocated, (2) the address range is // kernel data structures cannot be allocated, (2) the address range is
@ -293,7 +306,8 @@ void DecommitSystemPagesInternal(
// crbug.com/1153021). // crbug.com/1153021).
if (change_permissions) { if (change_permissions) {
SetSystemPagesAccess(address, length, SetSystemPagesAccess(address, length,
PageAccessibilityConfiguration::kInaccessible); PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible));
} }
} }

View File

@ -134,7 +134,8 @@ void DecommitSystemPagesInternal(
// Ignore accessibility_disposition, because decommitting is equivalent to // Ignore accessibility_disposition, because decommitting is equivalent to
// making pages inaccessible. // making pages inaccessible.
SetSystemPagesAccess(address, length, SetSystemPagesAccess(address, length,
PageAccessibilityConfiguration::kInaccessible); PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible));
} }
void DecommitAndZeroSystemPagesInternal(uintptr_t address, size_t length) { void DecommitAndZeroSystemPagesInternal(uintptr_t address, size_t length) {

View File

@ -18,6 +18,7 @@
#include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/partition_alloc_config.h" #include "base/allocator/partition_allocator/partition_alloc_config.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_alloc_constants.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "build/build_config.h" #include "build/build_config.h"
#if BUILDFLAG(IS_IOS) #if BUILDFLAG(IS_IOS)
@ -28,7 +29,7 @@
#include <windows.h> #include <windows.h>
#endif // BUILDFLAG(IS_WIN) #endif // BUILDFLAG(IS_WIN)
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA) || BUILDFLAG(ENABLE_PKEYS)
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
@ -102,7 +103,11 @@ PA_NOINLINE void HandlePoolAllocFailure() {
} // namespace } // namespace
#if BUILDFLAG(ENABLE_PKEYS)
alignas(PA_PKEY_ALIGN_SZ)
#else
alignas(kPartitionCachelineSize) alignas(kPartitionCachelineSize)
#endif
PartitionAddressSpace::PoolSetup PartitionAddressSpace::setup_; PartitionAddressSpace::PoolSetup PartitionAddressSpace::setup_;
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA)
@ -168,6 +173,30 @@ void PartitionAddressSpace::Init() {
return; return;
size_t regular_pool_size = RegularPoolSize(); size_t regular_pool_size = RegularPoolSize();
size_t brp_pool_size = BRPPoolSize();
#if defined(PA_GLUE_CORE_POOLS)
// Gluing core pools (regular & BRP) makes sense only when both pools are of
// the same size. This the only way we can check belonging to either of the
// two with a single bitmask operation.
PA_CHECK(regular_pool_size == brp_pool_size);
// TODO(crbug.com/1362969): Support PA_ENABLE_SHADOW_METADATA.
int pools_fd = -1;
size_t glued_pool_sizes = regular_pool_size * 2;
// Note, BRP pool requires to be preceded by a "forbidden zone", which is
// conveniently taken care of by the last guard page of the regular pool.
setup_.regular_pool_base_address_ =
AllocPages(glued_pool_sizes, glued_pool_sizes,
PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc, pools_fd);
if (!setup_.regular_pool_base_address_)
HandlePoolAllocFailure();
setup_.brp_pool_base_address_ =
setup_.regular_pool_base_address_ + regular_pool_size;
#else // defined(PA_GLUE_CORE_POOLS)
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA)
int regular_pool_fd = memfd_create("/regular_pool", MFD_CLOEXEC); int regular_pool_fd = memfd_create("/regular_pool", MFD_CLOEXEC);
#else #else
@ -175,24 +204,14 @@ void PartitionAddressSpace::Init() {
#endif #endif
setup_.regular_pool_base_address_ = setup_.regular_pool_base_address_ =
AllocPages(regular_pool_size, regular_pool_size, AllocPages(regular_pool_size, regular_pool_size,
PageAccessibilityConfiguration::kInaccessible, PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc, regular_pool_fd); PageTag::kPartitionAlloc, regular_pool_fd);
if (!setup_.regular_pool_base_address_) if (!setup_.regular_pool_base_address_)
HandlePoolAllocFailure(); HandlePoolAllocFailure();
#if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
setup_.regular_pool_base_mask_ = ~(regular_pool_size - 1);
#endif #endif
PA_DCHECK(!(setup_.regular_pool_base_address_ & (regular_pool_size - 1)));
AddressPoolManager::GetInstance().Add(
kRegularPoolHandle, setup_.regular_pool_base_address_, regular_pool_size);
PA_DCHECK(!IsInRegularPool(setup_.regular_pool_base_address_ - 1));
PA_DCHECK(IsInRegularPool(setup_.regular_pool_base_address_));
PA_DCHECK(IsInRegularPool(setup_.regular_pool_base_address_ +
regular_pool_size - 1));
PA_DCHECK(
!IsInRegularPool(setup_.regular_pool_base_address_ + regular_pool_size));
size_t brp_pool_size = BRPPoolSize();
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA)
int brp_pool_fd = memfd_create("/brp_pool", MFD_CLOEXEC); int brp_pool_fd = memfd_create("/brp_pool", MFD_CLOEXEC);
#else #else
@ -206,21 +225,61 @@ void PartitionAddressSpace::Init() {
uintptr_t base_address = AllocPagesWithAlignOffset( uintptr_t base_address = AllocPagesWithAlignOffset(
0, brp_pool_size + kForbiddenZoneSize, brp_pool_size, 0, brp_pool_size + kForbiddenZoneSize, brp_pool_size,
brp_pool_size - kForbiddenZoneSize, brp_pool_size - kForbiddenZoneSize,
PageAccessibilityConfiguration::kInaccessible, PageTag::kPartitionAlloc, PageAccessibilityConfiguration(
brp_pool_fd); PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc, brp_pool_fd);
if (!base_address) if (!base_address)
HandlePoolAllocFailure(); HandlePoolAllocFailure();
setup_.brp_pool_base_address_ = base_address + kForbiddenZoneSize; setup_.brp_pool_base_address_ = base_address + kForbiddenZoneSize;
#endif // defined(PA_GLUE_CORE_POOLS)
#if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
setup_.regular_pool_base_mask_ = ~(regular_pool_size - 1);
setup_.brp_pool_base_mask_ = ~(brp_pool_size - 1); setup_.brp_pool_base_mask_ = ~(brp_pool_size - 1);
#if defined(PA_GLUE_CORE_POOLS)
// When PA_GLUE_CORE_POOLS is on, the BRP pool is placed at the end of the
// regular pool, effectively forming one virtual pool of a twice bigger
// size. Adjust the mask appropriately.
setup_.core_pools_base_mask_ = setup_.regular_pool_base_mask_ << 1;
PA_DCHECK(setup_.core_pools_base_mask_ == (setup_.brp_pool_base_mask_ << 1));
#endif #endif
PA_DCHECK(!(setup_.brp_pool_base_address_ & (brp_pool_size - 1))); #endif // defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
AddressPoolManager::GetInstance().Add(
kRegularPoolHandle, setup_.regular_pool_base_address_, regular_pool_size);
AddressPoolManager::GetInstance().Add( AddressPoolManager::GetInstance().Add(
kBRPPoolHandle, setup_.brp_pool_base_address_, brp_pool_size); kBRPPoolHandle, setup_.brp_pool_base_address_, brp_pool_size);
// Sanity check pool alignment.
PA_DCHECK(!(setup_.regular_pool_base_address_ & (regular_pool_size - 1)));
PA_DCHECK(!(setup_.brp_pool_base_address_ & (brp_pool_size - 1)));
#if defined(PA_GLUE_CORE_POOLS)
PA_DCHECK(!(setup_.regular_pool_base_address_ & (glued_pool_sizes - 1)));
#endif
// Sanity check pool belonging.
PA_DCHECK(!IsInRegularPool(setup_.regular_pool_base_address_ - 1));
PA_DCHECK(IsInRegularPool(setup_.regular_pool_base_address_));
PA_DCHECK(IsInRegularPool(setup_.regular_pool_base_address_ +
regular_pool_size - 1));
PA_DCHECK(
!IsInRegularPool(setup_.regular_pool_base_address_ + regular_pool_size));
PA_DCHECK(!IsInBRPPool(setup_.brp_pool_base_address_ - 1)); PA_DCHECK(!IsInBRPPool(setup_.brp_pool_base_address_ - 1));
PA_DCHECK(IsInBRPPool(setup_.brp_pool_base_address_)); PA_DCHECK(IsInBRPPool(setup_.brp_pool_base_address_));
PA_DCHECK(IsInBRPPool(setup_.brp_pool_base_address_ + brp_pool_size - 1)); PA_DCHECK(IsInBRPPool(setup_.brp_pool_base_address_ + brp_pool_size - 1));
PA_DCHECK(!IsInBRPPool(setup_.brp_pool_base_address_ + brp_pool_size)); PA_DCHECK(!IsInBRPPool(setup_.brp_pool_base_address_ + brp_pool_size));
#if defined(PA_GLUE_CORE_POOLS)
PA_DCHECK(!IsInCorePools(setup_.regular_pool_base_address_ - 1));
PA_DCHECK(IsInCorePools(setup_.regular_pool_base_address_));
PA_DCHECK(
IsInCorePools(setup_.regular_pool_base_address_ + regular_pool_size - 1));
PA_DCHECK(
IsInCorePools(setup_.regular_pool_base_address_ + regular_pool_size));
PA_DCHECK(IsInCorePools(setup_.brp_pool_base_address_ - 1));
PA_DCHECK(IsInCorePools(setup_.brp_pool_base_address_));
PA_DCHECK(IsInCorePools(setup_.brp_pool_base_address_ + brp_pool_size - 1));
PA_DCHECK(!IsInCorePools(setup_.brp_pool_base_address_ + brp_pool_size));
#endif // defined(PA_GLUE_CORE_POOLS)
#if PA_STARSCAN_USE_CARD_TABLE #if PA_STARSCAN_USE_CARD_TABLE
// Reserve memory for PCScan quarantine card table. // Reserve memory for PCScan quarantine card table.
@ -236,7 +295,8 @@ void PartitionAddressSpace::Init() {
// Reserve memory for the shadow pools. // Reserve memory for the shadow pools.
uintptr_t regular_pool_shadow_address = uintptr_t regular_pool_shadow_address =
AllocPages(regular_pool_size, regular_pool_size, AllocPages(regular_pool_size, regular_pool_size,
PageAccessibilityConfiguration::kInaccessible, PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc, regular_pool_fd); PageTag::kPartitionAlloc, regular_pool_fd);
regular_pool_shadow_offset_ = regular_pool_shadow_offset_ =
regular_pool_shadow_address - setup_.regular_pool_base_address_; regular_pool_shadow_address - setup_.regular_pool_base_address_;
@ -244,8 +304,9 @@ void PartitionAddressSpace::Init() {
uintptr_t brp_pool_shadow_address = AllocPagesWithAlignOffset( uintptr_t brp_pool_shadow_address = AllocPagesWithAlignOffset(
0, brp_pool_size + kForbiddenZoneSize, brp_pool_size, 0, brp_pool_size + kForbiddenZoneSize, brp_pool_size,
brp_pool_size - kForbiddenZoneSize, brp_pool_size - kForbiddenZoneSize,
PageAccessibilityConfiguration::kInaccessible, PageTag::kPartitionAlloc, PageAccessibilityConfiguration(
brp_pool_fd); PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc, brp_pool_fd);
brp_pool_shadow_offset_ = brp_pool_shadow_offset_ =
brp_pool_shadow_address - setup_.brp_pool_base_address_; brp_pool_shadow_address - setup_.brp_pool_base_address_;
#endif #endif
@ -256,8 +317,13 @@ void PartitionAddressSpace::InitConfigurablePool(uintptr_t pool_base,
// The ConfigurablePool must only be initialized once. // The ConfigurablePool must only be initialized once.
PA_CHECK(!IsConfigurablePoolInitialized()); PA_CHECK(!IsConfigurablePoolInitialized());
// The other Pools must be initialized first. #if BUILDFLAG(ENABLE_PKEYS)
Init(); // It's possible that the pkey pool has been initialized first, in which case
// the setup_ memory has been made read-only. Remove the protection
// temporarily.
if (IsPkeyPoolInitialized())
TagGlobalsWithPkey(kDefaultPkey);
#endif
PA_CHECK(pool_base); PA_CHECK(pool_base);
PA_CHECK(size <= kConfigurablePoolMaxSize); PA_CHECK(size <= kConfigurablePoolMaxSize);
@ -270,15 +336,61 @@ void PartitionAddressSpace::InitConfigurablePool(uintptr_t pool_base,
AddressPoolManager::GetInstance().Add( AddressPoolManager::GetInstance().Add(
kConfigurablePoolHandle, setup_.configurable_pool_base_address_, size); kConfigurablePoolHandle, setup_.configurable_pool_base_address_, size);
#if BUILDFLAG(ENABLE_PKEYS)
// Put the pkey protection back in place.
if (IsPkeyPoolInitialized())
TagGlobalsWithPkey(setup_.pkey_);
#endif
} }
#if BUILDFLAG(ENABLE_PKEYS)
void PartitionAddressSpace::InitPkeyPool(int pkey) {
// The PkeyPool can't be initialized with conflicting pkeys.
if (IsPkeyPoolInitialized()) {
PA_CHECK(setup_.pkey_ == pkey);
return;
}
size_t pool_size = PkeyPoolSize();
setup_.pkey_pool_base_address_ =
AllocPages(pool_size, pool_size,
PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc);
if (!setup_.pkey_pool_base_address_)
HandlePoolAllocFailure();
PA_DCHECK(!(setup_.pkey_pool_base_address_ & (pool_size - 1)));
setup_.pkey_ = pkey;
AddressPoolManager::GetInstance().Add(
kPkeyPoolHandle, setup_.pkey_pool_base_address_, pool_size);
PA_DCHECK(!IsInPkeyPool(setup_.pkey_pool_base_address_ - 1));
PA_DCHECK(IsInPkeyPool(setup_.pkey_pool_base_address_));
PA_DCHECK(IsInPkeyPool(setup_.pkey_pool_base_address_ + pool_size - 1));
PA_DCHECK(!IsInPkeyPool(setup_.pkey_pool_base_address_ + pool_size));
// TODO(1362969): support PA_ENABLE_SHADOW_METADATA
}
#endif // BUILDFLAG(ENABLE_PKEYS)
void PartitionAddressSpace::UninitForTesting() { void PartitionAddressSpace::UninitForTesting() {
#if BUILDFLAG(ENABLE_PKEYS)
UninitPkeyPoolForTesting(); // IN-TEST
#endif
#if defined(PA_GLUE_CORE_POOLS)
// The core pools (regular & BRP) were allocated using a single allocation of
// double size.
FreePages(setup_.regular_pool_base_address_, 2 * RegularPoolSize());
#else // defined(PA_GLUE_CORE_POOLS)
FreePages(setup_.regular_pool_base_address_, RegularPoolSize()); FreePages(setup_.regular_pool_base_address_, RegularPoolSize());
// For BRP pool, the allocation region includes a "forbidden zone" before the // For BRP pool, the allocation region includes a "forbidden zone" before the
// pool. // pool.
const size_t kForbiddenZoneSize = PageAllocationGranularity(); const size_t kForbiddenZoneSize = PageAllocationGranularity();
FreePages(setup_.brp_pool_base_address_ - kForbiddenZoneSize, FreePages(setup_.brp_pool_base_address_ - kForbiddenZoneSize,
BRPPoolSize() + kForbiddenZoneSize); BRPPoolSize() + kForbiddenZoneSize);
#endif // defined(PA_GLUE_CORE_POOLS)
// Do not free pages for the configurable pool, because its memory is owned // Do not free pages for the configurable pool, because its memory is owned
// by someone else, but deinitialize it nonetheless. // by someone else, but deinitialize it nonetheless.
setup_.regular_pool_base_address_ = kUninitializedPoolBaseAddress; setup_.regular_pool_base_address_ = kUninitializedPoolBaseAddress;
@ -289,11 +401,37 @@ void PartitionAddressSpace::UninitForTesting() {
} }
void PartitionAddressSpace::UninitConfigurablePoolForTesting() { void PartitionAddressSpace::UninitConfigurablePoolForTesting() {
#if BUILDFLAG(ENABLE_PKEYS)
// It's possible that the pkey pool has been initialized first, in which case
// the setup_ memory has been made read-only. Remove the protection
// temporarily.
if (IsPkeyPoolInitialized())
TagGlobalsWithPkey(kDefaultPkey);
#endif
AddressPoolManager::GetInstance().Remove(kConfigurablePoolHandle); AddressPoolManager::GetInstance().Remove(kConfigurablePoolHandle);
setup_.configurable_pool_base_address_ = kUninitializedPoolBaseAddress; setup_.configurable_pool_base_address_ = kUninitializedPoolBaseAddress;
setup_.configurable_pool_base_mask_ = 0; setup_.configurable_pool_base_mask_ = 0;
#if BUILDFLAG(ENABLE_PKEYS)
// Put the pkey protection back in place.
if (IsPkeyPoolInitialized())
TagGlobalsWithPkey(setup_.pkey_);
#endif
} }
#if BUILDFLAG(ENABLE_PKEYS)
void PartitionAddressSpace::UninitPkeyPoolForTesting() {
if (IsPkeyPoolInitialized()) {
TagGlobalsWithPkey(kDefaultPkey);
PkeySettings::settings.enabled = false;
FreePages(setup_.pkey_pool_base_address_, PkeyPoolSize());
AddressPoolManager::GetInstance().Remove(kPkeyPoolHandle);
setup_.pkey_pool_base_address_ = kUninitializedPoolBaseAddress;
setup_.pkey_ = kInvalidPkey;
}
}
#endif
#if BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64) #if BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
PageCharacteristics page_characteristics; PageCharacteristics page_characteristics;

View File

@ -21,6 +21,7 @@
#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_alloc_constants.h"
#include "base/allocator/partition_allocator/partition_alloc_forward.h" #include "base/allocator/partition_allocator/partition_alloc_forward.h"
#include "base/allocator/partition_allocator/partition_alloc_notreached.h" #include "base/allocator/partition_allocator/partition_alloc_notreached.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -65,6 +66,11 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
PA_DCHECK(IsConfigurablePoolInitialized()); PA_DCHECK(IsConfigurablePoolInitialized());
pool = kConfigurablePoolHandle; pool = kConfigurablePoolHandle;
base = setup_.configurable_pool_base_address_; base = setup_.configurable_pool_base_address_;
#if BUILDFLAG(ENABLE_PKEYS)
} else if (IsInPkeyPool(address)) {
pool = kPkeyPoolHandle;
base = setup_.pkey_pool_base_address_;
#endif
} else { } else {
PA_NOTREACHED(); PA_NOTREACHED();
} }
@ -87,12 +93,16 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
// //
// This function must only be called from the main thread. // This function must only be called from the main thread.
static void InitConfigurablePool(uintptr_t pool_base, size_t size); static void InitConfigurablePool(uintptr_t pool_base, size_t size);
#if BUILDFLAG(ENABLE_PKEYS)
static void InitPkeyPool(int pkey);
static void UninitPkeyPoolForTesting();
#endif
static void UninitForTesting(); static void UninitForTesting();
static void UninitConfigurablePoolForTesting(); static void UninitConfigurablePoolForTesting();
static PA_ALWAYS_INLINE bool IsInitialized() { static PA_ALWAYS_INLINE bool IsInitialized() {
// Either neither or both regular and BRP pool are initialized. The // Either neither or both regular and BRP pool are initialized. The
// configurable pool is initialized separately. // configurable and pkey pool are initialized separately.
if (setup_.regular_pool_base_address_ != kUninitializedPoolBaseAddress) { if (setup_.regular_pool_base_address_ != kUninitializedPoolBaseAddress) {
PA_DCHECK(setup_.brp_pool_base_address_ != kUninitializedPoolBaseAddress); PA_DCHECK(setup_.brp_pool_base_address_ != kUninitializedPoolBaseAddress);
return true; return true;
@ -107,6 +117,12 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
kUninitializedPoolBaseAddress; kUninitializedPoolBaseAddress;
} }
#if BUILDFLAG(ENABLE_PKEYS)
static PA_ALWAYS_INLINE bool IsPkeyPoolInitialized() {
return setup_.pkey_pool_base_address_ != kUninitializedPoolBaseAddress;
}
#endif
// Returns false for nullptr. // Returns false for nullptr.
static PA_ALWAYS_INLINE bool IsInRegularPool(uintptr_t address) { static PA_ALWAYS_INLINE bool IsInRegularPool(uintptr_t address) {
#if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
@ -132,6 +148,25 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
return (address & brp_pool_base_mask) == setup_.brp_pool_base_address_; return (address & brp_pool_base_mask) == setup_.brp_pool_base_address_;
} }
#if defined(PA_GLUE_CORE_POOLS)
// Checks whether the address belongs to either regular or BRP pool.
// Returns false for nullptr.
static PA_ALWAYS_INLINE bool IsInCorePools(uintptr_t address) {
#if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
const uintptr_t core_pools_base_mask = setup_.core_pools_base_mask_;
#else
// When PA_GLUE_CORE_POOLS is on, the BRP pool is placed at the end of the
// regular pool, effectively forming one virtual pool of a twice bigger
// size. Adjust the mask appropriately.
constexpr uintptr_t core_pools_base_mask = kRegularPoolBaseMask << 1;
#endif
bool ret =
(address & core_pools_base_mask) == setup_.regular_pool_base_address_;
PA_DCHECK(ret == (IsInRegularPool(address) || IsInBRPPool(address)));
return ret;
}
#endif // defined(PA_GLUE_CORE_POOLS)
static PA_ALWAYS_INLINE uintptr_t OffsetInBRPPool(uintptr_t address) { static PA_ALWAYS_INLINE uintptr_t OffsetInBRPPool(uintptr_t address) {
PA_DCHECK(IsInBRPPool(address)); PA_DCHECK(IsInBRPPool(address));
return address - setup_.brp_pool_base_address_; return address - setup_.brp_pool_base_address_;
@ -147,6 +182,13 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
return setup_.configurable_pool_base_address_; return setup_.configurable_pool_base_address_;
} }
#if BUILDFLAG(ENABLE_PKEYS)
// Returns false for nullptr.
static PA_ALWAYS_INLINE bool IsInPkeyPool(uintptr_t address) {
return (address & kPkeyPoolBaseMask) == setup_.pkey_pool_base_address_;
}
#endif
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA)
static PA_ALWAYS_INLINE std::ptrdiff_t ShadowPoolOffset(pool_handle pool) { static PA_ALWAYS_INLINE std::ptrdiff_t ShadowPoolOffset(pool_handle pool) {
if (pool == kRegularPoolHandle) { if (pool == kRegularPoolHandle) {
@ -183,6 +225,12 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
} }
#endif // defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #endif // defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
#if BUILDFLAG(ENABLE_PKEYS)
constexpr static PA_ALWAYS_INLINE size_t PkeyPoolSize() {
return kPkeyPoolSize;
}
#endif
// On 64-bit systems, PA allocates from several contiguous, mutually disjoint // On 64-bit systems, PA allocates from several contiguous, mutually disjoint
// pools. The BRP pool is where all allocations have a BRP ref-count, thus // pools. The BRP pool is where all allocations have a BRP ref-count, thus
// pointers pointing there can use a BRP protection against UaF. Allocations // pointers pointing there can use a BRP protection against UaF. Allocations
@ -204,8 +252,12 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
// ArrayBuffers be located inside of it. // ArrayBuffers be located inside of it.
static constexpr size_t kRegularPoolSize = kPoolMaxSize; static constexpr size_t kRegularPoolSize = kPoolMaxSize;
static constexpr size_t kBRPPoolSize = kPoolMaxSize; static constexpr size_t kBRPPoolSize = kPoolMaxSize;
static_assert(base::bits::IsPowerOfTwo(kRegularPoolSize) && static_assert(base::bits::IsPowerOfTwo(kRegularPoolSize));
base::bits::IsPowerOfTwo(kBRPPoolSize)); static_assert(base::bits::IsPowerOfTwo(kBRPPoolSize));
#if BUILDFLAG(ENABLE_PKEYS)
static constexpr size_t kPkeyPoolSize = kGiB / 4;
static_assert(base::bits::IsPowerOfTwo(kPkeyPoolSize));
#endif
#if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
// We can't afford pool sizes as large as kPoolMaxSize on Windows <8.1 (see // We can't afford pool sizes as large as kPoolMaxSize on Windows <8.1 (see
// crbug.com/1101421 and crbug.com/1217759). // crbug.com/1101421 and crbug.com/1217759).
@ -213,14 +265,14 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
static constexpr size_t kBRPPoolSizeForLegacyWindows = 4 * kGiB; static constexpr size_t kBRPPoolSizeForLegacyWindows = 4 * kGiB;
static_assert(kRegularPoolSizeForLegacyWindows < kRegularPoolSize); static_assert(kRegularPoolSizeForLegacyWindows < kRegularPoolSize);
static_assert(kBRPPoolSizeForLegacyWindows < kBRPPoolSize); static_assert(kBRPPoolSizeForLegacyWindows < kBRPPoolSize);
static_assert(base::bits::IsPowerOfTwo(kRegularPoolSizeForLegacyWindows) && static_assert(base::bits::IsPowerOfTwo(kRegularPoolSizeForLegacyWindows));
base::bits::IsPowerOfTwo(kBRPPoolSizeForLegacyWindows)); static_assert(base::bits::IsPowerOfTwo(kBRPPoolSizeForLegacyWindows));
#endif // defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #endif // defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
static constexpr size_t kConfigurablePoolMaxSize = kPoolMaxSize; static constexpr size_t kConfigurablePoolMaxSize = kPoolMaxSize;
static constexpr size_t kConfigurablePoolMinSize = 1 * kGiB; static constexpr size_t kConfigurablePoolMinSize = 1 * kGiB;
static_assert(kConfigurablePoolMinSize <= kConfigurablePoolMaxSize); static_assert(kConfigurablePoolMinSize <= kConfigurablePoolMaxSize);
static_assert(base::bits::IsPowerOfTwo(kConfigurablePoolMaxSize) && static_assert(base::bits::IsPowerOfTwo(kConfigurablePoolMaxSize));
base::bits::IsPowerOfTwo(kConfigurablePoolMinSize)); static_assert(base::bits::IsPowerOfTwo(kConfigurablePoolMinSize));
#if BUILDFLAG(IS_IOS) #if BUILDFLAG(IS_IOS)
@ -235,8 +287,8 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
static constexpr size_t kBRPPoolSizeForIOSTestProcess = kGiB / 4; static constexpr size_t kBRPPoolSizeForIOSTestProcess = kGiB / 4;
static_assert(kRegularPoolSizeForIOSTestProcess < kRegularPoolSize); static_assert(kRegularPoolSizeForIOSTestProcess < kRegularPoolSize);
static_assert(kBRPPoolSizeForIOSTestProcess < kBRPPoolSize); static_assert(kBRPPoolSizeForIOSTestProcess < kBRPPoolSize);
static_assert(base::bits::IsPowerOfTwo(kRegularPoolSizeForIOSTestProcess) && static_assert(base::bits::IsPowerOfTwo(kRegularPoolSizeForIOSTestProcess));
base::bits::IsPowerOfTwo(kBRPPoolSizeForIOSTestProcess)); static_assert(base::bits::IsPowerOfTwo(kBRPPoolSizeForIOSTestProcess));
#endif // BUILDFLAG(IOS_IOS) #endif // BUILDFLAG(IOS_IOS)
#if !defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #if !defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
@ -249,6 +301,12 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
static constexpr uintptr_t kBRPPoolBaseMask = ~kBRPPoolOffsetMask; static constexpr uintptr_t kBRPPoolBaseMask = ~kBRPPoolOffsetMask;
#endif // !defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #endif // !defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
#if BUILDFLAG(ENABLE_PKEYS)
static constexpr uintptr_t kPkeyPoolOffsetMask =
static_cast<uintptr_t>(kPkeyPoolSize) - 1;
static constexpr uintptr_t kPkeyPoolBaseMask = ~kPkeyPoolOffsetMask;
#endif
// This must be set to such a value that IsIn*Pool() always returns false when // This must be set to such a value that IsIn*Pool() always returns false when
// the pool isn't initialized. // the pool isn't initialized.
static constexpr uintptr_t kUninitializedPoolBaseAddress = static constexpr uintptr_t kUninitializedPoolBaseAddress =
@ -262,11 +320,22 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
: regular_pool_base_address_(kUninitializedPoolBaseAddress), : regular_pool_base_address_(kUninitializedPoolBaseAddress),
brp_pool_base_address_(kUninitializedPoolBaseAddress), brp_pool_base_address_(kUninitializedPoolBaseAddress),
configurable_pool_base_address_(kUninitializedPoolBaseAddress), configurable_pool_base_address_(kUninitializedPoolBaseAddress),
#if BUILDFLAG(ENABLE_PKEYS)
pkey_pool_base_address_(kUninitializedPoolBaseAddress),
#endif
#if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
regular_pool_base_mask_(0), regular_pool_base_mask_(0),
brp_pool_base_mask_(0), brp_pool_base_mask_(0),
#if defined(PA_GLUE_CORE_POOLS)
core_pools_base_mask_(0),
#endif #endif
configurable_pool_base_mask_(0) { #endif // defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
configurable_pool_base_mask_(0)
#if BUILDFLAG(ENABLE_PKEYS)
,
pkey_(kInvalidPkey)
#endif
{
} }
// Using a union to enforce padding. // Using a union to enforce padding.
@ -275,30 +344,62 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAddressSpace {
uintptr_t regular_pool_base_address_; uintptr_t regular_pool_base_address_;
uintptr_t brp_pool_base_address_; uintptr_t brp_pool_base_address_;
uintptr_t configurable_pool_base_address_; uintptr_t configurable_pool_base_address_;
#if BUILDFLAG(ENABLE_PKEYS)
uintptr_t pkey_pool_base_address_;
#endif
#if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE) #if defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
uintptr_t regular_pool_base_mask_; uintptr_t regular_pool_base_mask_;
uintptr_t brp_pool_base_mask_; uintptr_t brp_pool_base_mask_;
#if defined(PA_GLUE_CORE_POOLS)
uintptr_t core_pools_base_mask_;
#endif #endif
#endif // defined(PA_DYNAMICALLY_SELECT_POOL_SIZE)
uintptr_t configurable_pool_base_mask_; uintptr_t configurable_pool_base_mask_;
#if BUILDFLAG(ENABLE_PKEYS)
int pkey_;
#endif
}; };
#if BUILDFLAG(ENABLE_PKEYS)
// With pkey support, we want to be able to pkey-tag all global metadata
// which requires page granularity.
char one_page_[SystemPageSize()];
#else
char one_cacheline_[kPartitionCachelineSize]; char one_cacheline_[kPartitionCachelineSize];
#endif
}; };
}; };
#if BUILDFLAG(ENABLE_PKEYS)
static_assert(sizeof(PoolSetup) % SystemPageSize() == 0,
"PoolSetup has to fill a page(s)");
#else
static_assert(sizeof(PoolSetup) % kPartitionCachelineSize == 0, static_assert(sizeof(PoolSetup) % kPartitionCachelineSize == 0,
"PoolSetup has to fill a cacheline(s)"); "PoolSetup has to fill a cacheline(s)");
#endif
// See the comment describing the address layout above. // See the comment describing the address layout above.
// //
// These are write-once fields, frequently accessed thereafter. Make sure they // These are write-once fields, frequently accessed thereafter. Make sure they
// don't share a cacheline with other, potentially writeable data, through // don't share a cacheline with other, potentially writeable data, through
// alignment and padding. // alignment and padding.
alignas(kPartitionCachelineSize) static PoolSetup setup_; #if BUILDFLAG(ENABLE_PKEYS)
static_assert(PA_PKEY_ALIGN_SZ >= kPartitionCachelineSize);
alignas(PA_PKEY_ALIGN_SZ)
#else
alignas(kPartitionCachelineSize)
#endif
static PoolSetup setup_ PA_CONSTINIT;
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA)
static std::ptrdiff_t regular_pool_shadow_offset_; static std::ptrdiff_t regular_pool_shadow_offset_;
static std::ptrdiff_t brp_pool_shadow_offset_; static std::ptrdiff_t brp_pool_shadow_offset_;
#endif #endif
#if BUILDFLAG(ENABLE_PKEYS)
// If we use a pkey pool, we need to tag its metadata with the pkey. Allow the
// function to get access to the PoolSetup.
friend void TagGlobalsWithPkey(int pkey);
#endif
}; };
PA_ALWAYS_INLINE std::pair<pool_handle, uintptr_t> GetPoolAndOffset( PA_ALWAYS_INLINE std::pair<pool_handle, uintptr_t> GetPoolAndOffset(
@ -331,6 +432,9 @@ PA_ALWAYS_INLINE bool IsManagedByPartitionAlloc(uintptr_t address) {
return internal::PartitionAddressSpace::IsInRegularPool(address) return internal::PartitionAddressSpace::IsInRegularPool(address)
#if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
|| internal::PartitionAddressSpace::IsInBRPPool(address) || internal::PartitionAddressSpace::IsInBRPPool(address)
#endif
#if BUILDFLAG(ENABLE_PKEYS)
|| internal::PartitionAddressSpace::IsInPkeyPool(address)
#endif #endif
|| internal::PartitionAddressSpace::IsInConfigurablePool(address); || internal::PartitionAddressSpace::IsInConfigurablePool(address);
} }
@ -345,12 +449,27 @@ PA_ALWAYS_INLINE bool IsManagedByPartitionAllocBRPPool(uintptr_t address) {
return internal::PartitionAddressSpace::IsInBRPPool(address); return internal::PartitionAddressSpace::IsInBRPPool(address);
} }
#if defined(PA_GLUE_CORE_POOLS)
// Checks whether the address belongs to either regular or BRP pool.
// Returns false for nullptr.
PA_ALWAYS_INLINE bool IsManagedByPartitionAllocCorePools(uintptr_t address) {
return internal::PartitionAddressSpace::IsInCorePools(address);
}
#endif // defined(PA_GLUE_CORE_POOLS)
// Returns false for nullptr. // Returns false for nullptr.
PA_ALWAYS_INLINE bool IsManagedByPartitionAllocConfigurablePool( PA_ALWAYS_INLINE bool IsManagedByPartitionAllocConfigurablePool(
uintptr_t address) { uintptr_t address) {
return internal::PartitionAddressSpace::IsInConfigurablePool(address); return internal::PartitionAddressSpace::IsInConfigurablePool(address);
} }
#if BUILDFLAG(ENABLE_PKEYS)
// Returns false for nullptr.
PA_ALWAYS_INLINE bool IsManagedByPartitionAllocPkeyPool(uintptr_t address) {
return internal::PartitionAddressSpace::IsInPkeyPool(address);
}
#endif
PA_ALWAYS_INLINE bool IsConfigurablePoolAvailable() { PA_ALWAYS_INLINE bool IsConfigurablePoolAvailable() {
return internal::PartitionAddressSpace::IsConfigurablePoolInitialized(); return internal::PartitionAddressSpace::IsConfigurablePoolInitialized();
} }

View File

@ -11,6 +11,7 @@
#include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h" #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h" #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
#include "base/allocator/partition_allocator/partition_ref_count.h" #include "base/allocator/partition_allocator/partition_ref_count.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/random.h" #include "base/allocator/partition_allocator/random.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -56,6 +57,10 @@ PA_ALWAYS_INLINE void DebugMemset(void* ptr, int value, size_t size) {
// of uininitialized / freed memory, and makes tests run significantly // of uininitialized / freed memory, and makes tests run significantly
// faster. Note that for direct-mapped allocations, memory is decomitted at // faster. Note that for direct-mapped allocations, memory is decomitted at
// free() time, so freed memory usage cannot happen. // free() time, so freed memory usage cannot happen.
#if BUILDFLAG(ENABLE_PKEYS)
LiftPkeyRestrictionsScope lift_pkey_restrictions;
#endif
size_t size_to_memset = std::min(size, size_t{1} << 19); size_t size_to_memset = std::min(size, size_t{1} << 19);
memset(ptr, value, size_to_memset); memset(ptr, value, size_to_memset);
} }

View File

@ -102,6 +102,9 @@ void PartitionAllocGlobalInit(OomFunction on_out_of_memory) {
} }
void PartitionAllocGlobalUninitForTesting() { void PartitionAllocGlobalUninitForTesting() {
#if BUILDFLAG(ENABLE_PKEYS)
internal::PartitionAddressSpace::UninitPkeyPoolForTesting();
#endif
#if BUILDFLAG(STARSCAN) #if BUILDFLAG(STARSCAN)
internal::PCScan::UninitForTesting(); // IN-TEST internal::PCScan::UninitForTesting(); // IN-TEST
#endif // BUILDFLAG(STARSCAN) #endif // BUILDFLAG(STARSCAN)

View File

@ -12,41 +12,59 @@ if (use_partition_alloc_as_malloc_default) {
} }
declare_args() { declare_args() {
# Temporarily move |use_allocator| to partition_alloc.gni, because # Whether PartitionAlloc should be available for use or not.
# some bots use |use_allocator|="none" with # true makes PartitionAlloc linked to the executable or shared library and
# |use_partition_alloc_as_malloc_default|=true. This causes PA_CHECK() # makes it available for use. It doesn't mean that the default allocator
# failure at PartitionAllocator::init(). # is PartitionAlloc, which is governed by |use_partition_alloc_as_malloc|.
# TODO(1151236): Replace |use_allocator|="none" and |use_allocator|= #
# "partition" with |use_partition_alloc_as_malloc|=false and # N.B. generally, embedders should look at this GN arg and at the
# |use_partition_alloc_as_malloc|=true, and remove |use_allocator| from # corresponding buildflag to determine whether to interact with PA
# args.gn of all trybots. //base/allocator will look at # source at all (pulling the component in via GN, including headers,
# |use_partition_alloc_as_malloc| and will generate buildflags. # etc.). There is nothing stopping a lazy embedder from ignoring this
# Memory allocator to use. Set to "none" to use default allocator. # and unconditionally using PA, but such a setup is inadvisable.
use_allocator = _default_allocator #
# This flag is currently set to false only on Cronet bots, because Cronet
# doesn't use PartitionAlloc at all, and doesn't wish to incur the library
# size increase (crbug.com/674570).
use_partition_alloc = true
}
declare_args() {
# PartitionAlloc-Everywhere (PA-E).
use_partition_alloc_as_malloc =
use_partition_alloc && use_partition_alloc_as_malloc_default
}
if (!use_partition_alloc) {
assert(
!use_partition_alloc_as_malloc,
"Can't use PartitionAlloc-Everywhere when PartitionAlloc is wholly disabled")
} }
declare_args() { declare_args() {
use_freeslot_bitmap = false use_freeslot_bitmap = false
# Puts the regular and BRP pools right next to each other, so that we can
# check "belongs to one of the two pools" with a single bitmask operation.
glue_core_pools = false
} }
declare_args() { declare_args() {
# Set use_backup_ref_ptr true to use BackupRefPtr (BRP) as the implementation # Build support for Use-after-Free protection via BackupRefPtr (BRP) or
# of raw_ptr<T>, and enable PartitionAlloc support for it. # MTECheckedPtr. To be effective, these need to be paired with raw_ptr<>.
#
# These are effective only for memory allocated from PartitionAlloc, so it is
# recommended to enable PA-E above, but isn't strictly necessary. Embedders
# can create and use PA partitions explicitly.
enable_backup_ref_ptr_support = enable_backup_ref_ptr_support =
enable_backup_ref_ptr_support_default && use_allocator == "partition" use_partition_alloc && enable_backup_ref_ptr_support_default
enable_mte_checked_ptr_support = enable_mte_checked_ptr_support =
enable_mte_checked_ptr_support_default && use_allocator == "partition" use_partition_alloc && enable_mte_checked_ptr_support_default
} }
assert(!(enable_backup_ref_ptr_support && enable_mte_checked_ptr_support), assert(!(enable_backup_ref_ptr_support && enable_mte_checked_ptr_support),
"MTECheckedPtrSupport conflicts with BRPSupport.") "MTECheckedPtrSupport conflicts with BRPSupport.")
declare_args() {
enable_partition_alloc_as_malloc_support =
use_partition_alloc_as_malloc_default && use_allocator == "partition"
}
declare_args() { declare_args() {
# - put_ref_count_in_previous_slot: place the ref-count at the end of the # - put_ref_count_in_previous_slot: place the ref-count at the end of the
# previous slot (or in metadata if a slot starts on the page boundary), as # previous slot (or in metadata if a slot starts on the page boundary), as
@ -60,8 +78,19 @@ declare_args() {
enable_backup_ref_ptr_slow_checks = enable_backup_ref_ptr_slow_checks =
enable_backup_ref_ptr_slow_checks_default && enable_backup_ref_ptr_support enable_backup_ref_ptr_slow_checks_default && enable_backup_ref_ptr_support
enable_dangling_raw_ptr_checks = enable_dangling_raw_ptr_checks =
enable_dangling_raw_ptr_checks_default && enable_backup_ref_ptr_support enable_dangling_raw_ptr_checks_default && enable_backup_ref_ptr_support
# Enables the dangling raw_ptr checks feature for the performance experiment.
# Not every dangling pointers have been fixed or annotated yet. To avoid
# accounting for the cost of calling the PA's embedder's callbacks when a
# dangling pointer has been detected, this simulates the raw_ptr to be
# allowed to dangle.
#
# This flag is temporary, and isn't used by PA embedders, so it doesn't need
# to go through build_overrides
enable_dangling_raw_ptr_perf_experiment = false
} }
declare_args() { declare_args() {
@ -85,6 +114,12 @@ assert(
enable_backup_ref_ptr_support || !enable_dangling_raw_ptr_checks, enable_backup_ref_ptr_support || !enable_dangling_raw_ptr_checks,
"Can't enable dangling raw_ptr checks if BackupRefPtr isn't enabled at all") "Can't enable dangling raw_ptr checks if BackupRefPtr isn't enabled at all")
# To run the dangling raw_ptr detector experiment, the underlying feature must
# be enabled too.
assert(
enable_dangling_raw_ptr_checks || !enable_dangling_raw_ptr_perf_experiment,
"Missing dangling pointer checks feature for its performance experiment")
declare_args() { declare_args() {
enable_pkeys = is_linux && target_cpu == "x64" enable_pkeys = is_linux && target_cpu == "x64"
} }

View File

@ -0,0 +1,23 @@
# `partition_alloc_base/`
This is a rough mirror of Chromium's `//base`, cut down to the necessary
files and contents that PartitionAlloc pulls in. Small tweaks (n.b.
macro renaming) have been made to prevent compilation issues, but we
generally prefer that this be a mostly unmutated subset of `//base`.
## Update Policy
TBD.
* This directory may drift out of sync with `//base`.
* We will merge security updates from Chromium's `//base` once we are
made aware of them.
* We may elect to freshen files when we need to use new `//base`
functionality in PA.
## Augmentation Policy
Prefer not to directly modify contents here. Add them into
`augmentations/`, documenting the usage and provenance of each addition.

View File

@ -0,0 +1,22 @@
// Copyright 2022 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_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_AUGMENTATIONS_COMPILER_SPECIFIC_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_AUGMENTATIONS_COMPILER_SPECIFIC_H_
// Extensions for PA's copy of `//base/compiler_specific.h`.
#include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
// PA_ATTRIBUTE_RETURNS_NONNULL
//
// Tells the compiler that a function never returns a null pointer.
// Sourced from Abseil's `attributes.h`.
#if PA_HAS_ATTRIBUTE(returns_nonnull)
#define PA_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#define PA_ATTRIBUTE_RETURNS_NONNULL
#endif
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_AUGMENTATIONS_COMPILER_SPECIFIC_H_

View File

@ -98,8 +98,11 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) CheckError {
LogMessage* log_message_; LogMessage* log_message_;
}; };
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && \ #if defined(OFFICIAL_BUILD) && !defined(NDEBUG)
!BUILDFLAG(PA_DCHECK_IS_CONFIGURABLE) #error "Debug builds are not expected to be optimized as official builds."
#endif // defined(OFFICIAL_BUILD) && !defined(NDEBUG)
#if defined(OFFICIAL_BUILD) && !BUILDFLAG(PA_DCHECK_IS_ON)
// Discard log strings to reduce code bloat. // Discard log strings to reduce code bloat.
// //

View File

@ -147,6 +147,8 @@ void CPU::Initialize() {
has_aesni_ = (cpu_info[2] & 0x02000000) != 0; has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
has_fma3_ = (cpu_info[2] & 0x00001000) != 0; has_fma3_ = (cpu_info[2] & 0x00001000) != 0;
has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0; has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
has_pku_ = (cpu_info7[2] & 0x00000008) != 0;
} }
// Get the brand string of the cpu. // Get the brand string of the cpu.

View File

@ -68,6 +68,13 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) CPU final {
constexpr bool has_bti() const { return false; } constexpr bool has_bti() const { return false; }
#endif #endif
#if defined(ARCH_CPU_X86_FAMILY)
// Memory protection key support for user-mode pages
bool has_pku() const { return has_pku_; }
#else
constexpr bool has_pku() const { return false; }
#endif
private: private:
// Query the processor for CPUID information. // Query the processor for CPUID information.
void Initialize(); void Initialize();
@ -90,6 +97,9 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) CPU final {
#if defined(ARCH_CPU_ARM_FAMILY) #if defined(ARCH_CPU_ARM_FAMILY)
bool has_mte_ = false; // Armv8.5-A MTE (Memory Taggging Extension) bool has_mte_ = false; // Armv8.5-A MTE (Memory Taggging Extension)
bool has_bti_ = false; // Armv8.5-A BTI (Branch Target Identification) bool has_bti_ = false; // Armv8.5-A BTI (Branch Target Identification)
#endif
#if defined(ARCH_CPU_X86_FAMILY)
bool has_pku_ = false;
#endif #endif
bool has_non_stop_time_stamp_counter_ = false; bool has_non_stop_time_stamp_counter_ = false;
bool is_running_in_vm_ = false; bool is_running_in_vm_ = false;

View File

@ -0,0 +1,16 @@
// Copyright 2022 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_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_WIN_WIN_HANDLE_TYPES_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_WIN_WIN_HANDLE_TYPES_H_
// Forward declare Windows compatible handles.
#define PA_WINDOWS_HANDLE_TYPE(name) \
struct name##__; \
typedef struct name##__* name;
#include "base/allocator/partition_allocator/partition_alloc_base/win/win_handle_types_list.inc"
#undef PA_WINDOWS_HANDLE_TYPE
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_WIN_WIN_HANDLE_TYPES_H_

View File

@ -0,0 +1,25 @@
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file intentionally does not have header guards, it's included
// inside a macro to generate enum values. The following line silences a
// presubmit and Tricium warning that would otherwise be triggered by this:
// no-include-guard-because-multiply-included
// NOLINT(build/header_guard)
// This file contains the list of Windows handle types that can be recognized
// via specific pointee types declared in //base/win/windows_types.h
// (e.g. `HDC` points to a fake/forward-declared `HDC__` struct).
PA_WINDOWS_HANDLE_TYPE(HDC)
PA_WINDOWS_HANDLE_TYPE(HDESK)
PA_WINDOWS_HANDLE_TYPE(HGLRC)
PA_WINDOWS_HANDLE_TYPE(HICON)
PA_WINDOWS_HANDLE_TYPE(HINSTANCE)
PA_WINDOWS_HANDLE_TYPE(HKEY)
PA_WINDOWS_HANDLE_TYPE(HKL)
PA_WINDOWS_HANDLE_TYPE(HMENU)
PA_WINDOWS_HANDLE_TYPE(HWINSTA)
PA_WINDOWS_HANDLE_TYPE(HWND)
PA_WINDOWS_HANDLE_TYPE(HMONITOR)

View File

@ -46,6 +46,14 @@ static_assert(sizeof(void*) != 8, "");
#endif // defined(PA_HAS_64_BITS_POINTERS) && #endif // defined(PA_HAS_64_BITS_POINTERS) &&
// (BUILDFLAG(IS_IOS) || BUILDFLAG(IS_WIN)) // (BUILDFLAG(IS_IOS) || BUILDFLAG(IS_WIN))
// Puts the regular and BRP pools right next to each other, so that we can
// check "belongs to one of the two pools" with a single bitmask operation.
//
// This setting is specific to 64-bit, as 32-bit has a different implementation.
#if defined(PA_HAS_64_BITS_POINTERS) && BUILDFLAG(GLUE_CORE_POOLS)
#define PA_GLUE_CORE_POOLS
#endif
#if defined(PA_HAS_64_BITS_POINTERS) && \ #if defined(PA_HAS_64_BITS_POINTERS) && \
(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)) (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID))
#include <linux/version.h> #include <linux/version.h>
@ -138,8 +146,19 @@ static_assert(sizeof(void*) != 8, "");
#define PA_HAS_FREELIST_SHADOW_ENTRY #define PA_HAS_FREELIST_SHADOW_ENTRY
#endif #endif
// Build MTECheckedPtr code.
//
// Only applicable to code with 64-bit pointers. Currently conflicts with true
// hardware MTE.
#if BUILDFLAG(ENABLE_MTE_CHECKED_PTR_SUPPORT) && \
defined(PA_HAS_64_BITS_POINTERS) && !defined(PA_HAS_MEMORY_TAGGING)
#define PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS
#endif // BUILDFLAG(ENABLE_MTE_CHECKED_PTR_SUPPORT) &&
// defined(PA_HAS_64_BITS_POINTERS) && !defined(PA_HAS_MEMORY_TAGGING)
// Specifies whether allocation extras need to be added. // Specifies whether allocation extras need to be added.
#if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \
defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
#define PA_EXTRAS_REQUIRED #define PA_EXTRAS_REQUIRED
#endif #endif
@ -242,16 +261,6 @@ constexpr bool kUseLazyCommit = false;
#define PA_PREFER_SMALLER_SLOT_SPANS #define PA_PREFER_SMALLER_SLOT_SPANS
#endif // BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)) #endif // BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64))
// Build MTECheckedPtr code.
//
// Only applicable to code with 64-bit pointers. Currently conflicts with true
// hardware MTE.
#if BUILDFLAG(ENABLE_MTE_CHECKED_PTR_SUPPORT) && \
defined(PA_HAS_64_BITS_POINTERS) && !defined(PA_HAS_MEMORY_TAGGING)
#define PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS
#endif // BUILDFLAG(ENABLE_MTE_CHECKED_PTR_SUPPORT) &&
// defined(PA_HAS_64_BITS_POINTERS) && !defined(PA_HAS_MEMORY_TAGGING)
// Enable shadow metadata. // Enable shadow metadata.
// //
// With this flag, shadow pools will be mapped, on which writable shadow // With this flag, shadow pools will be mapped, on which writable shadow

View File

@ -261,7 +261,11 @@ constexpr size_t kSuperPageBaseMask = ~kSuperPageOffsetMask;
// PartitionAlloc's address space is split into pools. See `glossary.md`. // PartitionAlloc's address space is split into pools. See `glossary.md`.
#if defined(PA_HAS_64_BITS_POINTERS) #if defined(PA_HAS_64_BITS_POINTERS)
#if BUILDFLAG(ENABLE_PKEYS)
constexpr size_t kNumPools = 4;
#else
constexpr size_t kNumPools = 3; constexpr size_t kNumPools = 3;
#endif
// Maximum pool size. With exception of Configurable Pool, it is also // Maximum pool size. With exception of Configurable Pool, it is also
// the actual size, unless PA_DYNAMICALLY_SELECT_POOL_SIZE is set, which // the actual size, unless PA_DYNAMICALLY_SELECT_POOL_SIZE is set, which
// allows to choose a different size at initialization time for certain // allows to choose a different size at initialization time for certain
@ -284,6 +288,12 @@ constexpr size_t kMaxSuperPagesInPool = kPoolMaxSize / kSuperPageSize;
static constexpr pool_handle kRegularPoolHandle = 1; static constexpr pool_handle kRegularPoolHandle = 1;
static constexpr pool_handle kBRPPoolHandle = 2; static constexpr pool_handle kBRPPoolHandle = 2;
static constexpr pool_handle kConfigurablePoolHandle = 3; static constexpr pool_handle kConfigurablePoolHandle = 3;
#if BUILDFLAG(ENABLE_PKEYS)
static constexpr pool_handle kPkeyPoolHandle = 4;
static_assert(
kPkeyPoolHandle == kNumPools,
"The pkey pool must come last since we pkey_mprotect its metadata.");
#endif
// Slots larger than this size will not receive MTE protection. Pages intended // Slots larger than this size will not receive MTE protection. Pages intended
// for allocations larger than this constant should not be backed with PROT_MTE // for allocations larger than this constant should not be backed with PROT_MTE

View File

@ -306,9 +306,11 @@ SlotSpanMetadata<thread_safe>* PartitionDirectMap(
RecommitSystemPages(reservation_start + SystemPageSize(), RecommitSystemPages(reservation_start + SystemPageSize(),
SystemPageSize(), SystemPageSize(),
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA)
PageAccessibilityConfiguration::kRead, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kRead),
#else #else
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
#endif #endif
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
@ -321,7 +323,8 @@ SlotSpanMetadata<thread_safe>* PartitionDirectMap(
ScopedSyscallTimer timer{root}; ScopedSyscallTimer timer{root};
RecommitSystemPages(reservation_start + SystemPageSize() * 2, RecommitSystemPages(reservation_start + SystemPageSize() * 2,
SystemPageSize(), SystemPageSize(),
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
#endif #endif
@ -331,7 +334,8 @@ SlotSpanMetadata<thread_safe>* PartitionDirectMap(
ScopedSyscallTimer timer{root}; ScopedSyscallTimer timer{root};
RecommitSystemPages(ShadowMetadataStart(reservation_start, pool), RecommitSystemPages(ShadowMetadataStart(reservation_start, pool),
SystemPageSize(), SystemPageSize(),
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
#endif #endif
@ -708,7 +712,8 @@ PartitionBucket<thread_safe>::AllocNewSlotSpan(PartitionRoot<thread_safe>* root,
#endif #endif
SetSystemPagesAccess(root->next_tag_bitmap_page, SetSystemPagesAccess(root->next_tag_bitmap_page,
next_tag_bitmap_page - root->next_tag_bitmap_page, next_tag_bitmap_page - root->next_tag_bitmap_page,
PageAccessibilityConfiguration::kReadWrite); PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kReadWrite));
root->next_tag_bitmap_page = next_tag_bitmap_page; root->next_tag_bitmap_page = next_tag_bitmap_page;
} }
#endif // defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS) #endif // defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
@ -807,9 +812,11 @@ PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::InitializeSuperPage(
ScopedSyscallTimer timer{root}; ScopedSyscallTimer timer{root};
RecommitSystemPages(super_page + SystemPageSize(), SystemPageSize(), RecommitSystemPages(super_page + SystemPageSize(), SystemPageSize(),
#if defined(PA_ENABLE_SHADOW_METADATA) #if defined(PA_ENABLE_SHADOW_METADATA)
PageAccessibilityConfiguration::kRead, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kRead),
#else #else
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
#endif #endif
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
@ -820,7 +827,8 @@ PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::InitializeSuperPage(
if (root->ChoosePool() == kBRPPoolHandle) { if (root->ChoosePool() == kBRPPoolHandle) {
ScopedSyscallTimer timer{root}; ScopedSyscallTimer timer{root};
RecommitSystemPages(super_page + SystemPageSize() * 2, SystemPageSize(), RecommitSystemPages(super_page + SystemPageSize() * 2, SystemPageSize(),
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
#endif #endif
@ -830,7 +838,8 @@ PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::InitializeSuperPage(
ScopedSyscallTimer timer{root}; ScopedSyscallTimer timer{root};
RecommitSystemPages(ShadowMetadataStart(super_page, root->ChoosePool()), RecommitSystemPages(ShadowMetadataStart(super_page, root->ChoosePool()),
SystemPageSize(), SystemPageSize(),
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
#endif #endif
@ -902,7 +911,8 @@ PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::InitializeSuperPage(
{ {
ScopedSyscallTimer timer{root}; ScopedSyscallTimer timer{root};
RecommitSystemPages(state_bitmap, state_bitmap_size_to_commit, RecommitSystemPages(state_bitmap, state_bitmap_size_to_commit,
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
PCScan::RegisterNewSuperPage(root, super_page); PCScan::RegisterNewSuperPage(root, super_page);
@ -917,7 +927,8 @@ PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::InitializeSuperPage(
PA_DCHECK(SuperPageFreeSlotBitmapAddr(super_page) == freeslot_bitmap_addr); PA_DCHECK(SuperPageFreeSlotBitmapAddr(super_page) == freeslot_bitmap_addr);
ScopedSyscallTimer timer{root}; ScopedSyscallTimer timer{root};
RecommitSystemPages(freeslot_bitmap_addr, CommittedFreeSlotBitmapSize(), RecommitSystemPages(freeslot_bitmap_addr, CommittedFreeSlotBitmapSize(),
PageAccessibilityConfiguration::kReadWrite, root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
} }
#endif #endif

View File

@ -14,6 +14,7 @@
#include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h" #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
#include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h" #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread.h"
#include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/spinning_mutex.h" #include "base/allocator/partition_allocator/spinning_mutex.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -24,6 +25,10 @@ class PA_LOCKABLE Lock {
inline constexpr Lock(); inline constexpr Lock();
void Acquire() PA_EXCLUSIVE_LOCK_FUNCTION() { void Acquire() PA_EXCLUSIVE_LOCK_FUNCTION() {
#if BUILDFLAG(PA_DCHECK_IS_ON) #if BUILDFLAG(PA_DCHECK_IS_ON)
#if BUILDFLAG(ENABLE_PKEYS)
LiftPkeyRestrictionsScope lift_pkey_restrictions;
#endif
// When PartitionAlloc is malloc(), it can easily become reentrant. For // When PartitionAlloc is malloc(), it can easily become reentrant. For
// instance, a DCHECK() triggers in external code (such as // instance, a DCHECK() triggers in external code (such as
// base::Lock). DCHECK() error message formatting allocates, which triggers // base::Lock). DCHECK() error message formatting allocates, which triggers
@ -69,6 +74,9 @@ class PA_LOCKABLE Lock {
void AssertAcquired() const PA_ASSERT_EXCLUSIVE_LOCK() { void AssertAcquired() const PA_ASSERT_EXCLUSIVE_LOCK() {
lock_.AssertAcquired(); lock_.AssertAcquired();
#if BUILDFLAG(PA_DCHECK_IS_ON) #if BUILDFLAG(PA_DCHECK_IS_ON)
#if BUILDFLAG(ENABLE_PKEYS)
LiftPkeyRestrictionsScope lift_pkey_restrictions;
#endif
PA_DCHECK(owning_thread_ref_.load(std ::memory_order_acquire) == PA_DCHECK(owning_thread_ref_.load(std ::memory_order_acquire) ==
base::PlatformThread::CurrentRef()); base::PlatformThread::CurrentRef());
#endif #endif
@ -89,7 +97,8 @@ class PA_LOCKABLE Lock {
#if BUILDFLAG(PA_DCHECK_IS_ON) #if BUILDFLAG(PA_DCHECK_IS_ON)
// Should in theory be protected by |lock_|, but we need to read it to detect // Should in theory be protected by |lock_|, but we need to read it to detect
// recursive lock acquisition (and thus, the allocator becoming reentrant). // recursive lock acquisition (and thus, the allocator becoming reentrant).
std::atomic<base::PlatformThreadRef> owning_thread_ref_{}; std::atomic<base::PlatformThreadRef> owning_thread_ref_ =
base::PlatformThreadRef();
#endif #endif
}; };

View File

@ -334,10 +334,17 @@ void UnmapNow(uintptr_t reservation_start,
} else } else
#endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
{ {
PA_DCHECK(pool == kRegularPoolHandle || (IsConfigurablePoolAvailable() && PA_DCHECK(
pool == kConfigurablePoolHandle)); pool == kRegularPoolHandle
#if BUILDFLAG(ENABLE_PKEYS)
|| pool == kPkeyPoolHandle
#endif
|| (IsConfigurablePoolAvailable() && pool == kConfigurablePoolHandle));
// Non-BRP pools don't need adjustment that BRP needs in 32-bit mode. // Non-BRP pools don't need adjustment that BRP needs in 32-bit mode.
PA_DCHECK(IsManagedByPartitionAllocRegularPool(reservation_start) || PA_DCHECK(IsManagedByPartitionAllocRegularPool(reservation_start) ||
#if BUILDFLAG(ENABLE_PKEYS)
IsManagedByPartitionAllocPkeyPool(reservation_start) ||
#endif
IsManagedByPartitionAllocConfigurablePool(reservation_start)); IsManagedByPartitionAllocConfigurablePool(reservation_start));
} }
#endif // BUILDFLAG(PA_DCHECK_IS_ON) #endif // BUILDFLAG(PA_DCHECK_IS_ON)

View File

@ -108,9 +108,17 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRefCount {
// https://docs.google.com/document/d/1cSTVDVEE-8l2dXLPcfyN75r6ihMbeiSp1ncL9ae3RZE // https://docs.google.com/document/d/1cSTVDVEE-8l2dXLPcfyN75r6ihMbeiSp1ncL9ae3RZE
PA_ALWAYS_INLINE void Acquire() { PA_ALWAYS_INLINE void Acquire() {
CheckCookieIfSupported(); CheckCookieIfSupported();
CountType old_count = count_.fetch_add(kPtrInc, std::memory_order_relaxed);
#if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_PERF_EXPERIMENT)
constexpr CountType kInc = kUnprotectedPtrInc;
constexpr CountType kMask = kUnprotectedPtrCountMask;
#else
constexpr CountType kInc = kPtrInc;
constexpr CountType kMask = kPtrCountMask;
#endif
CountType old_count = count_.fetch_add(kInc, std::memory_order_relaxed);
// Check overflow. // Check overflow.
PA_CHECK((old_count & kPtrCountMask) != kPtrCountMask); PA_CHECK((old_count & kMask) != kMask);
} }
// Similar to |Acquire()|, but for raw_ptr<T, DisableDanglingPtrDetection> // Similar to |Acquire()|, but for raw_ptr<T, DisableDanglingPtrDetection>
@ -130,11 +138,18 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRefCount {
// Returns true if the allocation should be reclaimed. // Returns true if the allocation should be reclaimed.
PA_ALWAYS_INLINE bool Release() { PA_ALWAYS_INLINE bool Release() {
#if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_PERF_EXPERIMENT)
constexpr CountType kInc = kUnprotectedPtrInc;
constexpr CountType kMask = kUnprotectedPtrCountMask;
#else
constexpr CountType kInc = kPtrInc;
constexpr CountType kMask = kPtrCountMask;
#endif
CheckCookieIfSupported(); CheckCookieIfSupported();
CountType old_count = count_.fetch_sub(kPtrInc, std::memory_order_release); CountType old_count = count_.fetch_sub(kInc, std::memory_order_release);
// Check underflow. // Check underflow.
PA_DCHECK(old_count & kPtrCountMask); PA_DCHECK(old_count & kMask);
#if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) #if BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS)
// If a dangling raw_ptr<> was detected, report it. // If a dangling raw_ptr<> was detected, report it.
@ -145,7 +160,7 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRefCount {
} }
#endif #endif
return ReleaseCommon(old_count - kPtrInc); return ReleaseCommon(old_count - kInc);
} }
// Similar to |Release()|, but for raw_ptr<T, DisableDanglingPtrDetection> // Similar to |Release()|, but for raw_ptr<T, DisableDanglingPtrDetection>

View File

@ -24,6 +24,7 @@
#include "base/allocator/partition_allocator/partition_cookie.h" #include "base/allocator/partition_allocator/partition_cookie.h"
#include "base/allocator/partition_allocator/partition_oom.h" #include "base/allocator/partition_allocator/partition_oom.h"
#include "base/allocator/partition_allocator/partition_page.h" #include "base/allocator/partition_allocator/partition_page.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h" #include "base/allocator/partition_allocator/reservation_offset_table.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -640,6 +641,16 @@ void DCheckIfManagedByPartitionAllocBRPPool(uintptr_t address) {
} }
#endif #endif
#if BUILDFLAG(ENABLE_PKEYS)
void PartitionAllocPkeyInit(int pkey) {
PkeySettings::settings.enabled = true;
PartitionAddressSpace::InitPkeyPool(pkey);
// Call TagGlobalsWithPkey last since we might not have write permissions to
// to memory tagged with `pkey` at this point.
TagGlobalsWithPkey(pkey);
}
#endif // BUILDFLAG(ENABLE_PKEYS)
} // namespace internal } // namespace internal
template <bool thread_safe> template <bool thread_safe>
@ -717,9 +728,15 @@ void PartitionRoot<thread_safe>::DestructForTesting() {
auto* curr = first_extent; auto* curr = first_extent;
while (curr != nullptr) { while (curr != nullptr) {
auto* next = curr->next; auto* next = curr->next;
uintptr_t address = SuperPagesBeginFromExtent(curr);
size_t size =
internal::kSuperPageSize * curr->number_of_consecutive_super_pages;
#if !defined(PA_HAS_64_BITS_POINTERS)
internal::AddressPoolManager::GetInstance().MarkUnused(pool_handle, address,
size);
#endif
internal::AddressPoolManager::GetInstance().UnreserveAndDecommit( internal::AddressPoolManager::GetInstance().UnreserveAndDecommit(
pool_handle, SuperPagesBeginFromExtent(curr), pool_handle, address, size);
internal::kSuperPageSize * curr->number_of_consecutive_super_pages);
curr = next; curr = next;
} }
} }
@ -731,6 +748,44 @@ void PartitionRoot<thread_safe>::EnableMac11MallocSizeHackForTesting() {
} }
#endif // defined(PA_ENABLE_MAC11_MALLOC_SIZE_HACK) #endif // defined(PA_ENABLE_MAC11_MALLOC_SIZE_HACK)
#if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) && \
!defined(PA_HAS_64_BITS_POINTERS)
namespace {
std::atomic<bool> g_reserve_brp_guard_region_called;
// An address constructed by repeating `kQuarantinedByte` shouldn't never point
// to valid memory. Preemptively reserve a memory region around that address and
// make it inaccessible. Not needed for 64-bit platforms where the address is
// guaranteed to be non-canonical. Safe to call multiple times.
void ReserveBackupRefPtrGuardRegionIfNeeded() {
bool expected = false;
// No need to block execution for potential concurrent initialization, merely
// want to make sure this is only called once.
if (!g_reserve_brp_guard_region_called.compare_exchange_strong(expected,
true))
return;
size_t alignment = internal::PageAllocationGranularity();
uintptr_t requested_address;
memset(&requested_address, internal::kQuarantinedByte,
sizeof(requested_address));
requested_address = RoundDownToPageAllocationGranularity(requested_address);
// Request several pages so that even unreasonably large C++ objects stay
// within the inaccessible region. If some of the pages can't be reserved,
// it's still preferable to try and reserve the rest.
for (size_t i = 0; i < 4; ++i) {
[[maybe_unused]] uintptr_t allocated_address =
AllocPages(requested_address, alignment, alignment,
PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
PageTag::kPartitionAlloc);
requested_address += alignment;
}
}
} // namespace
#endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) &&
// !defined(PA_HAS_64_BITS_POINTERS)
template <bool thread_safe> template <bool thread_safe>
void PartitionRoot<thread_safe>::Init(PartitionOptions opts) { void PartitionRoot<thread_safe>::Init(PartitionOptions opts) {
{ {
@ -762,6 +817,11 @@ void PartitionRoot<thread_safe>::Init(PartitionOptions opts) {
internal::PartitionAddressSpace::Init(); internal::PartitionAddressSpace::Init();
#endif #endif
#if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) && \
!defined(PA_HAS_64_BITS_POINTERS)
ReserveBackupRefPtrGuardRegionIfNeeded();
#endif
flags.allow_aligned_alloc = flags.allow_aligned_alloc =
opts.aligned_alloc == PartitionOptions::AlignedAlloc::kAllowed; opts.aligned_alloc == PartitionOptions::AlignedAlloc::kAllowed;
flags.allow_cookie = opts.cookie == PartitionOptions::Cookie::kAllowed; flags.allow_cookie = opts.cookie == PartitionOptions::Cookie::kAllowed;
@ -789,6 +849,14 @@ void PartitionRoot<thread_safe>::Init(PartitionOptions opts) {
// BRP requires objects to be in a different Pool. // BRP requires objects to be in a different Pool.
PA_CHECK(!(flags.use_configurable_pool && brp_enabled())); PA_CHECK(!(flags.use_configurable_pool && brp_enabled()));
#if BUILDFLAG(ENABLE_PKEYS)
// BRP and pkey mode use different pools, so they can't be enabled at the
// same time.
PA_CHECK(opts.pkey == internal::kDefaultPkey ||
opts.backup_ref_ptr == PartitionOptions::BackupRefPtr::kDisabled);
flags.pkey = opts.pkey;
#endif
// Ref-count messes up alignment needed for AlignedAlloc, making this // Ref-count messes up alignment needed for AlignedAlloc, making this
// option incompatible. However, except in the // option incompatible. However, except in the
// PUT_REF_COUNT_IN_PREVIOUS_SLOT case. // PUT_REF_COUNT_IN_PREVIOUS_SLOT case.
@ -812,6 +880,11 @@ void PartitionRoot<thread_safe>::Init(PartitionOptions opts) {
flags.extras_size += internal::kPartitionRefCountSizeAdjustment; flags.extras_size += internal::kPartitionRefCountSizeAdjustment;
flags.extras_offset += internal::kPartitionRefCountOffsetAdjustment; flags.extras_offset += internal::kPartitionRefCountOffsetAdjustment;
} }
#if defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
// Add one extra byte to each slot's end to allow beyond-the-end
// pointers (crbug.com/1364476).
flags.extras_size += 1;
#endif // defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
#endif // defined(PA_EXTRAS_REQUIRED) #endif // defined(PA_EXTRAS_REQUIRED)
// Re-confirm the above PA_CHECKs, by making sure there are no // Re-confirm the above PA_CHECKs, by making sure there are no
@ -879,6 +952,12 @@ void PartitionRoot<thread_safe>::Init(PartitionOptions opts) {
#if BUILDFLAG(ENABLE_PARTITION_ALLOC_AS_MALLOC_SUPPORT) #if BUILDFLAG(ENABLE_PARTITION_ALLOC_AS_MALLOC_SUPPORT)
PartitionAllocMallocInitOnce(); PartitionAllocMallocInitOnce();
#endif #endif
#if BUILDFLAG(ENABLE_PKEYS)
if (flags.pkey != internal::kDefaultPkey) {
internal::PartitionAllocPkeyInit(flags.pkey);
}
#endif
} }
template <bool thread_safe> template <bool thread_safe>
@ -960,6 +1039,7 @@ bool PartitionRoot<thread_safe>::TryReallocInPlaceForDirectMap(
// bucket->slot_size is the currently committed size of the allocation. // bucket->slot_size is the currently committed size of the allocation.
size_t current_slot_size = slot_span->bucket->slot_size; size_t current_slot_size = slot_span->bucket->slot_size;
size_t current_usable_size = slot_span->GetUsableSize(this);
uintptr_t slot_start = SlotSpan::ToSlotSpanStart(slot_span); uintptr_t slot_start = SlotSpan::ToSlotSpanStart(slot_span);
// This is the available part of the reservation up to which the new // This is the available part of the reservation up to which the new
// allocation can grow. // allocation can grow.
@ -1013,6 +1093,16 @@ bool PartitionRoot<thread_safe>::TryReallocInPlaceForDirectMap(
IncreaseTotalSizeOfAllocatedBytes(reinterpret_cast<uintptr_t>(slot_span), IncreaseTotalSizeOfAllocatedBytes(reinterpret_cast<uintptr_t>(slot_span),
slot_span->bucket->slot_size, raw_size); slot_span->bucket->slot_size, raw_size);
// Always record in-place realloc() as free()+malloc() pair.
//
// The early returns above (`return false`) will fall back to free()+malloc(),
// so this is consistent.
auto* thread_cache = GetOrCreateThreadCache();
if (ThreadCache::IsValid(thread_cache)) {
thread_cache->RecordDeallocation(current_usable_size);
thread_cache->RecordAllocation(slot_span->GetUsableSize(this));
}
#if BUILDFLAG(PA_DCHECK_IS_ON) #if BUILDFLAG(PA_DCHECK_IS_ON)
// Write a new trailing cookie. // Write a new trailing cookie.
if (flags.allow_cookie) { if (flags.allow_cookie) {
@ -1037,8 +1127,10 @@ bool PartitionRoot<thread_safe>::TryReallocInPlaceForNormalBuckets(
// new size is a significant percentage smaller. We could do the same if we // new size is a significant percentage smaller. We could do the same if we
// determine it is a win. // determine it is a win.
if (AllocationCapacityFromRequestedSize(new_size) != if (AllocationCapacityFromRequestedSize(new_size) !=
AllocationCapacityFromSlotStart(slot_start)) AllocationCapacityFromSlotStart(slot_start)) {
return false; return false;
}
size_t current_usable_size = slot_span->GetUsableSize(this);
// Trying to allocate |new_size| would use the same amount of underlying // Trying to allocate |new_size| would use the same amount of underlying
// memory as we're already using, so re-use the allocation after updating // memory as we're already using, so re-use the allocation after updating
@ -1070,6 +1162,16 @@ bool PartitionRoot<thread_safe>::TryReallocInPlaceForNormalBuckets(
} }
#endif // BUILDFLAG(PA_DCHECK_IS_ON) #endif // BUILDFLAG(PA_DCHECK_IS_ON)
} }
// Always record a realloc() as a free() + malloc(), even if it's in
// place. When we cannot do it in place (`return false` above), the allocator
// falls back to free()+malloc(), so this is consistent.
ThreadCache* thread_cache = GetOrCreateThreadCache();
if (PA_LIKELY(ThreadCache::IsValid(thread_cache))) {
thread_cache->RecordDeallocation(current_usable_size);
thread_cache->RecordAllocation(slot_span->GetUsableSize(this));
}
return object; return object;
} }
@ -1369,9 +1471,7 @@ void PartitionRoot<thread_safe>::ResetBookkeepingForTesting() {
} }
template <> template <>
uintptr_t PartitionRoot<internal::ThreadSafe>::MaybeInitThreadCacheAndAlloc( ThreadCache* PartitionRoot<internal::ThreadSafe>::MaybeInitThreadCache() {
uint16_t bucket_index,
size_t* slot_size) {
auto* tcache = ThreadCache::Get(); auto* tcache = ThreadCache::Get();
// See comment in `EnableThreadCacheIfSupport()` for why this is an acquire // See comment in `EnableThreadCacheIfSupport()` for why this is an acquire
// load. // load.
@ -1384,7 +1484,7 @@ uintptr_t PartitionRoot<internal::ThreadSafe>::MaybeInitThreadCacheAndAlloc(
// be us, in which case we are re-entering and should not create a thread // be us, in which case we are re-entering and should not create a thread
// cache. If it is not us, then this merely delays thread cache // cache. If it is not us, then this merely delays thread cache
// construction a bit, which is not an issue. // construction a bit, which is not an issue.
return 0; return nullptr;
} }
// There is no per-thread ThreadCache allocated here yet, and this partition // There is no per-thread ThreadCache allocated here yet, and this partition
@ -1407,10 +1507,7 @@ uintptr_t PartitionRoot<internal::ThreadSafe>::MaybeInitThreadCacheAndAlloc(
tcache = ThreadCache::Create(this); tcache = ThreadCache::Create(this);
thread_caches_being_constructed_.fetch_sub(1, std::memory_order_relaxed); thread_caches_being_constructed_.fetch_sub(1, std::memory_order_relaxed);
// Cache is created empty, but at least this will trigger batch fill, which return tcache;
// may be useful, and we are already in a slow path anyway (first small
// allocation of this thread).
return tcache->GetFromCache(bucket_index, slot_size);
} }
template <> template <>

View File

@ -66,6 +66,7 @@
#include "base/allocator/partition_allocator/partition_ref_count.h" #include "base/allocator/partition_allocator/partition_ref_count.h"
#include "base/allocator/partition_allocator/partition_tag.h" #include "base/allocator/partition_allocator/partition_tag.h"
#include "base/allocator/partition_allocator/partition_tag_types.h" #include "base/allocator/partition_allocator/partition_tag_types.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h" #include "base/allocator/partition_allocator/reservation_offset_table.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
#include "base/allocator/partition_allocator/thread_cache.h" #include "base/allocator/partition_allocator/thread_cache.h"
@ -203,14 +204,25 @@ struct PartitionOptions {
Cookie cookie, Cookie cookie,
BackupRefPtr backup_ref_ptr, BackupRefPtr backup_ref_ptr,
BackupRefPtrZapping backup_ref_ptr_zapping, BackupRefPtrZapping backup_ref_ptr_zapping,
UseConfigurablePool use_configurable_pool) UseConfigurablePool use_configurable_pool
#if BUILDFLAG(ENABLE_PKEYS)
,
int pkey = internal::kDefaultPkey
#endif
)
: aligned_alloc(aligned_alloc), : aligned_alloc(aligned_alloc),
thread_cache(thread_cache), thread_cache(thread_cache),
quarantine(quarantine), quarantine(quarantine),
cookie(cookie), cookie(cookie),
backup_ref_ptr(backup_ref_ptr), backup_ref_ptr(backup_ref_ptr),
backup_ref_ptr_zapping(backup_ref_ptr_zapping), backup_ref_ptr_zapping(backup_ref_ptr_zapping),
use_configurable_pool(use_configurable_pool) {} use_configurable_pool(use_configurable_pool)
#if BUILDFLAG(ENABLE_PKEYS)
,
pkey(pkey)
#endif
{
}
AlignedAlloc aligned_alloc; AlignedAlloc aligned_alloc;
ThreadCache thread_cache; ThreadCache thread_cache;
@ -219,6 +231,9 @@ struct PartitionOptions {
BackupRefPtr backup_ref_ptr; BackupRefPtr backup_ref_ptr;
BackupRefPtrZapping backup_ref_ptr_zapping; BackupRefPtrZapping backup_ref_ptr_zapping;
UseConfigurablePool use_configurable_pool; UseConfigurablePool use_configurable_pool;
#if BUILDFLAG(ENABLE_PKEYS)
int pkey;
#endif
}; };
// Never instantiate a PartitionRoot directly, instead use // Never instantiate a PartitionRoot directly, instead use
@ -280,6 +295,10 @@ struct PA_ALIGNAS(64) PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRoot {
#endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) #endif // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
bool use_configurable_pool; bool use_configurable_pool;
#if BUILDFLAG(ENABLE_PKEYS)
int pkey;
#endif
#if defined(PA_EXTRAS_REQUIRED) #if defined(PA_EXTRAS_REQUIRED)
uint32_t extras_size; uint32_t extras_size;
uint32_t extras_offset; uint32_t extras_offset;
@ -534,6 +553,9 @@ struct PA_ALIGNAS(64) PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRoot {
void* ptr); void* ptr);
PA_ALWAYS_INLINE PageAccessibilityConfiguration GetPageAccessibility() const; PA_ALWAYS_INLINE PageAccessibilityConfiguration GetPageAccessibility() const;
PA_ALWAYS_INLINE PageAccessibilityConfiguration
PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::Permissions) const;
PA_ALWAYS_INLINE size_t PA_ALWAYS_INLINE size_t
AllocationCapacityFromSlotStart(uintptr_t slot_start) const; AllocationCapacityFromSlotStart(uintptr_t slot_start) const;
@ -635,6 +657,11 @@ struct PA_ALIGNAS(64) PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRoot {
PA_DCHECK(IsConfigurablePoolAvailable()); PA_DCHECK(IsConfigurablePoolAvailable());
return internal::kConfigurablePoolHandle; return internal::kConfigurablePoolHandle;
} }
#if BUILDFLAG(ENABLE_PKEYS)
if (flags.pkey != internal::kDefaultPkey) {
return internal::kPkeyPoolHandle;
}
#endif
#if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
return brp_enabled() ? internal::kBRPPoolHandle return brp_enabled() ? internal::kBRPPoolHandle
: internal::kRegularPoolHandle; : internal::kRegularPoolHandle;
@ -883,8 +910,10 @@ struct PA_ALIGNAS(64) PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRoot {
void DecommitEmptySlotSpans() PA_EXCLUSIVE_LOCKS_REQUIRED(lock_); void DecommitEmptySlotSpans() PA_EXCLUSIVE_LOCKS_REQUIRED(lock_);
PA_ALWAYS_INLINE void RawFreeLocked(uintptr_t slot_start) PA_ALWAYS_INLINE void RawFreeLocked(uintptr_t slot_start)
PA_EXCLUSIVE_LOCKS_REQUIRED(lock_); PA_EXCLUSIVE_LOCKS_REQUIRED(lock_);
uintptr_t MaybeInitThreadCacheAndAlloc(uint16_t bucket_index, ThreadCache* MaybeInitThreadCache();
size_t* slot_size);
// May return an invalid thread cache.
PA_ALWAYS_INLINE ThreadCache* GetOrCreateThreadCache();
#if defined(PA_USE_PARTITION_ROOT_ENUMERATOR) #if defined(PA_USE_PARTITION_ROOT_ENUMERATOR)
static internal::Lock& GetEnumeratorLock(); static internal::Lock& GetEnumeratorLock();
@ -1094,8 +1123,8 @@ PartitionRoot<thread_safe>::AllocFromBucket(Bucket* bucket,
if (PA_LIKELY(slot_span_alignment <= internal::PartitionPageSize() && if (PA_LIKELY(slot_span_alignment <= internal::PartitionPageSize() &&
slot_start)) { slot_start)) {
*is_already_zeroed = false; *is_already_zeroed = false;
// This is a fast path, so avoid calling GetUsableSize() on Release builds // This is a fast path, avoid calling GetUsableSize() in Release builds
// as it is more costly. Copy its small bucket path instead. // as it is costlier. Copy its small bucket path instead.
*usable_size = AdjustSizeForExtrasSubtract(bucket->slot_size); *usable_size = AdjustSizeForExtrasSubtract(bucket->slot_size);
PA_DCHECK(*usable_size == slot_span->GetUsableSize(this)); PA_DCHECK(*usable_size == slot_span->GetUsableSize(this));
@ -1484,21 +1513,35 @@ template <bool thread_safe>
PA_ALWAYS_INLINE void PartitionRoot<thread_safe>::RawFreeWithThreadCache( PA_ALWAYS_INLINE void PartitionRoot<thread_safe>::RawFreeWithThreadCache(
uintptr_t slot_start, uintptr_t slot_start,
SlotSpan* slot_span) { SlotSpan* slot_span) {
// TLS access can be expensive, do a cheap local check first.
//
// PA_LIKELY: performance-sensitive partitions have a thread cache, // PA_LIKELY: performance-sensitive partitions have a thread cache,
// direct-mapped allocations are uncommon. // direct-mapped allocations are uncommon.
if (PA_LIKELY(flags.with_thread_cache && ThreadCache* thread_cache = GetOrCreateThreadCache();
if (PA_LIKELY(ThreadCache::IsValid(thread_cache) &&
!IsDirectMappedBucket(slot_span->bucket))) { !IsDirectMappedBucket(slot_span->bucket))) {
size_t bucket_index = size_t bucket_index =
static_cast<size_t>(slot_span->bucket - this->buckets); static_cast<size_t>(slot_span->bucket - this->buckets);
auto* thread_cache = ThreadCache::Get(); size_t slot_size;
if (PA_LIKELY(ThreadCache::IsValid(thread_cache) && if (PA_LIKELY(thread_cache->MaybePutInCache(slot_start, bucket_index,
thread_cache->MaybePutInCache(slot_start, bucket_index))) { &slot_size))) {
// This is a fast path, avoid calling GetUsableSize() in Release builds
// as it is costlier. Copy its small bucket path instead.
PA_DCHECK(!slot_span->CanStoreRawSize());
size_t usable_size = AdjustSizeForExtrasSubtract(slot_size);
PA_DCHECK(usable_size == slot_span->GetUsableSize(this));
thread_cache->RecordDeallocation(usable_size);
return; return;
} }
} }
if (PA_LIKELY(ThreadCache::IsValid(thread_cache))) {
// Accounting must be done outside `RawFree()`, as it's also called from the
// thread cache. We would double-count otherwise.
//
// GetUsableSize() will always give the correct result, and we are in a slow
// path here (since the thread cache case returned earlier).
size_t usable_size = slot_span->GetUsableSize(this);
thread_cache->RecordDeallocation(usable_size);
}
RawFree(slot_start, slot_span); RawFree(slot_start, slot_span);
} }
@ -1654,8 +1697,8 @@ PA_ALWAYS_INLINE bool PartitionRoot<thread_safe>::TryRecommitSystemPagesForData(
internal::ScopedSyscallTimer timer{this}; internal::ScopedSyscallTimer timer{this};
bool ok = TryRecommitSystemPages(address, length, GetPageAccessibility(), bool ok = TryRecommitSystemPages(address, length, GetPageAccessibility(),
accessibility_disposition); accessibility_disposition);
#if defined(PA_COMMIT_CHARGE_IS_LIMITED)
if (PA_UNLIKELY(!ok)) { if (PA_UNLIKELY(!ok)) {
// Decommit some memory and retry. The alternative is crashing.
{ {
::partition_alloc::internal::ScopedGuard guard(lock_); ::partition_alloc::internal::ScopedGuard guard(lock_);
DecommitEmptySlotSpans(); DecommitEmptySlotSpans();
@ -1663,7 +1706,6 @@ PA_ALWAYS_INLINE bool PartitionRoot<thread_safe>::TryRecommitSystemPagesForData(
ok = TryRecommitSystemPages(address, length, GetPageAccessibility(), ok = TryRecommitSystemPages(address, length, GetPageAccessibility(),
accessibility_disposition); accessibility_disposition);
} }
#endif // defined(PA_COMMIT_CHARGE_IS_LIMITED)
if (ok) if (ok)
IncreaseCommittedPages(length); IncreaseCommittedPages(length);
@ -1724,11 +1766,27 @@ PartitionRoot<thread_safe>::GetUsableSizeWithMac11MallocSizeHack(void* ptr) {
template <bool thread_safe> template <bool thread_safe>
PA_ALWAYS_INLINE PageAccessibilityConfiguration PA_ALWAYS_INLINE PageAccessibilityConfiguration
PartitionRoot<thread_safe>::GetPageAccessibility() const { PartitionRoot<thread_safe>::GetPageAccessibility() const {
PageAccessibilityConfiguration::Permissions permissions =
PageAccessibilityConfiguration::kReadWrite;
#if defined(PA_HAS_MEMORY_TAGGING) #if defined(PA_HAS_MEMORY_TAGGING)
if (IsMemoryTaggingEnabled()) if (IsMemoryTaggingEnabled())
return PageAccessibilityConfiguration::kReadWriteTagged; permissions = PageAccessibilityConfiguration::kReadWriteTagged;
#endif #endif
return PageAccessibilityConfiguration::kReadWrite; #if BUILDFLAG(ENABLE_PKEYS)
return PageAccessibilityConfiguration(permissions, flags.pkey);
#else
return PageAccessibilityConfiguration(permissions);
#endif
}
template <bool thread_safe>
PA_ALWAYS_INLINE PageAccessibilityConfiguration
PartitionRoot<thread_safe>::PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::Permissions permissions) const {
#if BUILDFLAG(ENABLE_PKEYS)
return PageAccessibilityConfiguration(permissions, flags.pkey);
#endif
return PageAccessibilityConfiguration(permissions);
} }
// Return the capacity of the underlying slot (adjusted for extras). This // Return the capacity of the underlying slot (adjusted for extras). This
@ -1856,20 +1914,18 @@ PA_ALWAYS_INLINE void* PartitionRoot<thread_safe>::AllocWithFlagsNoHooks(
} }
#endif // BUILDFLAG(STARSCAN) #endif // BUILDFLAG(STARSCAN)
auto* thread_cache = GetOrCreateThreadCache();
// Don't use thread cache if higher order alignment is requested, because the // Don't use thread cache if higher order alignment is requested, because the
// thread cache will not be able to satisfy it. // thread cache will not be able to satisfy it.
// //
// PA_LIKELY: performance-sensitive partitions use the thread cache. // PA_LIKELY: performance-sensitive partitions use the thread cache.
if (PA_LIKELY(this->flags.with_thread_cache && if (PA_LIKELY(ThreadCache::IsValid(thread_cache) &&
slot_span_alignment <= internal::PartitionPageSize())) { slot_span_alignment <= internal::PartitionPageSize())) {
auto* tcache = ThreadCache::Get(); // Note: getting slot_size from the thread cache rather than by
// PA_LIKELY: Typically always true, except for the very first allocation of // `buckets[bucket_index].slot_size` to avoid touching `buckets` on the fast
// this thread. // path.
if (PA_LIKELY(ThreadCache::IsValid(tcache))) { slot_start = thread_cache->GetFromCache(bucket_index, &slot_size);
slot_start = tcache->GetFromCache(bucket_index, &slot_size);
} else {
slot_start = MaybeInitThreadCacheAndAlloc(bucket_index, &slot_size);
}
// PA_LIKELY: median hit rate in the thread cache is 95%, from metrics. // PA_LIKELY: median hit rate in the thread cache is 95%, from metrics.
if (PA_LIKELY(slot_start)) { if (PA_LIKELY(slot_start)) {
@ -1905,6 +1961,9 @@ PA_ALWAYS_INLINE void* PartitionRoot<thread_safe>::AllocWithFlagsNoHooks(
if (PA_UNLIKELY(!slot_start)) if (PA_UNLIKELY(!slot_start))
return nullptr; return nullptr;
if (PA_LIKELY(ThreadCache::IsValid(thread_cache)))
thread_cache->RecordAllocation(usable_size);
// Layout inside the slot: // Layout inside the slot:
// |[refcnt]|...object...|[empty]|[cookie]|[unused]| // |[refcnt]|...object...|[empty]|[cookie]|[unused]|
// <----(a)-----> // <----(a)----->
@ -2164,6 +2223,18 @@ PartitionRoot<thread_safe>::AllocationCapacityFromRequestedSize(
#endif #endif
} }
template <bool thread_safe>
ThreadCache* PartitionRoot<thread_safe>::GetOrCreateThreadCache() {
ThreadCache* thread_cache = nullptr;
if (PA_LIKELY(flags.with_thread_cache)) {
thread_cache = ThreadCache::Get();
if (PA_UNLIKELY(!ThreadCache::IsValid(thread_cache))) {
thread_cache = MaybeInitThreadCache();
}
}
return thread_cache;
}
using ThreadSafePartitionRoot = PartitionRoot<internal::ThreadSafe>; using ThreadSafePartitionRoot = PartitionRoot<internal::ThreadSafe>;
static_assert(offsetof(ThreadSafePartitionRoot, lock_) == static_assert(offsetof(ThreadSafePartitionRoot, lock_) ==

View File

@ -15,7 +15,7 @@
namespace partition_alloc { namespace partition_alloc {
// Most of these are not populated if PA_ENABLE_THREAD_CACHE_STATISTICS is not // Most of these are not populated if PA_THREAD_CACHE_ENABLE_STATISTICS is not
// defined. // defined.
struct ThreadCacheStats { struct ThreadCacheStats {
uint64_t alloc_count; // Total allocation requests. uint64_t alloc_count; // Total allocation requests.
@ -42,6 +42,20 @@ struct ThreadCacheStats {
#endif // defined(PA_THREAD_CACHE_ALLOC_STATS) #endif // defined(PA_THREAD_CACHE_ALLOC_STATS)
}; };
// Per-thread allocation statistics. Only covers allocations made through the
// partition linked to the thread cache. As the allocator doesn't record
// requested sizes in most cases, the data there will be an overestimate of the
// actually requested sizes. It is also not expected to sum up to anything
// meaningful across threads, due to the lack of synchronization. Figures there
// are cumulative, not net. Since the data below is per-thread, note a thread
// can deallocate more than it allocated.
struct ThreadAllocStats {
uint64_t alloc_count;
uint64_t alloc_total_size;
uint64_t dealloc_count;
uint64_t dealloc_total_size;
};
// Struct used to retrieve total memory usage of a partition. Used by // Struct used to retrieve total memory usage of a partition. Used by
// PartitionStatsDumper implementation. // PartitionStatsDumper implementation.
struct PartitionMemoryStats { struct PartitionMemoryStats {

View File

@ -0,0 +1,121 @@
// Copyright 2022 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/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/address_pool_manager.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h"
#if BUILDFLAG(ENABLE_PKEYS)
#include <errno.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "base/allocator/partition_allocator/partition_alloc_base/cpu.h"
#include "base/allocator/partition_allocator/partition_alloc_check.h"
#if !BUILDFLAG(IS_LINUX)
#error "This pkey code is currently only supported on Linux"
#endif
namespace partition_alloc::internal {
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
bool CPUHasPkeySupport() {
return base::CPU::GetInstanceNoAllocation().has_pku();
}
PkeySettings PkeySettings::settings PA_PKEY_ALIGN;
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
int PkeyMprotect(void* addr, size_t len, int prot, int pkey) {
return syscall(SYS_pkey_mprotect, addr, len, prot, pkey);
}
int PkeyMprotectIfEnabled(void* addr, size_t len, int prot, int pkey) {
if (PA_UNLIKELY(PkeySettings::settings.enabled)) {
return PkeyMprotect(addr, len, prot, pkey);
}
PA_CHECK(pkey == 0);
return mprotect(addr, len, prot);
}
void TagMemoryWithPkey(int pkey, void* address, size_t size) {
PA_DCHECK(
(reinterpret_cast<uintptr_t>(address) & PA_PKEY_ALIGN_OFFSET_MASK) == 0);
PA_PCHECK(
PkeyMprotect(address,
(size + PA_PKEY_ALIGN_OFFSET_MASK) & PA_PKEY_ALIGN_BASE_MASK,
PROT_READ | PROT_WRITE, pkey) == 0);
}
template <typename T>
void TagVariableWithPkey(int pkey, T& var) {
TagMemoryWithPkey(pkey, &var, sizeof(T));
}
void TagGlobalsWithPkey(int pkey) {
TagVariableWithPkey(pkey, PartitionAddressSpace::setup_);
AddressPoolManager::Pool* pool =
AddressPoolManager::GetInstance().GetPool(kPkeyPoolHandle);
TagVariableWithPkey(pkey, *pool);
uint16_t* pkey_reservation_offset_table =
GetReservationOffsetTable(kPkeyPoolHandle);
TagMemoryWithPkey(pkey, pkey_reservation_offset_table,
ReservationOffsetTable::kReservationOffsetTableLength);
TagVariableWithPkey(pkey, PkeySettings::settings);
}
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
int PkeyAlloc(int access_rights) {
return syscall(SYS_pkey_alloc, 0, access_rights);
}
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
void PkeyFree(int pkey) {
PA_PCHECK(syscall(SYS_pkey_free, pkey) == 0);
}
uint32_t Rdpkru() {
uint32_t pkru;
asm volatile(".byte 0x0f,0x01,0xee\n" : "=a"(pkru) : "c"(0), "d"(0));
return pkru;
}
void Wrpkru(uint32_t pkru) {
asm volatile(".byte 0x0f,0x01,0xef\n" : : "a"(pkru), "c"(0), "d"(0));
}
#if BUILDFLAG(PA_DCHECK_IS_ON)
LiftPkeyRestrictionsScope::LiftPkeyRestrictionsScope()
: saved_pkey_value_(kDefaultPkeyValue) {
if (!PkeySettings::settings.enabled)
return;
saved_pkey_value_ = Rdpkru();
if (saved_pkey_value_ != kDefaultPkeyValue) {
Wrpkru(kAllowAllPkeyValue);
}
}
LiftPkeyRestrictionsScope::~LiftPkeyRestrictionsScope() {
if (!PkeySettings::settings.enabled)
return;
if (Rdpkru() != saved_pkey_value_) {
Wrpkru(saved_pkey_value_);
}
}
#endif // BUILDFLAG(PA_DCHECK_IS_ON)
} // namespace partition_alloc::internal
#endif // BUILDFLAG(ENABLE_PKEYS)

View File

@ -0,0 +1,98 @@
// Copyright 2022 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_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_
#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
#if BUILDFLAG(ENABLE_PKEYS)
#include "base/allocator/partition_allocator/page_allocator_constants.h"
#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
#include "base/allocator/partition_allocator/partition_alloc_config.h"
#include <cstddef>
#include <cstdint>
#if !defined(PA_HAS_64_BITS_POINTERS)
#error "pkey support requires 64 bit pointers"
#endif
#define PA_PKEY_ALIGN_SZ SystemPageSize()
#define PA_PKEY_ALIGN_OFFSET_MASK (PA_PKEY_ALIGN_SZ - 1)
#define PA_PKEY_ALIGN_BASE_MASK (~PA_PKEY_ALIGN_OFFSET_MASK)
#define PA_PKEY_ALIGN alignas(PA_PKEY_ALIGN_SZ)
#define PA_PKEY_FILL_PAGE_SZ(size) \
((PA_PKEY_ALIGN_SZ - (size & PA_PKEY_ALIGN_OFFSET_MASK)) % PA_PKEY_ALIGN_SZ)
// Calculate the required padding so that the last element of a page-aligned
// array lands on a page boundary. In other words, calculate that padding so
// that (count-1) elements are a multiple of page size.
#define PA_PKEY_ARRAY_PAD_SZ(Type, count) \
PA_PKEY_FILL_PAGE_SZ(sizeof(Type) * (count - 1))
namespace partition_alloc::internal {
constexpr int kDefaultPkey = 0;
constexpr int kInvalidPkey = -1;
// Check if the CPU supports pkeys.
bool CPUHasPkeySupport();
// A wrapper around pkey_mprotect that falls back to regular mprotect if
// PkeySettings::enabled is false.
[[nodiscard]] int PkeyMprotectIfEnabled(void* addr,
size_t len,
int prot,
int pkey);
// A wrapper around pkey_mprotect without fallback.
[[nodiscard]] int PkeyMprotect(void* addr, size_t len, int prot, int pkey);
// If we set up a pkey pool, we need to tag global variables with the pkey to
// make them readable in case default pkey access is disabled. Called once
// during pkey pool initialization.
void TagGlobalsWithPkey(int pkey);
int PkeyAlloc(int access_rights);
void PkeyFree(int pkey);
// Read the pkru register (the current pkey state).
uint32_t Rdpkru();
// Write the pkru register (the current pkey state).
void Wrpkru(uint32_t pkru);
struct PkeySettings {
bool enabled = false;
char pad_[PA_PKEY_FILL_PAGE_SZ(sizeof(enabled))] = {};
static PkeySettings settings PA_PKEY_ALIGN PA_CONSTINIT;
};
#if BUILDFLAG(PA_DCHECK_IS_ON)
class PA_COMPONENT_EXPORT(PARTITION_ALLOC) LiftPkeyRestrictionsScope {
public:
static constexpr uint32_t kDefaultPkeyValue = 0x55555554;
static constexpr uint32_t kAllowAllPkeyValue = 0x0;
LiftPkeyRestrictionsScope();
~LiftPkeyRestrictionsScope();
private:
uint32_t saved_pkey_value_;
};
#endif // BUILDFLAG(PA_DCHECK_IS_ON)
} // namespace partition_alloc::internal
#else // BUILDFLAG(ENABLE_PKEYS)
#define PA_PKEY_ALIGN
#define PA_PKEY_FILL_PAGE_SZ(size) 0
#define PA_PKEY_ARRAY_PAD_SZ(Type, size) 0
#endif // BUILDFLAG(ENABLE_PKEYS)
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PKEY_H_

View File

@ -7,8 +7,8 @@
namespace partition_alloc::internal { namespace partition_alloc::internal {
#if defined(PA_HAS_64_BITS_POINTERS) #if defined(PA_HAS_64_BITS_POINTERS)
ReservationOffsetTable::_ReservationOffsetTable ReservationOffsetTable::_PaddedReservationOffsetTables
ReservationOffsetTable::reservation_offset_tables_[]; ReservationOffsetTable::padded_reservation_offset_tables_ PA_PKEY_ALIGN;
#else #else
ReservationOffsetTable::_ReservationOffsetTable ReservationOffsetTable::_ReservationOffsetTable
ReservationOffsetTable::reservation_offset_table_; ReservationOffsetTable::reservation_offset_table_;

View File

@ -19,6 +19,7 @@
#include "base/allocator/partition_allocator/partition_alloc_check.h" #include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/partition_alloc_config.h" #include "base/allocator/partition_allocator/partition_alloc_config.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h" #include "base/allocator/partition_allocator/partition_alloc_constants.h"
#include "base/allocator/partition_allocator/pkey.h"
#include "base/allocator/partition_allocator/tagging.h" #include "base/allocator/partition_allocator/tagging.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -81,7 +82,7 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ReservationOffsetTable {
static_assert(kReservationOffsetTableLength < kOffsetTagNormalBuckets, static_assert(kReservationOffsetTableLength < kOffsetTagNormalBuckets,
"Offsets should be smaller than kOffsetTagNormalBuckets."); "Offsets should be smaller than kOffsetTagNormalBuckets.");
static PA_CONSTINIT struct _ReservationOffsetTable { struct _ReservationOffsetTable {
// The number of table elements is less than MAX_UINT16, so the element type // The number of table elements is less than MAX_UINT16, so the element type
// can be uint16_t. // can be uint16_t.
static_assert( static_assert(
@ -93,19 +94,30 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ReservationOffsetTable {
for (uint16_t& offset : offsets) for (uint16_t& offset : offsets)
offset = kOffsetTagNotAllocated; offset = kOffsetTagNotAllocated;
} }
};
#if defined(PA_HAS_64_BITS_POINTERS) #if defined(PA_HAS_64_BITS_POINTERS)
// One table per Pool. // If pkey support is enabled, we need to pkey-tag the tables of the pkey
} reservation_offset_tables_[kNumPools]; // pool. For this, we need to pad the tables so that the pkey ones start on a
// page boundary.
struct _PaddedReservationOffsetTables {
char pad_[PA_PKEY_ARRAY_PAD_SZ(_ReservationOffsetTable, kNumPools)] = {};
struct _ReservationOffsetTable tables[kNumPools];
char pad_after_[PA_PKEY_FILL_PAGE_SZ(sizeof(_ReservationOffsetTable))] = {};
};
static PA_CONSTINIT _PaddedReservationOffsetTables
padded_reservation_offset_tables_ PA_PKEY_ALIGN;
#else #else
// A single table for the entire 32-bit address space. // A single table for the entire 32-bit address space.
} reservation_offset_table_; static PA_CONSTINIT struct _ReservationOffsetTable reservation_offset_table_;
#endif #endif
}; };
#if defined(PA_HAS_64_BITS_POINTERS) #if defined(PA_HAS_64_BITS_POINTERS)
PA_ALWAYS_INLINE uint16_t* GetReservationOffsetTable(pool_handle handle) { PA_ALWAYS_INLINE uint16_t* GetReservationOffsetTable(pool_handle handle) {
PA_DCHECK(0 < handle && handle <= kNumPools); PA_DCHECK(0 < handle && handle <= kNumPools);
return ReservationOffsetTable::reservation_offset_tables_[handle - 1].offsets; return ReservationOffsetTable::padded_reservation_offset_tables_
.tables[handle - 1]
.offsets;
} }
PA_ALWAYS_INLINE const uint16_t* GetReservationOffsetTableEnd( PA_ALWAYS_INLINE const uint16_t* GetReservationOffsetTableEnd(
@ -169,6 +181,12 @@ PA_ALWAYS_INLINE uintptr_t GetDirectMapReservationStart(uintptr_t address) {
#if BUILDFLAG(PA_DCHECK_IS_ON) #if BUILDFLAG(PA_DCHECK_IS_ON)
bool is_in_brp_pool = IsManagedByPartitionAllocBRPPool(address); bool is_in_brp_pool = IsManagedByPartitionAllocBRPPool(address);
bool is_in_regular_pool = IsManagedByPartitionAllocRegularPool(address); bool is_in_regular_pool = IsManagedByPartitionAllocRegularPool(address);
bool is_in_configurable_pool =
IsManagedByPartitionAllocConfigurablePool(address);
#if BUILDFLAG(ENABLE_PKEYS)
bool is_in_pkey_pool = IsManagedByPartitionAllocPkeyPool(address);
#endif
// When ENABLE_BACKUP_REF_PTR_SUPPORT is off, BRP pool isn't used. // When ENABLE_BACKUP_REF_PTR_SUPPORT is off, BRP pool isn't used.
#if !BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) #if !BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
PA_DCHECK(!is_in_brp_pool); PA_DCHECK(!is_in_brp_pool);
@ -197,6 +215,12 @@ PA_ALWAYS_INLINE uintptr_t GetDirectMapReservationStart(uintptr_t address) {
IsManagedByPartitionAllocBRPPool(reservation_start + kBRPOffset)); IsManagedByPartitionAllocBRPPool(reservation_start + kBRPOffset));
PA_DCHECK(is_in_regular_pool == PA_DCHECK(is_in_regular_pool ==
IsManagedByPartitionAllocRegularPool(reservation_start)); IsManagedByPartitionAllocRegularPool(reservation_start));
PA_DCHECK(is_in_configurable_pool ==
IsManagedByPartitionAllocConfigurablePool(reservation_start));
#if BUILDFLAG(ENABLE_PKEYS)
PA_DCHECK(is_in_pkey_pool ==
IsManagedByPartitionAllocPkeyPool(reservation_start));
#endif
PA_DCHECK(*ReservationOffsetPointer(reservation_start) == 0); PA_DCHECK(*ReservationOffsetPointer(reservation_start) == 0);
#endif // BUILDFLAG(PA_DCHECK_IS_ON) #endif // BUILDFLAG(PA_DCHECK_IS_ON)

View File

@ -164,7 +164,8 @@ BASE_EXPORT void ConfigurePartitionAlloc();
#if BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_APPLE)
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
void InitializeDefaultAllocatorPartitionRoot(); BASE_EXPORT void InitializeDefaultAllocatorPartitionRoot();
bool IsDefaultAllocatorPartitionRootInitialized();
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
// On macOS, the allocator shim needs to be turned on during runtime. // On macOS, the allocator shim needs to be turned on during runtime.
BASE_EXPORT void InitializeAllocatorShim(); BASE_EXPORT void InitializeAllocatorShim();

View File

@ -15,6 +15,7 @@
#include <string.h> #include <string.h>
#include <atomic>
#include <tuple> #include <tuple>
#include "base/allocator/early_zone_registration_mac.h" #include "base/allocator/early_zone_registration_mac.h"
@ -312,6 +313,10 @@ void InitializeZone() {
g_mac_malloc_zone.claimed_address = nullptr; g_mac_malloc_zone.claimed_address = nullptr;
} }
namespace {
static std::atomic<bool> g_initialization_is_done;
}
// Replaces the default malloc zone with our own malloc zone backed by // Replaces the default malloc zone with our own malloc zone backed by
// PartitionAlloc. Since we'd like to make as much code as possible to use our // PartitionAlloc. Since we'd like to make as much code as possible to use our
// own memory allocator (and reduce bugs caused by mixed use of the system // own memory allocator (and reduce bugs caused by mixed use of the system
@ -349,6 +354,7 @@ InitializeDefaultMallocZoneWithPartitionAlloc() {
// |EarlyMallocZoneRegistration()|. // |EarlyMallocZoneRegistration()|.
malloc_zone_register(&g_mac_malloc_zone); malloc_zone_register(&g_mac_malloc_zone);
malloc_zone_unregister(system_default_zone); malloc_zone_unregister(system_default_zone);
g_initialization_is_done.store(true, std::memory_order_release);
return; return;
} }
@ -373,10 +379,17 @@ InitializeDefaultMallocZoneWithPartitionAlloc() {
// Confirm that our own zone is now the default zone. // Confirm that our own zone is now the default zone.
CHECK_EQ(GetDefaultMallocZone(), &g_mac_malloc_zone); CHECK_EQ(GetDefaultMallocZone(), &g_mac_malloc_zone);
g_initialization_is_done.store(true, std::memory_order_release);
} }
} // namespace } // namespace
bool IsDefaultAllocatorPartitionRootInitialized() {
// Even though zone registration is not thread-safe, let's not make it worse,
// and use acquire/release ordering.
return g_initialization_is_done.load(std::memory_order_acquire);
}
} // namespace allocator_shim } // namespace allocator_shim
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_SHIM_ALLOCATOR_SHIM_OVERRIDE_MAC_DEFAULT_ZONE_H_ #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_SHIM_ALLOCATOR_SHIM_OVERRIDE_MAC_DEFAULT_ZONE_H_

View File

@ -272,7 +272,8 @@ void CommitCardTable() {
#if PA_STARSCAN_USE_CARD_TABLE #if PA_STARSCAN_USE_CARD_TABLE
RecommitSystemPages(PartitionAddressSpace::RegularPoolBase(), RecommitSystemPages(PartitionAddressSpace::RegularPoolBase(),
sizeof(QuarantineCardTable), sizeof(QuarantineCardTable),
PageAccessibilityConfiguration::kReadWrite, PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
#endif #endif
} }
@ -1404,7 +1405,8 @@ PCScanInternal::SuperPages GetSuperPagesAndCommitStateBitmaps(
*metadata; *metadata;
RecommitSystemPages(SuperPageStateBitmapAddr(super_page), RecommitSystemPages(SuperPageStateBitmapAddr(super_page),
state_bitmap_size_to_commit, state_bitmap_size_to_commit,
PageAccessibilityConfiguration::kReadWrite, PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate); PageAccessibilityDisposition::kRequireUpdate);
super_pages.push_back(super_page); super_pages.push_back(super_page);
} }

View File

@ -775,6 +775,10 @@ void ThreadCache::PurgeInternal() {
PurgeInternalHelper<true>(); PurgeInternalHelper<true>();
} }
void ThreadCache::ResetPerThreadAllocationStatsForTesting() {
thread_alloc_stats_ = {};
}
template <bool crash_on_corruption> template <bool crash_on_corruption>
void ThreadCache::PurgeInternalHelper() { void ThreadCache::PurgeInternalHelper() {
should_purge_.store(false, std::memory_order_relaxed); should_purge_.store(false, std::memory_order_relaxed);

View File

@ -286,7 +286,8 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadCache {
// can happen either because the cache is full or the allocation was too // can happen either because the cache is full or the allocation was too
// large. // large.
PA_ALWAYS_INLINE bool MaybePutInCache(uintptr_t slot_start, PA_ALWAYS_INLINE bool MaybePutInCache(uintptr_t slot_start,
size_t bucket_index); size_t bucket_index,
size_t* slot_size);
// Tries to allocate a memory slot from the cache. // Tries to allocate a memory slot from the cache.
// Returns 0 on failure. // Returns 0 on failure.
@ -314,6 +315,9 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadCache {
// Purge the thread cache of the current thread, if one exists. // Purge the thread cache of the current thread, if one exists.
static void PurgeCurrentThread(); static void PurgeCurrentThread();
const ThreadAllocStats& thread_alloc_stats() const {
return thread_alloc_stats_;
}
size_t bucket_count_for_testing(size_t index) const { size_t bucket_count_for_testing(size_t index) const {
return buckets_[index].count; return buckets_[index].count;
} }
@ -325,6 +329,17 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadCache {
// |kLargeSizeThreshold|. // |kLargeSizeThreshold|.
static void SetLargestCachedSize(size_t size); static void SetLargestCachedSize(size_t size);
// Cumulative stats about *all* allocations made on the `root_` partition on
// this thread, that is not only the allocations serviced by the thread cache,
// but all allocations, including large and direct-mapped ones. This should in
// theory be split into a separate PerThread data structure, but the thread
// cache is the only per-thread data we have as of now.
//
// TODO(lizeb): Investigate adding a proper per-thread data structure.
PA_ALWAYS_INLINE void RecordAllocation(size_t size);
PA_ALWAYS_INLINE void RecordDeallocation(size_t size);
void ResetPerThreadAllocationStatsForTesting();
// Fill 1 / kBatchFillRatio * bucket.limit slots at a time. // Fill 1 / kBatchFillRatio * bucket.limit slots at a time.
static constexpr uint16_t kBatchFillRatio = 8; static constexpr uint16_t kBatchFillRatio = 8;
@ -420,6 +435,7 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadCache {
uint32_t cached_memory_ = 0; uint32_t cached_memory_ = 0;
std::atomic<bool> should_purge_; std::atomic<bool> should_purge_;
ThreadCacheStats stats_; ThreadCacheStats stats_;
ThreadAllocStats thread_alloc_stats_;
// Buckets are quite big, though each is only 2 pointers. // Buckets are quite big, though each is only 2 pointers.
Bucket buckets_[kBucketCount]; Bucket buckets_[kBucketCount];
@ -466,7 +482,8 @@ class PA_COMPONENT_EXPORT(PARTITION_ALLOC) ThreadCache {
}; };
PA_ALWAYS_INLINE bool ThreadCache::MaybePutInCache(uintptr_t slot_start, PA_ALWAYS_INLINE bool ThreadCache::MaybePutInCache(uintptr_t slot_start,
size_t bucket_index) { size_t bucket_index,
size_t* slot_size) {
PA_REENTRANCY_GUARD(is_in_thread_cache_); PA_REENTRANCY_GUARD(is_in_thread_cache_);
PA_INCREMENT_COUNTER(stats_.cache_fill_count); PA_INCREMENT_COUNTER(stats_.cache_fill_count);
@ -496,6 +513,7 @@ PA_ALWAYS_INLINE bool ThreadCache::MaybePutInCache(uintptr_t slot_start,
if (PA_UNLIKELY(should_purge_.load(std::memory_order_relaxed))) if (PA_UNLIKELY(should_purge_.load(std::memory_order_relaxed)))
PurgeInternal(); PurgeInternal();
*slot_size = bucket.slot_size;
return true; return true;
} }
@ -532,6 +550,18 @@ PA_ALWAYS_INLINE uintptr_t ThreadCache::GetFromCache(size_t bucket_index,
PA_DCHECK(bucket.count != 0); PA_DCHECK(bucket.count != 0);
internal::PartitionFreelistEntry* entry = bucket.freelist_head; internal::PartitionFreelistEntry* entry = bucket.freelist_head;
// TODO(lizeb): Consider removing once crbug.com/1382658 is fixed.
#if BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_X86_64) && \
defined(PA_HAS_64_BITS_POINTERS)
// x86_64 architecture now supports 57 bits of address space, as of Ice Lake
// for Intel. However Chrome OS systems do not ship with kernel support for
// it, but with 48 bits, so all canonical addresses have the upper 16 bits
// zeroed (17 in practice, since the upper half of address space is reserved
// by the kernel).
constexpr uintptr_t kCanonicalPointerMask = (1ULL << 48) - 1;
PA_CHECK(!(reinterpret_cast<uintptr_t>(entry) & ~kCanonicalPointerMask));
#endif
// Passes the bucket size to |GetNext()|, so that in case of freelist // Passes the bucket size to |GetNext()|, so that in case of freelist
// corruption, we know the bucket size that lead to the crash, helping to // corruption, we know the bucket size that lead to the crash, helping to
// narrow down the search for culprit. |bucket| was touched just now, so this // narrow down the search for culprit. |bucket| was touched just now, so this
@ -546,6 +576,7 @@ PA_ALWAYS_INLINE uintptr_t ThreadCache::GetFromCache(size_t bucket_index,
PA_DCHECK(cached_memory_ >= bucket.slot_size); PA_DCHECK(cached_memory_ >= bucket.slot_size);
cached_memory_ -= bucket.slot_size; cached_memory_ -= bucket.slot_size;
return internal::SlotStartPtr2Addr(entry); return internal::SlotStartPtr2Addr(entry);
} }
@ -612,6 +643,16 @@ PA_ALWAYS_INLINE void ThreadCache::PutInBucket(Bucket& bucket,
bucket.count++; bucket.count++;
} }
void ThreadCache::RecordAllocation(size_t size) {
thread_alloc_stats_.alloc_count++;
thread_alloc_stats_.alloc_total_size += size;
}
void ThreadCache::RecordDeallocation(size_t size) {
thread_alloc_stats_.dealloc_count++;
thread_alloc_stats_.dealloc_total_size += size;
}
} // namespace partition_alloc } // namespace partition_alloc
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_CACHE_H_ #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_CACHE_H_

View File

@ -0,0 +1,69 @@
# //base/android
This directory contains:
* C++ APIs that are broadly useful and are unique to `target_os="android"`, and
* Java APIs that are broadly useful, along C++ bindings when necessary.
This directory does not contain Android-specific implementations / extensions
to APIs declared directly in `//base`. Those live in `//base/*_android.cc`, or
behind `#ifdef`s.
## Adding New APIs
The advice laid out in [//base/README.md] applies to this directory as well.
The bars for what APIs should exist and for code quality are generally higher
than for other directories. If you find yourself wanting to add a new API, you
should expect that code reviews take multiple revisions and that they be met
with (respectful) scrutiny.
If you are not sure whether an API would make sense to add, you can ask via
java@chromium.org.
It is common to add APIs to `//chrome` (or elsewhere) first, and move them into
`//base` after their usefulness has been proven.
[//base/README.md]: /base/README.md
### What Uses //base/android?
The main two clients are Chrome and WebView, but it is also used by other
Chromium-based apps, such as Chromecast and Chrome Remote desktop. Some
`//base/android` classes are used by `//build` (this is a layering violation,
tracked in [crbug/1364192] and [crbug/1377351]).
Two considerations for WebView:
1. The application Context is that of the host app's.
2. The UI thread might be different from the main thread.
[crbug/1364192]: https://crbug.com/1364192
[crbug/1377351]: https://crbug.com/1377351
### New API Checklist
Here is a list of checks you should go through when adding a new API:
1. The functionality does not already exist in system libraries (Java APIs,
Android SDK) or in already adopted `third_party` libraries, such as AndroidX.
2. Reasonable effort has been made to ensure the new API is discoverable. E.g.:
Coordinate refactorings of existing patterns to it, add a [presubmit check],
to recommend it, etc.
3. Tests (ideally Robolectric) are added.
4. Thought has been put into API design.
* E.g. adding `@Nullable`, or `@DoNotMock`
* E.g. adding test helpers, such as `ForTesting()` methods or `TestRule`s
* E.g. adding asserts or comments about thread-safety
* E.g. could usage of the API be made harder to get wrong?
[presumbit check]: https://chromium.googlesource.com/chromium/src/+/main/build/android/docs/java_toolchain.md#Static-Analysis-Code-Checks
### Choosing a Reviewer
All members of [`//base/android/OWNERS`] will be CC'ed on reviews through a
[`//WATCHLIST`] entry. For new APIs, feel free to pick a reviewer at random.
For modifying existing files, it is best to use a reviewer from prior changes to
the file.
[`//base/android/OWNERS`]: /base/android/OWNERS
[`//WATCHLIST`]: /WATCHLIST

View File

@ -14,11 +14,11 @@ namespace base {
AndroidHardwareBufferCompat::AndroidHardwareBufferCompat() { AndroidHardwareBufferCompat::AndroidHardwareBufferCompat() {
DCHECK(IsSupportAvailable()); DCHECK(IsSupportAvailable());
// TODO(klausw): If the Chromium build requires __ANDROID_API__ >= 26 at some // TODO(https://crbug.com/1382595): If the Chromium build requires
// point in the future, we could directly use the global functions instead of // __ANDROID_API__ >= 26 at some point in the future, we could directly use
// dynamic loading. However, since this would be incompatible with pre-Oreo // the global functions instead of dynamic loading. However, since this would
// devices, this is unlikely to happen in the foreseeable future, so just // be incompatible with pre-Oreo devices, this is unlikely to happen in the
// unconditionally use dynamic loading. // foreseeable future, so just unconditionally use dynamic loading.
// cf. base/android/linker/modern_linker_jni.cc // cf. base/android/linker/modern_linker_jni.cc
void* main_dl_handle = dlopen(nullptr, RTLD_NOW); void* main_dl_handle = dlopen(nullptr, RTLD_NOW);

View File

@ -11,7 +11,6 @@
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/base_export.h" #include "base/base_export.h"
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
namespace base { namespace base {
namespace android { namespace android {

View File

@ -13,13 +13,16 @@
namespace base { namespace base {
namespace android { namespace android {
class ScopedAllowBlockingForImportantFileWriter
: public base::ScopedAllowBlocking {};
static jboolean JNI_ImportantFileWriterAndroid_WriteFileAtomically( static jboolean JNI_ImportantFileWriterAndroid_WriteFileAtomically(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jstring>& file_name, const JavaParamRef<jstring>& file_name,
const JavaParamRef<jbyteArray>& data) { const JavaParamRef<jbyteArray>& data) {
// This is called on the UI thread during shutdown to save tab data, so // This is called on the UI thread during shutdown to save tab data, so
// needs to enable IO. // needs to enable IO.
base::ThreadRestrictions::ScopedAllowIO allow_io; ScopedAllowBlockingForImportantFileWriter allow_blocking;
std::string native_file_name; std::string native_file_name;
base::android::ConvertJavaStringToUTF8(env, file_name, &native_file_name); base::android::ConvertJavaStringToUTF8(env, file_name, &native_file_name);
base::FilePath path(native_file_name); base::FilePath path(native_file_name);

View File

@ -19,12 +19,13 @@
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/threading/thread_local.h" #include "base/threading/thread_local.h"
#include "build/build_config.h"
namespace base { namespace base {
namespace android { namespace android {
namespace { namespace {
JavaVM* g_jvm = NULL; JavaVM* g_jvm = nullptr;
base::LazyInstance<ScopedJavaGlobalRef<jobject>>::Leaky g_class_loader = base::LazyInstance<ScopedJavaGlobalRef<jobject>>::Leaky g_class_loader =
LAZY_INSTANCE_INITIALIZER; LAZY_INSTANCE_INITIALIZER;
jmethodID g_class_loader_load_class_method_id = 0; jmethodID g_class_loader_load_class_method_id = 0;
@ -111,7 +112,11 @@ JNIEnv* AttachCurrentThread() {
args.name = thread_name; args.name = thread_name;
} }
#if BUILDFLAG(IS_ANDROID)
ret = g_jvm->AttachCurrentThread(&env, &args); ret = g_jvm->AttachCurrentThread(&env, &args);
#else
ret = g_jvm->AttachCurrentThread(reinterpret_cast<void**>(&env), &args);
#endif
CHECK_EQ(JNI_OK, ret); CHECK_EQ(JNI_OK, ret);
} }
return env; return env;
@ -121,10 +126,14 @@ JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name) {
DCHECK(g_jvm); DCHECK(g_jvm);
JavaVMAttachArgs args; JavaVMAttachArgs args;
args.version = JNI_VERSION_1_2; args.version = JNI_VERSION_1_2;
args.name = thread_name.c_str(); args.name = const_cast<char*>(thread_name.c_str());
args.group = NULL; args.group = nullptr;
JNIEnv* env = NULL; JNIEnv* env = nullptr;
#if BUILDFLAG(IS_ANDROID)
jint ret = g_jvm->AttachCurrentThread(&env, &args); jint ret = g_jvm->AttachCurrentThread(&env, &args);
#else
jint ret = g_jvm->AttachCurrentThread(reinterpret_cast<void**>(&env), &args);
#endif
CHECK_EQ(JNI_OK, ret); CHECK_EQ(JNI_OK, ret);
return env; return env;
} }
@ -142,7 +151,7 @@ void InitVM(JavaVM* vm) {
} }
bool IsVMInitialized() { bool IsVMInitialized() {
return g_jvm != NULL; return g_jvm != nullptr;
} }
void InitReplacementClassLoader(JNIEnv* env, void InitReplacementClassLoader(JNIEnv* env,

View File

@ -9,7 +9,7 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <algorithm>
#include <atomic> #include <atomic>
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
@ -24,6 +24,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "base/process/process_metrics.h" #include "base/process/process_metrics.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "build/build_config.h" #include "build/build_config.h"
@ -67,7 +68,7 @@ std::pair<size_t, size_t> GetTextRange() {
// Set the end to the page on which the beginning of the last symbol is. The // Set the end to the page on which the beginning of the last symbol is. The
// actual symbol may spill into the next page by a few bytes, but this is // actual symbol may spill into the next page by a few bytes, but this is
// outside of the executable code range anyway. // outside of the executable code range anyway.
size_t end_page = base::bits::AlignUp(kEndOfText, kPageSize); size_t end_page = bits::AlignUp(kEndOfText, kPageSize);
return {start_page, end_page}; return {start_page, end_page};
} }
@ -77,7 +78,7 @@ std::pair<size_t, size_t> GetOrderedTextRange() {
size_t start_page = kStartOfOrderedText - kStartOfOrderedText % kPageSize; size_t start_page = kStartOfOrderedText - kStartOfOrderedText % kPageSize;
// kEndOfUnorderedText is not considered ordered, but the byte immediately // kEndOfUnorderedText is not considered ordered, but the byte immediately
// before is considered ordered and so can not be contained in the start page. // before is considered ordered and so can not be contained in the start page.
size_t end_page = base::bits::AlignUp(kEndOfOrderedText, kPageSize); size_t end_page = bits::AlignUp(kEndOfOrderedText, kPageSize);
return {start_page, end_page}; return {start_page, end_page};
} }
@ -108,8 +109,8 @@ struct TimestampAndResidency {
bool CollectResidency(size_t start, bool CollectResidency(size_t start,
size_t end, size_t end,
std::vector<TimestampAndResidency>* data) { std::vector<TimestampAndResidency>* data) {
// Not using base::TimeTicks() to not call too many base:: symbol that would // Not using TimeTicks() to not call too many base:: symbol that would pollute
// pollute the reached symbols dumps. // the reached symbols dumps.
struct timespec ts; struct timespec ts;
if (HANDLE_EINTR(clock_gettime(CLOCK_MONOTONIC, &ts))) { if (HANDLE_EINTR(clock_gettime(CLOCK_MONOTONIC, &ts))) {
PLOG(ERROR) << "Cannot get the time."; PLOG(ERROR) << "Cannot get the time.";
@ -129,10 +130,9 @@ void DumpResidency(size_t start,
size_t end, size_t end,
std::unique_ptr<std::vector<TimestampAndResidency>> data) { std::unique_ptr<std::vector<TimestampAndResidency>> data) {
LOG(WARNING) << "Dumping native library residency"; LOG(WARNING) << "Dumping native library residency";
auto path = base::FilePath( auto path = FilePath(
base::StringPrintf("/data/local/tmp/chrome/residency-%d.txt", getpid())); StringPrintf("/data/local/tmp/chrome/residency-%d.txt", getpid()));
auto file = auto file = File(path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
base::File(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!file.IsValid()) { if (!file.IsValid()) {
PLOG(ERROR) << "Cannot open file to dump the residency data " PLOG(ERROR) << "Cannot open file to dump the residency data "
<< path.value(); << path.value();
@ -143,13 +143,12 @@ void DumpResidency(size_t start,
CHECK(AreAnchorsSane()); CHECK(AreAnchorsSane());
CHECK_LE(start, kStartOfText); CHECK_LE(start, kStartOfText);
CHECK_LE(kEndOfText, end); CHECK_LE(kEndOfText, end);
auto start_end = base::StringPrintf("%" PRIuS " %" PRIuS "\n", auto start_end = StringPrintf("%" PRIuS " %" PRIuS "\n", kStartOfText - start,
kStartOfText - start, kEndOfText - start); kEndOfText - start);
file.WriteAtCurrentPos(start_end.c_str(), static_cast<int>(start_end.size())); file.WriteAtCurrentPos(start_end.c_str(), static_cast<int>(start_end.size()));
for (const auto& data_point : *data) { for (const auto& data_point : *data) {
auto timestamp = auto timestamp = StringPrintf("%" PRIu64 " ", data_point.timestamp_nanos);
base::StringPrintf("%" PRIu64 " ", data_point.timestamp_nanos);
file.WriteAtCurrentPos(timestamp.c_str(), file.WriteAtCurrentPos(timestamp.c_str(),
static_cast<int>(timestamp.size())); static_cast<int>(timestamp.size()));
@ -285,9 +284,8 @@ int NativeLibraryPrefetcher::PercentageOfResidentCode(size_t start,
if (!ok) if (!ok)
return -1; return -1;
total_pages += residency.size(); total_pages += residency.size();
resident_pages += resident_pages += static_cast<size_t>(
static_cast<size_t>(std::count_if(residency.begin(), residency.end(), ranges::count_if(residency, [](unsigned char x) { return x & 1; }));
[](unsigned char x) { return x & 1; }));
if (total_pages == 0) if (total_pages == 0)
return -1; return -1;
return static_cast<int>((100 * resident_pages) / total_pages); return static_cast<int>((100 * resident_pages) / total_pages);

View File

@ -180,7 +180,7 @@ __attribute__((always_inline, no_instrument_function)) void RecordAddress(
// Only the code in the native library is instrumented. Callees are expected // Only the code in the native library is instrumented. Callees are expected
// to be within the native library bounds. // to be within the native library bounds.
Disable(); Disable();
IMMEDIATE_CRASH(); ImmediateCrash();
} }
size_t offset = callee_address - start; size_t offset = callee_address - start;

View File

@ -139,7 +139,7 @@ __attribute__((always_inline, no_instrument_function)) void RecordAddress(
// deadlock. By crashing immediately we at least have a chance to get a // deadlock. By crashing immediately we at least have a chance to get a
// stack trace from the system to give some clue about the nature of the // stack trace from the system to give some clue about the nature of the
// problem. // problem.
IMMEDIATE_CRASH(); ImmediateCrash();
} }
// We should really crash at the first instance, but it does happen on bots, // We should really crash at the first instance, but it does happen on bots,

View File

@ -32,7 +32,7 @@ class BASE_EXPORT ScopedHardwareBufferFenceSync {
// Provides fence which is signaled when the reads for this buffer are done // Provides fence which is signaled when the reads for this buffer are done
// and it can be reused. Must only be called once. // and it can be reused. Must only be called once.
virtual void SetReadFence(base::ScopedFD fence_fd, bool has_context) = 0; virtual void SetReadFence(base::ScopedFD fence_fd) = 0;
private: private:
ScopedHardwareBufferHandle handle_; ScopedHardwareBufferHandle handle_;

View File

@ -62,22 +62,31 @@ static void JNI_TraceEvent_RegisterEnabledObserver(JNIEnv* env) {
static void JNI_TraceEvent_StartATrace( static void JNI_TraceEvent_StartATrace(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jstring>& category_filter) { const JavaParamRef<jstring>& category_filter) {
// ATrace not supported for robolectric.
#if BUILDFLAG(IS_ANDROID)
std::string category_filter_utf8 = std::string category_filter_utf8 =
ConvertJavaStringToUTF8(env, category_filter); ConvertJavaStringToUTF8(env, category_filter);
base::trace_event::TraceLog::GetInstance()->StartATrace(category_filter_utf8); base::trace_event::TraceLog::GetInstance()->StartATrace(category_filter_utf8);
#endif
} }
static void JNI_TraceEvent_StopATrace(JNIEnv* env) { static void JNI_TraceEvent_StopATrace(JNIEnv* env) {
// ATrace not supported for robolectric.
#if BUILDFLAG(IS_ANDROID)
base::trace_event::TraceLog::GetInstance()->StopATrace(); base::trace_event::TraceLog::GetInstance()->StopATrace();
#endif
} }
static void JNI_TraceEvent_SetupATraceStartupTrace( static void JNI_TraceEvent_SetupATraceStartupTrace(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jstring>& category_filter) { const JavaParamRef<jstring>& category_filter) {
// ATrace not supported for robolectric.
#if BUILDFLAG(IS_ANDROID)
std::string category_filter_utf8 = std::string category_filter_utf8 =
ConvertJavaStringToUTF8(env, category_filter); ConvertJavaStringToUTF8(env, category_filter);
base::trace_event::TraceLog::GetInstance()->SetupATraceStartupTrace( base::trace_event::TraceLog::GetInstance()->SetupATraceStartupTrace(
category_filter_utf8); category_filter_utf8);
#endif
} }
static jboolean JNI_TraceEvent_ViewHierarchyDumpEnabled(JNIEnv* env) { static jboolean JNI_TraceEvent_ViewHierarchyDumpEnabled(JNIEnv* env) {

View File

@ -73,7 +73,7 @@ class BASE_EXPORT AtExitManager {
#endif #endif
// Stack of managers to allow shadowing. // Stack of managers to allow shadowing.
const raw_ptr<AtExitManager> next_manager_; const raw_ptr<AtExitManager, DanglingUntriaged> next_manager_;
}; };
#if defined(UNIT_TEST) #if defined(UNIT_TEST)

View File

@ -24,6 +24,23 @@
namespace { namespace {
// Returns true if the module for |address| is found. |path| will contain
// the path to the module. Note that |path| may not be absolute.
[[nodiscard]] bool GetModulePathForAddress(base::FilePath* path,
const void* address);
bool GetModulePathForAddress(base::FilePath* path, const void* address) {
Dl_info info;
if (dladdr(address, &info) == 0)
return false;
*path = base::FilePath(info.dli_fname);
return true;
}
} // namespace
namespace base {
void GetNSExecutablePath(base::FilePath* path) { void GetNSExecutablePath(base::FilePath* path) {
DCHECK(path); DCHECK(path);
// Executable path can have relative references ("..") depending on // Executable path can have relative references ("..") depending on
@ -42,27 +59,10 @@ void GetNSExecutablePath(base::FilePath* path) {
// paths such as DIR_SRC_TEST_DATA_ROOT can work, since we expect absolute // paths such as DIR_SRC_TEST_DATA_ROOT can work, since we expect absolute
// paths to be returned here. // paths to be returned here.
// TODO(bauerb): http://crbug.com/259796, http://crbug.com/373477 // TODO(bauerb): http://crbug.com/259796, http://crbug.com/373477
base::ThreadRestrictions::ScopedAllowIO allow_io; base::ScopedAllowBlocking allow_blocking;
*path = base::MakeAbsoluteFilePath(base::FilePath(executable_path)); *path = base::MakeAbsoluteFilePath(base::FilePath(executable_path));
} }
// Returns true if the module for |address| is found. |path| will contain
// the path to the module. Note that |path| may not be absolute.
[[nodiscard]] bool GetModulePathForAddress(base::FilePath* path,
const void* address);
bool GetModulePathForAddress(base::FilePath* path, const void* address) {
Dl_info info;
if (dladdr(address, &info) == 0)
return false;
*path = base::FilePath(info.dli_fname);
return true;
}
} // namespace
namespace base {
bool PathProviderMac(int key, base::FilePath* result) { bool PathProviderMac(int key, base::FilePath* result) {
switch (key) { switch (key) {
case base::FILE_EXE: case base::FILE_EXE:

View File

@ -138,8 +138,8 @@ class BASE_EXPORT BigEndianWriter {
bool Write(T v); bool Write(T v);
// TODO(crbug.com/1298696): Breaks net_unittests. // TODO(crbug.com/1298696): Breaks net_unittests.
raw_ptr<char, DegradeToNoOpWhenMTE> ptr_; raw_ptr<char, DanglingUntriagedDegradeToNoOpWhenMTE> ptr_;
raw_ptr<char, DegradeToNoOpWhenMTE> end_; raw_ptr<char, DanglingUntriagedDegradeToNoOpWhenMTE> end_;
}; };
} // namespace base } // namespace base

View File

@ -9,7 +9,6 @@
#include "base/debug/debugging_buildflags.h" #include "base/debug/debugging_buildflags.h"
#include "base/debug/dump_without_crashing.h" #include "base/debug/dump_without_crashing.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/thread_annotations.h" #include "base/thread_annotations.h"
#include "build/build_config.h" #include "build/build_config.h"

View File

@ -51,11 +51,6 @@ class VoidifyStream {
void operator&(std::ostream&) {} void operator&(std::ostream&) {}
}; };
// Helper macro which avoids evaluating the arguents to a stream if the
// condition is false.
#define LAZY_CHECK_STREAM(stream, condition) \
!(condition) ? (void)0 : ::logging::VoidifyStream() & (stream)
// Macro which uses but does not evaluate expr and any stream parameters. // Macro which uses but does not evaluate expr and any stream parameters.
#define EAT_CHECK_STREAM_PARAMS(expr) \ #define EAT_CHECK_STREAM_PARAMS(expr) \
true ? (void)0 \ true ? (void)0 \
@ -93,18 +88,44 @@ class BASE_EXPORT CheckError {
CheckError(const CheckError&) = delete; CheckError(const CheckError&) = delete;
CheckError& operator=(const CheckError&) = delete; CheckError& operator=(const CheckError&) = delete;
template <typename T>
std::ostream& operator<<(T&& streamed_type) {
return stream() << streamed_type;
}
private: private:
explicit CheckError(LogMessage* log_message); explicit CheckError(LogMessage* log_message);
LogMessage* const log_message_; LogMessage* const log_message_;
}; };
#define CHECK_FUNCTION_IMPL(check_function, condition) \ // The 'switch' is used to prevent the 'else' from being ambiguous when the
LAZY_CHECK_STREAM(check_function(__FILE__, __LINE__, #condition).stream(), \ // macro is used in an 'if' clause such as:
!ANALYZER_ASSUME_TRUE(condition)) // if (a == 1)
// CHECK(Foo());
//
// TODO(crbug.com/1380930): Remove the const bool when the blink-gc plugin has
// been updated to accept `if (LIKELY(!field_))` as well as `if (!field_)`.
#define CHECK_FUNCTION_IMPL(check_failure_invocation, condition) \
switch (0) \
case 0: \
default: \
if (const bool checky_bool_lol = static_cast<bool>(condition); \
LIKELY(ANALYZER_ASSUME_TRUE(checky_bool_lol))) \
; \
else \
check_failure_invocation
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && \ #if defined(OFFICIAL_BUILD) && !defined(NDEBUG)
!BUILDFLAG(DCHECK_IS_CONFIGURABLE) #error "Debug builds are not expected to be optimized as official builds."
#endif // defined(OFFICIAL_BUILD) && !defined(NDEBUG)
#if defined(OFFICIAL_BUILD) && !DCHECK_IS_ON()
// Note that this uses IMMEDIATE_CRASH_ALWAYS_INLINE to force-inline in debug
// mode as well. See LoggingTest.CheckCausesDistinctBreakpoints.
[[noreturn]] IMMEDIATE_CRASH_ALWAYS_INLINE void CheckFailure() {
base::ImmediateCrash();
}
// Discard log strings to reduce code bloat. // Discard log strings to reduce code bloat.
// //
@ -112,33 +133,40 @@ class BASE_EXPORT CheckError {
// calling an out-of-line function instead of a noreturn inline macro prevents // calling an out-of-line function instead of a noreturn inline macro prevents
// compiler optimizations. // compiler optimizations.
#define CHECK(condition) \ #define CHECK(condition) \
UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_CHECK_STREAM_PARAMS() UNLIKELY(!(condition)) ? logging::CheckFailure() : EAT_CHECK_STREAM_PARAMS()
#define CHECK_WILL_STREAM() false #define CHECK_WILL_STREAM() false
// Strip the conditional string from official builds.
#define PCHECK(condition) \ #define PCHECK(condition) \
LAZY_CHECK_STREAM( \ CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck(__FILE__, __LINE__), \
::logging::CheckError::PCheck(__FILE__, __LINE__).stream(), \ condition)
UNLIKELY(!(condition)))
#else #else
#define CHECK_WILL_STREAM() true #define CHECK_WILL_STREAM() true
#define CHECK(condition) \ #define CHECK(condition) \
CHECK_FUNCTION_IMPL(::logging::CheckError::Check, condition) CHECK_FUNCTION_IMPL( \
::logging::CheckError::Check(__FILE__, __LINE__, #condition), condition)
#define PCHECK(condition) \ #define PCHECK(condition) \
CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck, condition) CHECK_FUNCTION_IMPL( \
::logging::CheckError::PCheck(__FILE__, __LINE__, #condition), \
condition)
#endif #endif
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
#define DCHECK(condition) \ #define DCHECK(condition) \
CHECK_FUNCTION_IMPL(::logging::CheckError::DCheck, condition) CHECK_FUNCTION_IMPL( \
::logging::CheckError::DCheck(__FILE__, __LINE__, #condition), \
condition)
#define DPCHECK(condition) \ #define DPCHECK(condition) \
CHECK_FUNCTION_IMPL(::logging::CheckError::DPCheck, condition) CHECK_FUNCTION_IMPL( \
::logging::CheckError::DPCheck(__FILE__, __LINE__, #condition), \
condition)
#else #else

View File

@ -18,7 +18,7 @@
// See https://crbug.com/672699. // See https://crbug.com/672699.
#define BLINK_RELEASE_ASSERT_EQUIVALENT(assertion) \ #define BLINK_RELEASE_ASSERT_EQUIVALENT(assertion) \
(UNLIKELY(!(assertion)) ? (IMMEDIATE_CRASH()) : (void)0) (UNLIKELY(!(assertion)) ? (base::ImmediateCrash()) : (void)0)
void DoCheck(bool b) { void DoCheck(bool b) {
CHECK(b) << "DoCheck " << b; CHECK(b) << "DoCheck " << b;

View File

@ -18,21 +18,19 @@ void check_is_test_impl() {
} // namespace base::internal } // namespace base::internal
namespace base::test { namespace base::test {
// base/test/allow_check_is_test_to_be_called.h declares // base/test/allow_check_is_test_for_testing.h declares
// `AllowCheckIsTestToBeCalled`, but is only allowed to be included in test // `AllowCheckIsTestForTesting`, but is only allowed to be included in test
// code. // code. We therefore have to also mark the symbol as exported here.
// We therefore have to also mark the symbol as exported here. BASE_EXPORT void AllowCheckIsTestForTesting() {
BASE_EXPORT void AllowCheckIsTestToBeCalled() { // This CHECK ensures that `AllowCheckIsTestForTesting` is called
LOG(WARNING) << "Allowing special test code paths"; // just once. Since it is called in `base::TestSuite`, this should effectivly
// This CHECK ensures that `AllowCheckIsTestToBeCalled` is called just once. // prevent calls to `AllowCheckIsTestForTesting` in production code
// Since it is called in `base::TestSuite`, this should effectivly prevent // (assuming that code has unit test coverage).
// calls to AllowCheckIsTestToBeCalled in production code (assuming that code
// has unit test coverage).
// //
// This is just in case someone ignores the fact that this function in the // This is just in case someone ignores the fact that this function in the
// `base::test` namespace and ends on "ForTesting". // `base::test` namespace and ends on "ForTesting".
CHECK(!g_this_is_a_test) CHECK(!g_this_is_a_test)
<< "AllowCheckIsTestToBeCalled must not be called more than once"; << "AllowCheckIsTestForTesting must not be called more than once";
g_this_is_a_test = true; g_this_is_a_test = true;
} }

View File

@ -140,19 +140,12 @@ class CheckOpResult {
char* message_ = nullptr; char* message_ = nullptr;
}; };
#if !CHECK_WILL_STREAM()
// Discard log strings to reduce code bloat.
#define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))
#else
// Helper macro for binary operators. // Helper macro for binary operators.
// The 'switch' is used to prevent the 'else' from being ambiguous when the // The 'switch' is used to prevent the 'else' from being ambiguous when the
// macro is used in an 'if' clause such as: // macro is used in an 'if' clause such as:
// if (a == 1) // if (a == 1)
// CHECK_EQ(2, a); // CHECK_EQ(2, a);
#define CHECK_OP(name, op, val1, val2) \ #define CHECK_OP_FUNCTION_IMPL(check_function, name, op, val1, val2) \
switch (0) \ switch (0) \
case 0: \ case 0: \
default: \ default: \
@ -161,8 +154,17 @@ class CheckOpResult {
#val1 " " #op " " #val2)) \ #val1 " " #op " " #val2)) \
; \ ; \
else \ else \
::logging::CheckError::CheckOp(__FILE__, __LINE__, &true_if_passed) \ check_function(__FILE__, __LINE__, &true_if_passed)
.stream()
#if !CHECK_WILL_STREAM()
// Discard log strings to reduce code bloat.
#define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))
#else
#define CHECK_OP(name, op, val1, val2) \
CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, val1, val2)
#endif #endif
@ -211,16 +213,7 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
#define DCHECK_OP(name, op, val1, val2) \ #define DCHECK_OP(name, op, val1, val2) \
switch (0) \ CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DCheckOp, name, op, val1, val2)
case 0: \
default: \
if (::logging::CheckOpResult true_if_passed = \
::logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2)) \
; \
else \
::logging::CheckError::DCheckOp(__FILE__, __LINE__, &true_if_passed) \
.stream()
#else #else

View File

@ -29,11 +29,16 @@ Google naming. Be sure to use the base namespace.
### Usage advice ### Usage advice
* Generally avoid `std::unordered_set` and `std::unordered_map`. In the common * Do not use `base::flat_map` or `base::flat_set` if the number of items will
case, query performance is unlikely to be sufficiently higher than be large or unbounded and elements will be inserted/deleted outside of the
`std::map` to make a difference, insert performance is slightly worse, and containers constructor/destructor - they have O(n) performance on inserts
the memory overhead is high. This makes sense mostly for large tables where and deletes of individual items.
you expect a lot of lookups.
* Do not default to using `std::unordered_set` and `std::unordered_map`. In
the common case, query performance is unlikely to be sufficiently higher
than `std::map` to make a difference, insert performance is slightly worse,
and the memory overhead is high. This makes sense mostly for large tables
where you expect a lot of lookups.
* Most maps and sets in Chrome are small and contain objects that can be moved * Most maps and sets in Chrome are small and contain objects that can be moved
efficiently. In this case, consider `base::flat_map` and `base::flat_set`. efficiently. In this case, consider `base::flat_map` and `base::flat_set`.
@ -65,12 +70,12 @@ Google naming. Be sure to use the base namespace.
Sizes are on 64-bit platforms. Stable iterators aren't invalidated when the Sizes are on 64-bit platforms. Stable iterators aren't invalidated when the
container is mutated. container is mutated.
| Container | Empty size | Per-item overhead | Stable iterators? | | Container | Empty size | Per-item overhead | Stable iterators? | Insert/delete complexity |
|:------------------------------------------ |:--------------------- |:----------------- |:----------------- | |:------------------------------------------ |:--------------------- |:----------------- |:----------------- |:-----------------------------|
| `std::map`, `std::set` | 16 bytes | 32 bytes | Yes | | `std::map`, `std::set` | 16 bytes | 32 bytes | Yes | O(log n) |
| `std::unordered_map`, `std::unordered_set` | 128 bytes | 16 - 24 bytes | No | | `std::unordered_map`, `std::unordered_set` | 128 bytes | 16 - 24 bytes | No | O(1) |
| `base::flat_map`, `base::flat_set` | 24 bytes | 0 (see notes) | No | | `base::flat_map`, `base::flat_set` | 24 bytes | 0 (see notes) | No | O(n) |
| `base::small_map` | 24 bytes (see notes) | 32 bytes | No | | `base::small_map` | 24 bytes (see notes) | 32 bytes | No | depends on fallback map type |
**Takeaways:** `std::unordered_map` and `std::unordered_set` have high **Takeaways:** `std::unordered_map` and `std::unordered_set` have high
overhead for small container sizes, so prefer these only for larger workloads. overhead for small container sizes, so prefer these only for larger workloads.

View File

@ -10,6 +10,8 @@
#include <iterator> #include <iterator>
#include <utility> #include <utility>
#include "base/memory/raw_ref.h"
namespace base { namespace base {
namespace internal { namespace internal {
@ -24,11 +26,15 @@ class ReversedAdapter {
ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {} ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
ReversedAdapter& operator=(const ReversedAdapter&) = delete; ReversedAdapter& operator=(const ReversedAdapter&) = delete;
Iterator begin() const { return std::rbegin(t_); } Iterator begin() const { return std::rbegin(*t_); }
Iterator end() const { return std::rend(t_); } Iterator end() const { return std::rend(*t_); }
private: private:
T& t_; // `ReversedAdapter` and therefore `t_` are only used inside for loops. The
// container being iterated over should be the one holding a raw_ref/raw_ptr
// ideally. This member's type was rewritten into `const raw_ref` since it
// didn't hurt binary size at the time of the rewrite.
const raw_ref<T> t_;
}; };
} // namespace internal } // namespace internal

View File

@ -5,11 +5,14 @@
#ifndef BASE_CONTAINERS_BUFFER_ITERATOR_H_ #ifndef BASE_CONTAINERS_BUFFER_ITERATOR_H_
#define BASE_CONTAINERS_BUFFER_ITERATOR_H_ #define BASE_CONTAINERS_BUFFER_ITERATOR_H_
#include <string.h>
#include <type_traits> #include <type_traits>
#include "base/bit_cast.h" #include "base/bit_cast.h"
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/numerics/checked_math.h" #include "base/numerics/checked_math.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base { namespace base {
@ -70,16 +73,12 @@ class BufferIterator {
// position. On success, the iterator position is advanced by sizeof(T). If // position. On success, the iterator position is advanced by sizeof(T). If
// there are not sizeof(T) bytes remaining in the buffer, returns nullptr. // there are not sizeof(T) bytes remaining in the buffer, returns nullptr.
template <typename T, template <typename T,
typename = typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
T* MutableObject() { T* MutableObject() {
size_t size = sizeof(T); size_t size = sizeof(T);
size_t next_position; if (size > remaining_.size())
if (!CheckAdd(position(), size).AssignIfValid(&next_position))
return nullptr; return nullptr;
if (next_position > total_size()) T* t = reinterpret_cast<T*>(remaining_.data());
return nullptr;
T* t = bit_cast<T*>(remaining_.data());
remaining_ = remaining_.subspan(size); remaining_ = remaining_.subspan(size);
return t; return t;
} }
@ -87,29 +86,37 @@ class BufferIterator {
// Returns a const pointer to an object of type T in the buffer at the current // Returns a const pointer to an object of type T in the buffer at the current
// position. // position.
template <typename T, template <typename T,
typename = typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
const T* Object() { const T* Object() {
return MutableObject<const T>(); return MutableObject<const T>();
} }
// Copies out an object. As compared to using Object, this avoids potential
// unaligned access which may be undefined behavior.
template <typename T,
typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
absl::optional<T> CopyObject() {
absl::optional<T> t;
if (remaining_.size() >= sizeof(T)) {
memcpy(&t.emplace(), remaining_.data(), sizeof(T));
remaining_ = remaining_.subspan(sizeof(T));
}
return t;
}
// Returns a span of |count| T objects in the buffer at the current position. // Returns a span of |count| T objects in the buffer at the current position.
// On success, the iterator position is advanced by |sizeof(T) * count|. If // On success, the iterator position is advanced by |sizeof(T) * count|. If
// there are not enough bytes remaining in the buffer to fulfill the request, // there are not enough bytes remaining in the buffer to fulfill the request,
// returns an empty span. // returns an empty span.
template <typename T, template <typename T,
typename = typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
span<T> MutableSpan(size_t count) { span<T> MutableSpan(size_t count) {
size_t size; size_t size;
if (!CheckMul(sizeof(T), count).AssignIfValid(&size)) if (!CheckMul(sizeof(T), count).AssignIfValid(&size))
return span<T>(); return span<T>();
size_t next_position; if (size > remaining_.size())
if (!CheckAdd(position(), size).AssignIfValid(&next_position))
return span<T>(); return span<T>();
if (next_position > total_size()) auto result = span<T>(reinterpret_cast<T*>(remaining_.data()), count);
return span<T>();
auto result = span<T>(bit_cast<T*>(remaining_.data()), count);
remaining_ = remaining_.subspan(size); remaining_ = remaining_.subspan(size);
return result; return result;
} }
@ -117,8 +124,7 @@ class BufferIterator {
// Returns a span to |count| const objects of type T in the buffer at the // Returns a span to |count| const objects of type T in the buffer at the
// current position. // current position.
template <typename T, template <typename T,
typename = typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
span<const T> Span(size_t count) { span<const T> Span(size_t count) {
return MutableSpan<const T>(count); return MutableSpan<const T>(count);
} }
@ -126,11 +132,19 @@ class BufferIterator {
// Resets the iterator position to the absolute offset |to|. // Resets the iterator position to the absolute offset |to|.
void Seek(size_t to) { remaining_ = buffer_.subspan(to); } void Seek(size_t to) { remaining_ = buffer_.subspan(to); }
// Limits the remaining data to the specified size.
// Seeking to an absolute offset reverses this.
void TruncateTo(size_t size) { remaining_ = remaining_.first(size); }
// Returns the total size of the underlying buffer. // Returns the total size of the underlying buffer.
size_t total_size() { return buffer_.size(); } size_t total_size() const { return buffer_.size(); }
// Returns the current position in the buffer. // Returns the current position in the buffer.
size_t position() { return buffer_.size_bytes() - remaining_.size_bytes(); } size_t position() const {
DCHECK(buffer_.data() <= remaining_.data());
DCHECK(remaining_.data() <= buffer_.data() + buffer_.size());
return static_cast<size_t>(remaining_.data() - buffer_.data());
}
private: private:
// The original buffer that the iterator was constructed with. // The original buffer that the iterator was constructed with.

View File

@ -263,6 +263,11 @@ class EnumSet {
return (enums_ & other.enums_) == other.enums_; return (enums_ & other.enums_) == other.enums_;
} }
// Returns true if the given set contains any value of our set.
bool HasAny(EnumSet other) const {
return (enums_ & other.enums_).count() > 0;
}
// Returns true iff our set is empty. // Returns true iff our set is empty.
bool Empty() const { return !enums_.any(); } bool Empty() const { return !enums_.any(); }

View File

@ -344,6 +344,7 @@ class flat_tree {
template <typename DummyT = void> template <typename DummyT = void>
iterator erase(const_iterator position); iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last); iterator erase(const_iterator first, const_iterator last);
size_type erase(const Key& key);
template <typename K> template <typename K>
size_type erase(const K& key); size_type erase(const K& key);
@ -358,33 +359,39 @@ class flat_tree {
// //
// Search operations have O(log(size)) complexity. // Search operations have O(log(size)) complexity.
size_type count(const Key& key) const;
template <typename K> template <typename K>
size_type count(const K& key) const; size_type count(const K& key) const;
iterator find(const Key& key);
const_iterator find(const Key& key) const;
template <typename K> template <typename K>
iterator find(const K& key); iterator find(const K& key);
template <typename K> template <typename K>
const_iterator find(const K& key) const; const_iterator find(const K& key) const;
bool contains(const Key& key) const;
template <typename K> template <typename K>
bool contains(const K& key) const; bool contains(const K& key) const;
std::pair<iterator, iterator> equal_range(const Key& key);
std::pair<const_iterator, const_iterator> equal_range(const Key& key) const;
template <typename K> template <typename K>
std::pair<iterator, iterator> equal_range(const K& key); std::pair<iterator, iterator> equal_range(const K& key);
template <typename K> template <typename K>
std::pair<const_iterator, const_iterator> equal_range(const K& key) const; std::pair<const_iterator, const_iterator> equal_range(const K& key) const;
iterator lower_bound(const Key& key);
const_iterator lower_bound(const Key& key) const;
template <typename K> template <typename K>
iterator lower_bound(const K& key); iterator lower_bound(const K& key);
template <typename K> template <typename K>
const_iterator lower_bound(const K& key) const; const_iterator lower_bound(const K& key) const;
iterator upper_bound(const Key& key);
const_iterator upper_bound(const Key& key) const;
template <typename K> template <typename K>
iterator upper_bound(const K& key); iterator upper_bound(const K& key);
template <typename K> template <typename K>
const_iterator upper_bound(const K& key) const; const_iterator upper_bound(const K& key) const;
@ -469,7 +476,10 @@ class flat_tree {
const K& extract_if_value_type(const K& k) const { const K& extract_if_value_type(const K& k) const {
return k; return k;
} }
// This field was not rewritten into `const raw_ref<const key_compare>` due
// to binary size increase. There's also little value to rewriting this
// member as it points to `flat_tree::comp_`. The flat_tree itself should be
// holding raw_ptr/raw_ref if necessary.
const key_compare& comp_; const key_compare& comp_;
}; };
@ -900,6 +910,16 @@ auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(
return body_.erase(position); return body_.erase(position);
} }
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(
const Key& val) -> size_type {
auto eq_range = equal_range(val);
auto res =
static_cast<size_type>(std::distance(eq_range.first, eq_range.second));
erase(eq_range.first, eq_range.second);
return res;
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container> template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
template <typename K> template <typename K>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(const K& val) auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(const K& val)
@ -946,6 +966,26 @@ auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::count(
return static_cast<size_type>(std::distance(eq_range.first, eq_range.second)); return static_cast<size_type>(std::distance(eq_range.first, eq_range.second));
} }
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::count(
const Key& key) const -> size_type {
auto eq_range = equal_range(key);
return static_cast<size_type>(std::distance(eq_range.first, eq_range.second));
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(
const Key& key) -> iterator {
return const_cast_it(std::as_const(*this).find(key));
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(
const Key& key) const -> const_iterator {
auto eq_range = equal_range(key);
return (eq_range.first == eq_range.second) ? end() : eq_range.first;
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container> template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
template <typename K> template <typename K>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(const K& key) auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(const K& key)
@ -961,6 +1001,13 @@ auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(
return (eq_range.first == eq_range.second) ? end() : eq_range.first; return (eq_range.first == eq_range.second) ? end() : eq_range.first;
} }
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains(
const Key& key) const {
auto lower = lower_bound(key);
return lower != end() && !comp_(key, GetKeyFromValue()(*lower));
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container> template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
template <typename K> template <typename K>
bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains( bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains(
@ -969,6 +1016,25 @@ bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains(
return lower != end() && !comp_(key, GetKeyFromValue()(*lower)); return lower != end() && !comp_(key, GetKeyFromValue()(*lower));
} }
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
const Key& key) -> std::pair<iterator, iterator> {
auto res = std::as_const(*this).equal_range(key);
return {const_cast_it(res.first), const_cast_it(res.second)};
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
const Key& key) const -> std::pair<const_iterator, const_iterator> {
auto lower = lower_bound(key);
KeyValueCompare comp(comp_);
if (lower == end() || comp(key, *lower))
return {lower, lower};
return {lower, std::next(lower)};
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container> template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
template <typename K> template <typename K>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range( auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
@ -990,6 +1056,19 @@ auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
return {lower, std::next(lower)}; return {lower, std::next(lower)};
} }
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
const Key& key) -> iterator {
return const_cast_it(std::as_const(*this).lower_bound(key));
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
const Key& key) const -> const_iterator {
KeyValueCompare comp(comp_);
return ranges::lower_bound(*this, key, comp);
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container> template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
template <typename K> template <typename K>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound( auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
@ -1011,6 +1090,19 @@ auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
return ranges::lower_bound(*this, key_ref, comp); return ranges::lower_bound(*this, key_ref, comp);
} }
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound(
const Key& key) -> iterator {
return const_cast_it(std::as_const(*this).upper_bound(key));
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound(
const Key& key) const -> const_iterator {
KeyValueCompare comp(comp_);
return ranges::upper_bound(*this, key, comp);
}
template <class Key, class GetKeyFromValue, class KeyCompare, class Container> template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
template <typename K> template <typename K>
auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound( auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound(

View File

@ -8,6 +8,7 @@
#include <stddef.h> #include <stddef.h>
#include "base/check.h" #include "base/check.h"
#include "base/memory/raw_ref.h"
namespace base { namespace base {
@ -64,8 +65,8 @@ class RingBuffer {
public: public:
size_t index() const { return index_; } size_t index() const { return index_; }
const T* operator->() const { return &buffer_.ReadBuffer(index_); } const T* operator->() const { return &buffer_->ReadBuffer(index_); }
const T* operator*() const { return &buffer_.ReadBuffer(index_); } const T* operator*() const { return &buffer_->ReadBuffer(index_); }
Iterator& operator++() { Iterator& operator++() {
index_++; index_++;
@ -82,14 +83,14 @@ class RingBuffer {
} }
operator bool() const { operator bool() const {
return !out_of_range_ && buffer_.IsFilledIndex(index_); return !out_of_range_ && buffer_->IsFilledIndex(index_);
} }
private: private:
Iterator(const RingBuffer<T, kSize>& buffer, size_t index) Iterator(const RingBuffer<T, kSize>& buffer, size_t index)
: buffer_(buffer), index_(index), out_of_range_(false) {} : buffer_(buffer), index_(index), out_of_range_(false) {}
const RingBuffer<T, kSize>& buffer_; const raw_ref<const RingBuffer<T, kSize>> buffer_;
size_t index_; size_t index_;
bool out_of_range_; bool out_of_range_;

View File

@ -17,27 +17,15 @@
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "build/build_config.h" #include "build/build_config.h"
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
BUILDFLAG(IS_AIX)
#include "base/containers/flat_set.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/notreached.h"
#include "base/process/internal_linux.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/threading/thread_restrictions.h"
#endif
#if defined(ARCH_CPU_ARM_FAMILY) && \ #if defined(ARCH_CPU_ARM_FAMILY) && \
(BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include <sys/auxv.h> #include <sys/auxv.h>
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/numerics/checked_math.h" #include "base/numerics/checked_math.h"
#include "base/ranges/algorithm.h" #include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
@ -390,267 +378,6 @@ CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
} }
#endif #endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
BUILDFLAG(IS_AIX)
namespace {
constexpr char kTimeInStatePath[] =
"/sys/devices/system/cpu/cpu%" PRIuS "/cpufreq/stats/time_in_state";
constexpr char kPhysicalPackageIdPath[] =
"/sys/devices/system/cpu/cpu%" PRIuS "/topology/physical_package_id";
constexpr char kCoreIdleStateTimePath[] =
"/sys/devices/system/cpu/cpu%" PRIuS "/cpuidle/state%d/time";
bool SupportsTimeInState() {
// Reading from time_in_state doesn't block (it amounts to reading a struct
// from the cpufreq-stats kernel driver).
ThreadRestrictions::ScopedAllowIO allow_io;
// Check if the time_in_state path for the first core is readable.
FilePath time_in_state_path(
StringPrintf(kTimeInStatePath, /*core_index=*/size_t{0}));
ScopedFILE file_stream(OpenFile(time_in_state_path, "rb"));
return static_cast<bool>(file_stream);
}
bool ParseTimeInState(const std::string& content,
CPU::CoreType core_type,
size_t core_index,
CPU::TimeInState& time_in_state) {
const char* begin = content.data();
size_t max_pos = content.size() - 1;
// Example time_in_state content:
// ---
// 300000 1
// 403200 0
// 499200 15
// ---
// Iterate over the individual lines.
for (size_t pos = 0; pos <= max_pos;) {
int num_chars = 0;
// Each line should have two integer fields, frequency (kHz) and time (in
// jiffies), separated by a space, e.g. "2419200 132".
uint64_t frequency;
int64_t time;
int matches = sscanf(begin + pos, "%" PRIu64 " %" PRId64 "\n%n", &frequency,
&time, &num_chars);
if (matches != 2)
return false;
// Skip zero-valued entries in the output list (no time spent at this
// frequency).
if (time > 0) {
time_in_state.push_back({core_type, core_index, frequency,
internal::ClockTicksToTimeDelta(time)});
}
// Advance line.
DCHECK_GT(num_chars, 0);
pos += static_cast<size_t>(num_chars);
}
return true;
}
bool SupportsCoreIdleTimes() {
// Reading from the cpuidle driver doesn't block.
ThreadRestrictions::ScopedAllowIO allow_io;
// Check if the path for the idle time in state 0 for core 0 is readable.
FilePath idle_state0_path(StringPrintf(
kCoreIdleStateTimePath, /*core_index=*/size_t{0}, /*idle_state=*/0));
ScopedFILE file_stream(OpenFile(idle_state0_path, "rb"));
return static_cast<bool>(file_stream);
}
std::vector<CPU::CoreType> GuessCoreTypes() {
// Try to guess the CPU architecture and cores of each cluster by comparing
// the maximum frequencies of the available (online and offline) cores.
const char kCPUMaxFreqPath[] =
"/sys/devices/system/cpu/cpu%" PRIuS "/cpufreq/cpuinfo_max_freq";
size_t num_cpus = static_cast<size_t>(SysInfo::NumberOfProcessors());
std::vector<CPU::CoreType> core_index_to_type(num_cpus,
CPU::CoreType::kUnknown);
std::vector<uint32_t> max_core_frequencies_mhz(num_cpus, 0);
flat_set<uint32_t> frequencies_mhz;
{
// Reading from cpuinfo_max_freq doesn't block (it amounts to reading a
// struct field from the cpufreq kernel driver).
ThreadRestrictions::ScopedAllowIO allow_io;
for (size_t core_index = 0; core_index < num_cpus; ++core_index) {
std::string content;
uint32_t frequency_khz = 0;
auto path = StringPrintf(kCPUMaxFreqPath, core_index);
if (ReadFileToString(FilePath(path), &content))
StringToUint(content, &frequency_khz);
uint32_t frequency_mhz = frequency_khz / 1000;
max_core_frequencies_mhz[core_index] = frequency_mhz;
if (frequency_mhz > 0)
frequencies_mhz.insert(frequency_mhz);
}
}
size_t num_frequencies = frequencies_mhz.size();
for (size_t core_index = 0; core_index < num_cpus; ++core_index) {
uint32_t core_frequency_mhz = max_core_frequencies_mhz[core_index];
CPU::CoreType core_type = CPU::CoreType::kOther;
if (num_frequencies == 1u) {
core_type = CPU::CoreType::kSymmetric;
} else if (num_frequencies == 2u || num_frequencies == 3u) {
auto it = frequencies_mhz.find(core_frequency_mhz);
if (it != frequencies_mhz.end()) {
// flat_set is sorted.
ptrdiff_t frequency_index = it - frequencies_mhz.begin();
switch (frequency_index) {
case 0:
core_type = num_frequencies == 2u
? CPU::CoreType::kBigLittle_Little
: CPU::CoreType::kBigLittleBigger_Little;
break;
case 1:
core_type = num_frequencies == 2u
? CPU::CoreType::kBigLittle_Big
: CPU::CoreType::kBigLittleBigger_Big;
break;
case 2:
DCHECK_EQ(num_frequencies, 3u);
core_type = CPU::CoreType::kBigLittleBigger_Bigger;
break;
default:
NOTREACHED();
break;
}
}
}
core_index_to_type[core_index] = core_type;
}
return core_index_to_type;
}
} // namespace
// static
const std::vector<CPU::CoreType>& CPU::GetGuessedCoreTypes() {
static NoDestructor<std::vector<CoreType>> kCoreTypes(GuessCoreTypes());
return *kCoreTypes.get();
}
// static
bool CPU::GetTimeInState(TimeInState& time_in_state) {
time_in_state.clear();
// The kernel may not support the cpufreq-stats driver.
static const bool kSupportsTimeInState = SupportsTimeInState();
if (!kSupportsTimeInState)
return false;
static const std::vector<CoreType>& kCoreTypes = GetGuessedCoreTypes();
// time_in_state is reported per cluster. Identify the first cores of each
// cluster.
static NoDestructor<std::vector<size_t>> kFirstCoresIndexes([]() {
std::vector<size_t> first_cores;
int last_core_package_id = 0;
for (size_t core_index = 0;
core_index < static_cast<size_t>(SysInfo::NumberOfProcessors());
core_index++) {
// Reading from physical_package_id doesn't block (it amounts to reading a
// struct field from the kernel).
ThreadRestrictions::ScopedAllowIO allow_io;
FilePath package_id_path(
StringPrintf(kPhysicalPackageIdPath, core_index));
std::string package_id_str;
if (!ReadFileToString(package_id_path, &package_id_str))
return std::vector<size_t>();
int package_id;
base::StringPiece trimmed = base::TrimWhitespaceASCII(
package_id_str, base::TrimPositions::TRIM_ALL);
if (!base::StringToInt(trimmed, &package_id))
return std::vector<size_t>();
if (last_core_package_id != package_id || core_index == 0)
first_cores.push_back(core_index);
last_core_package_id = package_id;
}
return first_cores;
}());
if (kFirstCoresIndexes->empty())
return false;
// Reading from time_in_state doesn't block (it amounts to reading a struct
// from the cpufreq-stats kernel driver).
ThreadRestrictions::ScopedAllowIO allow_io;
// Read the time_in_state for each cluster from the /sys directory of the
// cluster's first core.
for (size_t cluster_core_index : *kFirstCoresIndexes) {
FilePath time_in_state_path(
StringPrintf(kTimeInStatePath, cluster_core_index));
std::string buffer;
if (!ReadFileToString(time_in_state_path, &buffer))
return false;
if (!ParseTimeInState(buffer, kCoreTypes[cluster_core_index],
cluster_core_index, time_in_state)) {
return false;
}
}
return true;
}
// static
bool CPU::GetCumulativeCoreIdleTimes(CoreIdleTimes& idle_times) {
idle_times.clear();
// The kernel may not support the cpufreq-stats driver.
static const bool kSupportsIdleTimes = SupportsCoreIdleTimes();
if (!kSupportsIdleTimes)
return false;
// Reading from the cpuidle driver doesn't block.
ThreadRestrictions::ScopedAllowIO allow_io;
size_t num_cpus = static_cast<size_t>(SysInfo::NumberOfProcessors());
bool success = false;
for (size_t core_index = 0; core_index < num_cpus; ++core_index) {
std::string content;
TimeDelta idle_time;
// The number of idle states is system/CPU dependent, so we increment and
// try to read each state until we fail.
for (int state_index = 0;; ++state_index) {
auto path = StringPrintf(kCoreIdleStateTimePath, core_index, state_index);
uint64_t idle_state_time = 0;
if (!ReadFileToString(FilePath(path), &content))
break;
StringToUint64(content, &idle_state_time);
idle_time += Microseconds(idle_state_time);
}
idle_times.push_back(idle_time);
// At least one of the cores should have some idle time, otherwise we report
// a failure.
success |= idle_time.is_positive();
}
return success;
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
// BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_AIX)
const CPU& CPU::GetInstanceNoAllocation() { const CPU& CPU::GetInstanceNoAllocation() {
static const base::NoDestructor<const CPU> cpu(CPU(false)); static const base::NoDestructor<const CPU> cpu(CPU(false));

View File

@ -6,10 +6,8 @@
#define BASE_CPU_H_ #define BASE_CPU_H_
#include <string> #include <string>
#include <vector>
#include "base/base_export.h" #include "base/base_export.h"
#include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
namespace base { namespace base {
@ -114,60 +112,6 @@ class BASE_EXPORT CPU final {
#endif #endif
const std::string& cpu_brand() const { return cpu_brand_; } const std::string& cpu_brand() const { return cpu_brand_; }
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
BUILDFLAG(IS_AIX)
enum class CoreType {
kUnknown = 0,
kOther,
kSymmetric,
kBigLittle_Little,
kBigLittle_Big,
kBigLittleBigger_Little,
kBigLittleBigger_Big,
kBigLittleBigger_Bigger,
kMaxValue = kBigLittleBigger_Bigger
};
// Attempts to guess the core types of individual CPU cores based on frequency
// information from /sys/devices/system/cpu/cpuN/cpufreq/cpuinfo_max_freq.
// Beware that it is kernel/hardware dependent whether the information from
// sys is accurate. Returns a reference to a static-storage vector (leaked on
// shutdown) with the guessed type for core N at index N.
static const std::vector<CoreType>& GetGuessedCoreTypes();
struct TimeInStateEntry {
CPU::CoreType core_type; // type of the cores in this cluster.
size_t cluster_core_index; // index of the first core in the cluster.
uint64_t core_frequency_khz;
TimeDelta cumulative_time;
};
using TimeInState = std::vector<TimeInStateEntry>;
// For each CPU core, emits the cumulative time spent in different frequency
// states into the output parameter (replacing its current contents). One
// entry in the output parameter is added for each cluster core index
// + frequency state combination with a non-zero CPU time value. Returns false
// on failure. We return the usage via an output parameter to allow reuse of
// TimeInState's std::vector by the caller, e.g. to avoid allocations between
// repeated calls to this method.
//
// NOTE: Currently only supported on Linux/Android, and only on kernels with
// cpufreq-stats driver.
static bool GetTimeInState(TimeInState&);
// For each CPU core, emits the total cumulative wall time spent in any idle
// state into the output parameter (replacing its current contents). Returns
// false on failure. We return the usage via an output parameter to allow
// reuse of TimeInState's std::vector by the caller, e.g. to avoid allocations
// between repeated calls to this method.
//
// NOTE: Currently only supported on Linux/Android, and only on kernels with
// cpuidle driver.
using CoreIdleTimes = std::vector<TimeDelta>;
static bool GetCumulativeCoreIdleTimes(CoreIdleTimes&);
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
// BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_AIX)
private: private:
// Query the processor for CPUID information. // Query the processor for CPUID information.
void Initialize(bool requires_branding); void Initialize(bool requires_branding);

View File

@ -5,10 +5,24 @@
#ifndef BASE_CXX20_TO_ADDRESS_H_ #ifndef BASE_CXX20_TO_ADDRESS_H_
#define BASE_CXX20_TO_ADDRESS_H_ #define BASE_CXX20_TO_ADDRESS_H_
#include <memory>
#include <type_traits> #include <type_traits>
namespace base { namespace base {
namespace {
template <typename Ptr, typename = void>
struct has_std_to_address : std::false_type {};
template <typename Ptr>
struct has_std_to_address<
Ptr,
std::void_t<decltype(std::pointer_traits<Ptr>::to_address(
std::declval<Ptr>()))>> : std::true_type {};
} // namespace
// Implementation of C++20's std::to_address. // Implementation of C++20's std::to_address.
// Note: This does consider specializations of pointer_traits<>::to_address, // Note: This does consider specializations of pointer_traits<>::to_address,
// even though it's a C++20 member function, because CheckedContiguousIterator // even though it's a C++20 member function, because CheckedContiguousIterator
@ -23,14 +37,12 @@ constexpr T* to_address(T* p) noexcept {
} }
template <typename Ptr> template <typename Ptr>
constexpr auto to_address(const Ptr& p) noexcept constexpr auto to_address(const Ptr& p) noexcept {
-> decltype(std::pointer_traits<Ptr>::to_address(p)) { if constexpr (has_std_to_address<Ptr>::value) {
return std::pointer_traits<Ptr>::to_address(p); return std::pointer_traits<Ptr>::to_address(p);
} } else {
template <typename Ptr, typename... None>
constexpr auto to_address(const Ptr& p, None...) noexcept {
return base::to_address(p.operator->()); return base::to_address(p.operator->());
}
} }
} // namespace base } // namespace base

View File

@ -4,6 +4,8 @@
#include "base/debug/crash_logging.h" #include "base/debug/crash_logging.h"
#include <ostream>
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "build/build_config.h" #include "build/build_config.h"

View File

@ -4,6 +4,8 @@
#include "base/debug/dwarf_line_no.h" #include "base/debug/dwarf_line_no.h"
#include "base/memory/raw_ref.h"
#ifdef USE_SYMBOLIZE #ifdef USE_SYMBOLIZE
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
@ -188,7 +190,7 @@ void EvaluateLineNumberProgram(const int fd,
private: private:
raw_ptr<LineNumberInfo> info; raw_ptr<LineNumberInfo> info;
uint64_t module_relative_pc; uint64_t module_relative_pc;
const ProgramInfo& program_info; const raw_ref<const ProgramInfo> program_info;
public: public:
OnCommitImpl(LineNumberInfo* info, OnCommitImpl(LineNumberInfo* info,
@ -213,7 +215,7 @@ void EvaluateLineNumberProgram(const int fd,
module_relative_pc >= registers->address) module_relative_pc >= registers->address)
return; return;
if (registers->last_file < program_info.num_filenames) { if (registers->last_file < program_info->num_filenames) {
info->line = registers->last_line; info->line = registers->last_line;
info->column = registers->last_column; info->column = registers->last_column;
@ -222,19 +224,19 @@ void EvaluateLineNumberProgram(const int fd,
// follow spec, but seems to be common behavior. See the following LLVM // follow spec, but seems to be common behavior. See the following LLVM
// bug for more info: https://reviews.llvm.org/D11003 // bug for more info: https://reviews.llvm.org/D11003
if (registers->last_file == 0 && if (registers->last_file == 0 &&
program_info.filename_offsets[0] == 0 && program_info->filename_offsets[0] == 0 &&
1 < program_info.num_filenames) { 1 < program_info->num_filenames) {
program_info.filename_offsets[0] = program_info.filename_offsets[1]; program_info->filename_offsets[0] = program_info->filename_offsets[1];
program_info.filename_dirs[0] = program_info.filename_dirs[1]; program_info->filename_dirs[0] = program_info->filename_dirs[1];
} }
if (registers->last_file < kMaxFilenames) { if (registers->last_file < kMaxFilenames) {
info->module_filename_offset = info->module_filename_offset =
program_info.filename_offsets[registers->last_file]; program_info->filename_offsets[registers->last_file];
uint8_t dir = program_info.filename_dirs[registers->last_file]; uint8_t dir = program_info->filename_dirs[registers->last_file];
info->module_dir_offset = program_info.directory_offsets[dir]; info->module_dir_offset = program_info->directory_offsets[dir];
info->dir_size = program_info.directory_sizes[dir]; info->dir_size = program_info->directory_sizes[dir];
} }
} }
} }

View File

@ -98,7 +98,7 @@ void StackTrace::OutputToStreamWithPrefix(std::ostream* os,
// on fatal log messages in debug builds only. If the restriction is enabled // on fatal log messages in debug builds only. If the restriction is enabled
// then it will recursively trigger fatal failures when this enters on the // then it will recursively trigger fatal failures when this enters on the
// UI thread. // UI thread.
base::ThreadRestrictions::ScopedAllowIO allow_io; base::ScopedAllowBlocking scoped_allow_blocking;
if (!ReadProcMaps(&proc_maps)) { if (!ReadProcMaps(&proc_maps)) {
__android_log_write( __android_log_write(
ANDROID_LOG_ERROR, "chromium", "Failed to read /proc/self/maps"); ANDROID_LOG_ERROR, "chromium", "Failed to read /proc/self/maps");

View File

@ -201,6 +201,22 @@ void SymbolMap::Populate() {
valid_ = true; valid_ = true;
} }
// Returns true if |address| is contained by any of the memory regions
// mapped for |module_entry|.
bool ModuleContainsFrameAddress(void* address,
const SymbolMap::Module& module_entry) {
for (size_t i = 0; i < module_entry.segment_count; ++i) {
const SymbolMap::Segment& segment = module_entry.segments[i];
const void* segment_end = reinterpret_cast<const void*>(
reinterpret_cast<const char*>(segment.addr) + segment.size - 1);
if (address >= segment.addr && address <= segment_end) {
return true;
}
}
return false;
}
} // namespace } // namespace
// static // static
@ -231,12 +247,22 @@ void StackTrace::OutputToStreamWithPrefix(std::ostream* os,
SymbolMap map; SymbolMap map;
int module_id = 0; int module_id = 0;
for (const SymbolMap::Module& entry : map.GetModules()) { for (const SymbolMap::Module& module_entry : map.GetModules()) {
*os << "{{{module:" << module_id << ":" << entry.name // Don't emit information on modules that aren't useful for the actual
<< ":elf:" << entry.build_id << "}}}\n"; // stack trace, so as to reduce the load on the symbolizer and syslog.
bool should_emit_module = false;
for (size_t i = 0; i < count_ && !should_emit_module; ++i) {
should_emit_module = ModuleContainsFrameAddress(trace_[i], module_entry);
}
if (!should_emit_module) {
continue;
}
for (size_t i = 0; i < entry.segment_count; ++i) { *os << "{{{module:" << module_id << ":" << module_entry.name
const SymbolMap::Segment& segment = entry.segments[i]; << ":elf:" << module_entry.build_id << "}}}\n";
for (size_t i = 0; i < module_entry.segment_count; ++i) {
const SymbolMap::Segment& segment = module_entry.segments[i];
char permission_string[4] = {}; char permission_string[4] = {};
*os << "{{{mmap:" << segment.addr << ":0x" << std::hex << segment.size *os << "{{{mmap:" << segment.addr << ":0x" << std::hex << segment.size

View File

@ -109,16 +109,6 @@ struct FeatureEntry {
} }
}; };
// Some characters are not allowed to appear in feature names or the associated
// field trial names, as they are used as special characters for command-line
// serialization. This function checks that the strings are ASCII (since they
// are used in command-line API functions that require ASCII) and whether there
// are any reserved characters present, returning true if the string is valid.
// Only called in DCHECKs.
bool IsValidFeatureOrFieldTrialName(StringPiece name) {
return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
}
// Splits |text| into two parts by the |separator| where the first part will be // Splits |text| into two parts by the |separator| where the first part will be
// returned updated in |first| and the second part will be returned as |second|. // returned updated in |first| and the second part will be returned as |second|.
// This function returns false if there is more than one |separator| in |first|. // This function returns false if there is more than one |separator| in |first|.
@ -401,6 +391,11 @@ bool FeatureList::IsEnabled(const Feature& feature) {
return g_feature_list_instance->IsFeatureEnabled(feature); return g_feature_list_instance->IsFeatureEnabled(feature);
} }
// static
bool FeatureList::IsValidFeatureOrFieldTrialName(StringPiece name) {
return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
}
// static // static
absl::optional<bool> FeatureList::GetStateIfOverridden(const Feature& feature) { absl::optional<bool> FeatureList::GetStateIfOverridden(const Feature& feature) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()

View File

@ -384,6 +384,14 @@ class BASE_EXPORT FeatureList {
// struct, which is checked in builds with DCHECKs enabled. // struct, which is checked in builds with DCHECKs enabled.
static bool IsEnabled(const Feature& feature); static bool IsEnabled(const Feature& feature);
// Some characters are not allowed to appear in feature names or the
// associated field trial names, as they are used as special characters for
// command-line serialization. This function checks that the strings are ASCII
// (since they are used in command-line API functions that require ASCII) and
// whether there are any reserved characters present, returning true if the
// string is valid.
static bool IsValidFeatureOrFieldTrialName(StringPiece name);
// If the given |feature| is overridden, returns its enabled state; otherwise, // If the given |feature| is overridden, returns its enabled state; otherwise,
// returns an empty optional. Must only be called after the singleton instance // returns an empty optional. Must only be called after the singleton instance
// has been registered via SetInstance(). Additionally, a feature with a given // has been registered via SetInstance(). Additionally, a feature with a given

View File

@ -171,10 +171,10 @@ std::u16string FileVersionInfoWin::GetStringValue(const char16_t* name) const {
} }
base::Version FileVersionInfoWin::GetFileVersion() const { base::Version FileVersionInfoWin::GetFileVersion() const {
return base::Version({HIWORD(fixed_file_info_.dwFileVersionMS), return base::Version({HIWORD(fixed_file_info_->dwFileVersionMS),
LOWORD(fixed_file_info_.dwFileVersionMS), LOWORD(fixed_file_info_->dwFileVersionMS),
HIWORD(fixed_file_info_.dwFileVersionLS), HIWORD(fixed_file_info_->dwFileVersionLS),
LOWORD(fixed_file_info_.dwFileVersionLS)}); LOWORD(fixed_file_info_->dwFileVersionLS)});
} }
FileVersionInfoWin::FileVersionInfoWin(std::vector<uint8_t>&& data, FileVersionInfoWin::FileVersionInfoWin(std::vector<uint8_t>&& data,

View File

@ -16,6 +16,7 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/file_version_info.h" #include "base/file_version_info.h"
#include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/version.h" #include "base/version.h"
struct tagVS_FIXEDFILEINFO; struct tagVS_FIXEDFILEINFO;
@ -71,7 +72,7 @@ class BASE_EXPORT FileVersionInfoWin : public FileVersionInfo {
const WORD code_page_; const WORD code_page_;
// This is a reference for a portion of |data_|. // This is a reference for a portion of |data_|.
const VS_FIXEDFILEINFO& fixed_file_info_; const raw_ref<const VS_FIXEDFILEINFO> fixed_file_info_;
}; };
#endif // BASE_FILE_VERSION_INFO_WIN_H_ #endif // BASE_FILE_VERSION_INFO_WIN_H_

View File

@ -9,6 +9,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/memory/raw_ref.h"
#include "base/message_loop/message_pump_for_io.h" #include "base/message_loop/message_pump_for_io.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
@ -71,7 +72,7 @@ class FileDescriptorWatcher::Controller::Watcher
// WaitableEvent to signal to ensure that the Watcher is always destroyed // WaitableEvent to signal to ensure that the Watcher is always destroyed
// before the Controller. // before the Controller.
base::WaitableEvent& on_destroyed_; const raw_ref<base::WaitableEvent> on_destroyed_;
// Whether this Watcher is notified when |fd_| becomes readable or writable // Whether this Watcher is notified when |fd_| becomes readable or writable
// without blocking. // without blocking.
@ -109,7 +110,7 @@ FileDescriptorWatcher::Controller::Watcher::~Watcher() {
// Stop watching the descriptor before signalling |on_destroyed_|. // Stop watching the descriptor before signalling |on_destroyed_|.
CHECK(fd_watch_controller_.StopWatchingFileDescriptor()); CHECK(fd_watch_controller_.StopWatchingFileDescriptor());
on_destroyed_.Signal(); on_destroyed_->Signal();
} }
void FileDescriptorWatcher::Controller::Watcher::StartWatching() { void FileDescriptorWatcher::Controller::Watcher::StartWatching() {

View File

@ -132,7 +132,14 @@
// Macros for string literal initialization of FilePath::CharType[]. // Macros for string literal initialization of FilePath::CharType[].
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
#define FILE_PATH_LITERAL(x) L##x
// The `FILE_PATH_LITERAL_INTERNAL` indirection allows `FILE_PATH_LITERAL` to
// work correctly with macro parameters, for example
// `FILE_PATH_LITERAL(TEST_FILE)` where `TEST_FILE` is a macro #defined as
// "TestFile".
#define FILE_PATH_LITERAL_INTERNAL(x) L##x
#define FILE_PATH_LITERAL(x) FILE_PATH_LITERAL_INTERNAL(x)
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
#define FILE_PATH_LITERAL(x) x #define FILE_PATH_LITERAL(x) x
#endif // BUILDFLAG(IS_WIN) #endif // BUILDFLAG(IS_WIN)

View File

@ -21,7 +21,8 @@ FilePathWatcher::~FilePathWatcher() {
// static // static
bool FilePathWatcher::RecursiveWatchAvailable() { bool FilePathWatcher::RecursiveWatchAvailable() {
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \ #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \
BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_AIX) BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_AIX) || \
BUILDFLAG(IS_FUCHSIA)
return true; return true;
#else #else
// FSEvents isn't available on iOS. // FSEvents isn't available on iOS.

View File

@ -119,6 +119,13 @@ class InotifyReader {
#else #else
using Watch = int; using Watch = int;
#endif #endif
// Record of watchers tracked for watch descriptors.
struct WatcherEntry {
scoped_refptr<SequencedTaskRunner> task_runner;
WeakPtr<FilePathWatcherImpl> watcher;
};
static constexpr Watch kInvalidWatch = static_cast<Watch>(-1); static constexpr Watch kInvalidWatch = static_cast<Watch>(-1);
static constexpr Watch kWatchLimitExceeded = static_cast<Watch>(-2); static constexpr Watch kWatchLimitExceeded = static_cast<Watch>(-2);
@ -141,12 +148,6 @@ class InotifyReader {
private: private:
friend struct LazyInstanceTraitsBase<InotifyReader>; friend struct LazyInstanceTraitsBase<InotifyReader>;
// Record of watchers tracked for watch descriptors.
struct WatcherEntry {
scoped_refptr<SequencedTaskRunner> task_runner;
WeakPtr<FilePathWatcherImpl> watcher;
};
InotifyReader(); InotifyReader();
// There is no destructor because |g_inotify_reader| is a // There is no destructor because |g_inotify_reader| is a
// base::LazyInstace::Leaky object. Having a destructor causes build // base::LazyInstace::Leaky object. Having a destructor causes build
@ -197,11 +198,8 @@ class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
// would exceed the limit if adding one more. // would exceed the limit if adding one more.
bool WouldExceedWatchLimit() const; bool WouldExceedWatchLimit() const;
// Returns the task runner to be used with this. // Returns a WatcherEntry for this, must be called on the original sequence.
scoped_refptr<SequencedTaskRunner> GetTaskRunner() const; InotifyReader::WatcherEntry GetWatcherEntry();
// Returns the WeakPtr of this, must be called on the original sequence.
WeakPtr<FilePathWatcherImpl> GetWeakPtr() const;
private: private:
// Start watching |path| for changes and notify |delegate| on each change. // Start watching |path| for changes and notify |delegate| on each change.
@ -365,8 +363,7 @@ InotifyReader::Watch InotifyReader::AddWatch(const FilePath& path,
return kInvalidWatch; return kInvalidWatch;
const Watch watch = static_cast<Watch>(watch_int); const Watch watch = static_cast<Watch>(watch_int);
watchers_[watch].emplace(std::make_pair( watchers_[watch].emplace(std::make_pair(watcher, watcher->GetWatcherEntry()));
watcher, WatcherEntry{watcher->GetTaskRunner(), watcher->GetWeakPtr()}));
return watch; return watch;
} }
@ -557,14 +554,9 @@ bool FilePathWatcherImpl::WouldExceedWatchLimit() const {
return number_of_inotify_watches >= GetMaxNumberOfInotifyWatches(); return number_of_inotify_watches >= GetMaxNumberOfInotifyWatches();
} }
scoped_refptr<SequencedTaskRunner> FilePathWatcherImpl::GetTaskRunner() const { InotifyReader::WatcherEntry FilePathWatcherImpl::GetWatcherEntry() {
DCHECK(task_runner()->RunsTasksInCurrentSequence()); DCHECK(task_runner()->RunsTasksInCurrentSequence());
return task_runner(); return {task_runner(), weak_factory_.GetWeakPtr()};
}
WeakPtr<FilePathWatcherImpl> FilePathWatcherImpl::GetWeakPtr() const {
DCHECK(task_runner()->RunsTasksInCurrentSequence());
return weak_factory_.GetWeakPtr();
} }
bool FilePathWatcherImpl::Watch(const FilePath& path, bool FilePathWatcherImpl::Watch(const FilePath& path,

View File

@ -367,6 +367,12 @@ BASE_EXPORT ScopedFILE CreateAndOpenTemporaryStreamInDir(const FilePath& dir,
// the format of prefixyyyy. // the format of prefixyyyy.
// NOTE: prefix is ignored in the POSIX implementation. // NOTE: prefix is ignored in the POSIX implementation.
// If success, return true and output the full path of the directory created. // If success, return true and output the full path of the directory created.
//
// For Windows, this directory is usually created in a secure location under
// %ProgramFiles% if the caller is admin. This is because the default %TEMP%
// folder for Windows is insecure, since low privilege users can get the path of
// folders under %TEMP% after creation and are able to create subfolders and
// files within these folders which can lead to privilege escalation.
BASE_EXPORT bool CreateNewTempDirectory(const FilePath::StringType& prefix, BASE_EXPORT bool CreateNewTempDirectory(const FilePath::StringType& prefix,
FilePath* new_temp_path); FilePath* new_temp_path);
@ -604,26 +610,6 @@ BASE_EXPORT bool VerifyPathControlledByAdmin(const base::FilePath& path);
// the directory |path|, in the number of FilePath::CharType, or -1 on failure. // the directory |path|, in the number of FilePath::CharType, or -1 on failure.
BASE_EXPORT int GetMaximumPathComponentLength(const base::FilePath& path); BASE_EXPORT int GetMaximumPathComponentLength(const base::FilePath& path);
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_AIX)
// Broad categories of file systems as returned by statfs() on Linux.
enum FileSystemType {
FILE_SYSTEM_UNKNOWN, // statfs failed.
FILE_SYSTEM_0, // statfs.f_type == 0 means unknown, may indicate AFS.
FILE_SYSTEM_ORDINARY, // on-disk filesystem like ext2
FILE_SYSTEM_NFS,
FILE_SYSTEM_SMB,
FILE_SYSTEM_CODA,
FILE_SYSTEM_MEMORY, // in-memory file system
FILE_SYSTEM_CGROUP, // cgroup control.
FILE_SYSTEM_OTHER, // any other value.
FILE_SYSTEM_TYPE_COUNT
};
// Attempts determine the FileSystemType for |path|.
// Returns false if |path| doesn't exist.
BASE_EXPORT bool GetFileSystemType(const FilePath& path, FileSystemType* type);
#endif
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
// Get a temporary directory for shared memory files. The directory may depend // Get a temporary directory for shared memory files. The directory may depend
// on whether the destination is intended for executable files, which in turn // on whether the destination is intended for executable files, which in turn

View File

@ -1,63 +0,0 @@
// Copyright 2011 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/files/file_util.h"
#include <errno.h>
#include <linux/magic.h>
#include <sys/vfs.h>
#include "base/files/file_path.h"
namespace base {
bool GetFileSystemType(const FilePath& path, FileSystemType* type) {
struct statfs statfs_buf;
if (statfs(path.value().c_str(), &statfs_buf) < 0) {
if (errno == ENOENT)
return false;
*type = FILE_SYSTEM_UNKNOWN;
return true;
}
// Not all possible |statfs_buf.f_type| values are in linux/magic.h.
// Missing values are copied from the statfs man page.
switch (static_cast<int>(statfs_buf.f_type)) {
case 0:
*type = FILE_SYSTEM_0;
break;
case EXT2_SUPER_MAGIC: // Also ext3 and ext4
case MSDOS_SUPER_MAGIC:
case REISERFS_SUPER_MAGIC:
case static_cast<int>(BTRFS_SUPER_MAGIC):
case 0x5346544E: // NTFS
case 0x58465342: // XFS
case 0x3153464A: // JFS
*type = FILE_SYSTEM_ORDINARY;
break;
case NFS_SUPER_MAGIC:
*type = FILE_SYSTEM_NFS;
break;
case SMB_SUPER_MAGIC:
case static_cast<int>(0xFF534D42): // CIFS
*type = FILE_SYSTEM_SMB;
break;
case CODA_SUPER_MAGIC:
*type = FILE_SYSTEM_CODA;
break;
case static_cast<int>(HUGETLBFS_MAGIC):
case static_cast<int>(RAMFS_MAGIC):
case TMPFS_MAGIC:
*type = FILE_SYSTEM_MEMORY;
break;
case CGROUP_SUPER_MAGIC:
*type = FILE_SYSTEM_CGROUP;
break;
default:
*type = FILE_SYSTEM_OTHER;
}
return true;
}
} // namespace base

View File

@ -30,6 +30,7 @@
#include "base/location.h" #include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/path_service.h"
#include "base/process/process_handle.h" #include "base/process/process_handle.h"
#include "base/rand_util.h" #include "base/rand_util.h"
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
@ -55,6 +56,7 @@ namespace {
const DWORD kFileShareAll = const DWORD kFileShareAll =
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
const wchar_t kDefaultTempDirPrefix[] = L"ChromiumTemp";
// Returns the Win32 last error code or ERROR_SUCCESS if the last error code is // Returns the Win32 last error code or ERROR_SUCCESS if the last error code is
// ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND. This is useful in cases where // ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND. This is useful in cases where
@ -620,15 +622,33 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
return false; return false;
} }
// The directory is created under %ProgramFiles% for security reasons if the
// caller is admin. Since only admin can write to %ProgramFiles%, this avoids
// attacks from lower privilege processes.
//
// If unable to create a dir under %ProgramFiles%, the dir is created under
// %TEMP%. The reasons for not being able to create a dir under %ProgramFiles%
// could be because we are unable to resolve `DIR_PROGRAM_FILES`, say due to
// registry redirection, or unable to create a directory due to %ProgramFiles%
// being read-only or having atypical ACLs.
bool CreateNewTempDirectory(const FilePath::StringType& prefix, bool CreateNewTempDirectory(const FilePath::StringType& prefix,
FilePath* new_temp_path) { FilePath* new_temp_path) {
ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK); ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
FilePath system_temp_dir; DCHECK(new_temp_path);
if (!GetTempDir(&system_temp_dir))
FilePath parent_dir;
if (::IsUserAnAdmin() && PathService::Get(DIR_PROGRAM_FILES, &parent_dir) &&
CreateTemporaryDirInDir(parent_dir,
prefix.empty() ? kDefaultTempDirPrefix : prefix,
new_temp_path)) {
return true;
}
if (!GetTempDir(&parent_dir))
return false; return false;
return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path); return CreateTemporaryDirInDir(parent_dir, prefix, new_temp_path);
} }
bool CreateDirectoryAndGetError(const FilePath& full_path, bool CreateDirectoryAndGetError(const FilePath& full_path,

View File

@ -29,7 +29,7 @@ std::array<std::atomic_bool, kMaxTrackedFds> g_is_fd_owned;
NOINLINE void CrashOnFdOwnershipViolation() { NOINLINE void CrashOnFdOwnershipViolation() {
RAW_LOG(ERROR, "Crashing due to FD ownership violation:\n"); RAW_LOG(ERROR, "Crashing due to FD ownership violation:\n");
base::debug::StackTrace().Print(); base::debug::StackTrace().Print();
IMMEDIATE_CRASH(); base::ImmediateCrash();
} }
bool CanTrack(int fd) { bool CanTrack(int fd) {

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