chromium/base/allocator/partition_allocator/partition_alloc.gni

# 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.

import("//build_overrides/partition_alloc.gni")

# PartitionAlloc have limited support for MSVC's cl.exe compiler. It can only
# access the generate "buildflags" and the "raw_ptr" definitions implemented
# with RawPtrNoOpImpl. Everything else is considered not supported.
#
# Since there are no other good ways to detect MSVC's cl.exe, we are reusing the
# same definition used by Chrome in //base/BUILD.gn. See
# https://crbug.com/988071.
is_clang_or_gcc = is_clang || !is_win

# Whether 64-bit pointers are used.
# A static_assert in partition_alloc_config.h verifies that.
if (is_nacl) {
  # NaCl targets don't use 64-bit pointers.
  has_64_bit_pointers = false
} else if (current_cpu == "x64" || current_cpu == "arm64" ||
           current_cpu == "loong64" || current_cpu == "riscv64") {
  has_64_bit_pointers = true
} else if (current_cpu == "x86" || current_cpu == "arm") {
  has_64_bit_pointers = false
} else {
  assert(false, "Unknown CPU: $current_cpu")
}

# Increases the size of the empty slot span ring.
use_large_empty_slot_span_ring = is_mac

has_memory_tagging =
    current_cpu == "arm64" && is_clang && !is_asan && (is_linux || is_android)

declare_args() {
  # Causes all the allocations to be routed via allocator_shim.cc. Usually,
  # the allocator shim will, in turn, route them to PartitionAlloc, but
  # other allocators are also supported by the allocator shim.
  use_allocator_shim = use_allocator_shim_default && is_clang_or_gcc

  # 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_partition_alloc_as_malloc|.
  #
  # N.B. generally, embedders should look at this GN arg and at the
  # corresponding buildflag to determine whether to interact with PA
  # source at all (pulling the component in via GN, including headers,
  # etc.). There is nothing stopping a lazy embedder from ignoring this
  # and unconditionally using PA, but such a setup is inadvisable.
  #
  # In Chromium, this is set true, except:
  #
  # 1.  On Cronet bots, because Cronet doesn't use PartitionAlloc at all,
  #     and doesn't wish to incur the library size increase (crbug.com/674570).
  # 2.  On NaCl (through this declaration), where PartitionAlloc doesn't
  #     build at all.
  use_partition_alloc = !is_nacl && is_clang_or_gcc
}

if (!is_clang_or_gcc) {
  assert(!use_partition_alloc,
         "PartitionAlloc's allocator does not support this compiler")
  assert(!use_allocator_shim,
         "PartitionAlloc's allocator shim does not support this compiler")
}

if (is_nacl) {
  assert(!use_partition_alloc, "PartitionAlloc doesn't build on NaCl")
}

declare_args() {
  # PartitionAlloc-Everywhere (PA-E). Causes allocator_shim.cc to route
  # calls to PartitionAlloc, rather than some other platform allocator.
  use_partition_alloc_as_malloc = use_partition_alloc && use_allocator_shim &&
                                  use_partition_alloc_as_malloc_default
}

declare_args() {
  # Whether PartitionAlloc dispatch can be replaced with another dispatch with
  # some more safety checks at runtime or not.  When true, the allocator shim
  # provides an extended API to swap PartitionAlloc.
  # TODO(https://crbug.com/351974425): Enable this when `use_partition_alloc_as_malloc` is true.
  enable_allocator_shim_partition_alloc_dispatch_with_advanced_checks_support =
      false
}

assert(
    !enable_allocator_shim_partition_alloc_dispatch_with_advanced_checks_support || use_partition_alloc_as_malloc,
    "PartitionAlloc with advanced checks requires PartitionAlloc itself.")

assert(!use_allocator_shim || (is_android || is_apple || is_chromeos ||
                                   is_fuchsia || is_linux || is_win),
       "The allocator shim does not (yet) support the platform.")

if (use_allocator_shim && is_win) {
  # It's hard to override CRT's malloc family in every case in the component
  # build, and it's very easy to override it partially and to be inconsistent
  # among allocations and deallocations. Then, we'll crash when PA deallocates
  # a memory region allocated by the CRT's malloc or vice versa.
  # Since PartitionAlloc depends on libc++, it is difficult to link libc++.dll
  # with PartitionAlloc to replace its allocator with PartitionAlloc.
  # If using libcxx_is_shared=true,
  # a. since inline methods or inline functions defined in some libc++ headers,
  #    e.g. vector, use new, malloc(), and so on, the memory allocation will
  #    be done inside a client code.
  # b. on the other hand, libc++.dll deallocates the memory allocated by the
  #    inline methods or inline functions. It will not be run inside the client
  #    code.
  # So a.'s allocation is done by PartitionAlloc, but b.'s deallocation is
  # done by system allocator. This will cause heap check failure (WinHeap
  # doesn't know PartitionAlloc) and crash.
  # If libcxx_is_shared=false, libc++ is a static library. All libc++ code
  # will be run inside the client. The above issue will disappear.
  assert(
      !is_component_build || (!libcxx_is_shared && !is_debug),
      "The allocator shim for the Windows component build needs !libcxx_is_shared && !is_debug.")
}

declare_args() {
  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.
  # TODO(crbug.com/350104111): Fix ios-simulator failures to remove `!is_ios`.
  glue_core_pools = use_partition_alloc_as_malloc && !is_ios

  # Introduces pointer compression support in PA. These are 4-byte
  # pointers that can point within the core pools (regular and BRP).
  #
  # This is 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_pointer_compression_support = false

  # Enables a bounds check when two pointers (at least one being raw_ptr) are
  # subtracted (if supported by the underlying implementation).
  enable_pointer_subtraction_check = false

  # Enables a compile-time check that all raw_ptrs to which arithmetic
  # operations are to be applied are annotated with the AllowPtrArithmetic
  # trait,
  enable_pointer_arithmetic_trait_check = true

  # Forwards all the allocation/freeing calls in shim (e.g. operator new)
  # through malloc. Useful for using with tools that intercept malloc, e.g.
  # heaptrack.
  forward_through_malloc = false
}

declare_args() {
  # Build support for Use-after-Free protection via BackupRefPtr (BRP),
  # making the raw_ptr<T> implementation to RawPtrBackupRefImpl if active.
  #
  # 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.
  #
  # Note that |enable_backup_ref_ptr_support = true| doesn't necessarily enable
  # BRP protection. It'll be enabled only for partition created with
  # partition_alloc::PartitionOptions::kEnabled.
  enable_backup_ref_ptr_support =
      use_partition_alloc && enable_backup_ref_ptr_support_default

  # 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.
  force_enable_raw_ptr_exclusion = false
}

assert(!enable_pointer_compression_support || glue_core_pools,
       "Pointer compression relies on core pools being contiguous.")

declare_args() {
  # We want to use RawPtrBackupRefImpl as the raw_ptr<> implementation
  # iff BRP support is enabled. However, for purpose of performance
  # investigations we want to be able to control each separately.
  #
  # TEST ONLY! Don't touch unless you think you know what you're doing. Play
  # with enable_backup_ref_ptr_support instead.
  use_raw_ptr_backup_ref_impl = enable_backup_ref_ptr_support

  # Make explicit calls to ASAN at runtime, e.g. to mark quarrantined memory
  # as poisoned. Allows ASAN to tell if a particular memory error is protected
  # by BRP in its reports.
  #
  # The implementation of ASan BRP is purpose-built to inspect Chromium
  # internals and is entangled with `//base` s.t. it cannot be used
  # outside of Chromium.
  use_asan_backup_ref_ptr =
      build_with_chromium && is_asan &&
      (is_win || is_android || is_linux || is_mac || is_chromeos)

  # Use probe-on-destruct unowned ptr detection with ASAN.
  use_raw_ptr_asan_unowned_impl = false
}

# Use the version of raw_ptr<T> that allows the embedder to implement custom
# logic.
use_raw_ptr_hookable_impl = use_asan_backup_ref_ptr

declare_args() {
  # - enable_backup_ref_ptr_slow_checks: enable additional safety checks that
  #   are too expensive to have on by default.
  # - enable_dangling_raw_ptr_checks: enable checking raw_ptr do not become
  #   dangling during their lifetime.
  # - backup_ref_ptr_poison_oob_ptr: poison out-of-bounds (OOB) pointers to
  #   generate an exception in the event that an OOB pointer is dereferenced.
  # - enable_backup_ref_ptr_instance_tracer: use a global table to track all
  #   live raw_ptr/raw_ref instances to help debug dangling pointers at test
  #   end.

  enable_backup_ref_ptr_slow_checks =
      enable_backup_ref_ptr_slow_checks_default && enable_backup_ref_ptr_support

  # Enable the feature flag required to activate backup ref pointers. That is to
  # say `PartitionAllocBackupRefPtr`.
  #
  # This is meant to be used primarily on bots. It is much easier to override
  # the feature flags using a binary flag instead of updating multiple bots's
  # scripts to pass command line arguments.
  #
  # TODO(328104161): Remove this flag.
  enable_backup_ref_ptr_feature_flag = false

  # Build support for Dangling Ptr Detection (DPD) via BackupRefPtr (BRP),
  # making the raw_ptr<T> implementation to RawPtrBackupRefImpl if active.
  enable_dangling_raw_ptr_checks =
      enable_dangling_raw_ptr_checks_default && enable_backup_ref_ptr_support &&
      use_raw_ptr_backup_ref_impl

  enable_backup_ref_ptr_instance_tracer = false

  backup_ref_ptr_extra_oob_checks =
      enable_backup_ref_ptr_support && use_raw_ptr_backup_ref_impl
}

declare_args() {
  # Enable the feature flag required to check for dangling pointers. That is to
  # say `PartitionAllocDanglingPtr`.
  #
  # This is meant to be used primarily on bots. It is much easier to override
  # the feature flags using a binary flag instead of updating multiple bots's
  # scripts to pass command line arguments.
  #
  # TODO(328104161): Remove this flag.
  enable_dangling_raw_ptr_feature_flag = enable_dangling_raw_ptr_checks
}

declare_args() {
  backup_ref_ptr_poison_oob_ptr =
      false && backup_ref_ptr_extra_oob_checks && has_64_bit_pointers
}

declare_args() {
  # Shadow metadata is still under development and only supports Linux
  # for now.
  enable_shadow_metadata = false
}

declare_args() {
  # Use full MTE protection available by changing the feature flag default
  # values. So sync mode on all processes. Also disables permissive MTE.
  #
  # This is meant to be used primarily on bots. It is much easier to override
  # the feature flags using a binary flag instead of updating multiple bots's
  # scripts to pass command line arguments.
  use_full_mte = false
}

stack_scan_supported =
    current_cpu == "x64" || current_cpu == "x86" || current_cpu == "arm" ||
    current_cpu == "arm64" || current_cpu == "riscv64"

# We want to provide assertions that guard against inconsistent build
# args, but there is no point in having them fire if we're not building
# PartitionAlloc at all. If `use_partition_alloc` is false, we jam all
# related args to `false`.
#
# Do not clear the following, as they can function outside of PartitionAlloc
# - has_64_bit_pointers
# - has_memory_tagging
if (!use_partition_alloc ||
    (defined(toolchain_allows_use_partition_alloc_as_malloc) &&
     !toolchain_allows_use_partition_alloc_as_malloc)) {
  use_partition_alloc_as_malloc = false
  glue_core_pools = false
  enable_backup_ref_ptr_support = false
  use_raw_ptr_backup_ref_impl = false
  use_asan_backup_ref_ptr = false
  use_raw_ptr_asan_unowned_impl = false
  use_raw_ptr_hookable_impl = false
  enable_backup_ref_ptr_slow_checks = false
  enable_dangling_raw_ptr_checks = false
  enable_dangling_raw_ptr_feature_flag = false
  enable_pointer_subtraction_check = false
  backup_ref_ptr_poison_oob_ptr = false
  backup_ref_ptr_extra_oob_checks = false
  enable_backup_ref_ptr_instance_tracer = false
  use_full_mte = false
}

# Disable |use_full_mte| if memory tagging is not available. This is for targets that run as part the build process.
if (!has_memory_tagging) {
  use_full_mte = false
}

# use_raw_ptr_backup_ref_impl can only be used if
# enable_backup_ref_ptr_support is true.
assert(enable_backup_ref_ptr_support || !use_raw_ptr_backup_ref_impl,
       "Can't use RawPtrBackupRefImpl if BRP isn't enabled at all")

# enable_backup_ref_ptr_slow_checks can only be used if
# enable_backup_ref_ptr_support is true.
assert(enable_backup_ref_ptr_support || !enable_backup_ref_ptr_slow_checks,
       "Can't enable additional BRP checks if it isn't enabled at all")

# enable_dangling_raw_ptr_checks can only be used if
# enable_backup_ref_ptr_support & use_raw_ptr_backup_ref_impl are true.
assert((enable_backup_ref_ptr_support && use_raw_ptr_backup_ref_impl) ||
           !enable_dangling_raw_ptr_checks,
       "Can't enable dangling raw_ptr checks if BRP isn't enabled and used")

# It's meaningless to force on DPD (e.g. on bots) if the support isn't compiled
# in.
assert(enable_dangling_raw_ptr_checks || !enable_dangling_raw_ptr_feature_flag,
       "Meaningless to enable DPD without it compiled.")

# To enable extra OOB checks for BRP, the underlying feature must be
# enabled, too.
assert((enable_backup_ref_ptr_support && use_raw_ptr_backup_ref_impl) ||
           !backup_ref_ptr_extra_oob_checks,
       "Can't enable extra OOB checks if BRP isn't enabled and used")

# To poison OOB pointers for BRP, the underlying feature must be
# enabled, too.
assert(backup_ref_ptr_extra_oob_checks || !backup_ref_ptr_poison_oob_ptr,
       "Can't enable poisoning for OOB pointers if OOB checks aren't enabled " +
           "at all")
assert(has_64_bit_pointers || !backup_ref_ptr_poison_oob_ptr,
       "Can't enable poisoning for OOB pointers if pointers are only 32-bit")

# AsanBackupRefPtr and AsanUnownedPtr are mutually exclusive variants of
# raw_ptr.
assert(
    !use_raw_ptr_asan_unowned_impl || !use_asan_backup_ref_ptr,
    "Both AsanUnownedPtr and AsanBackupRefPtr can't be enabled at the same " +
        "time")

# BackupRefPtr and AsanBackupRefPtr are mutually exclusive variants of raw_ptr.
assert(
    !enable_backup_ref_ptr_support || !use_asan_backup_ref_ptr,
    "Both BackupRefPtr and AsanBackupRefPtr can't be enabled at the same time")

# BackupRefPtr and AsanUnownedPtr are mutually exclusive variants of raw_ptr.
assert(!enable_backup_ref_ptr_support || !use_raw_ptr_asan_unowned_impl,
       "Both BackupRefPtr and AsanUnownedPtr can't be enabled at the same time")

# RawPtrHookableImpl and BackupRefPtr are mutually exclusive variants of
# raw_ptr.
assert(
    !use_raw_ptr_hookable_impl || !enable_backup_ref_ptr_support,
    "Both RawPtrHookableImpl and BackupRefPtr can't be enabled at the same " +
        "time")

# RawPtrHookableImpl and AsanUnownedPtr are mutually exclusive variants of
# raw_ptr.
assert(
    !use_raw_ptr_hookable_impl || !use_raw_ptr_asan_unowned_impl,
    "Both RawPtrHookableImpl and AsanUnownedPtr can't be enabled at the same " +
        "time")

assert(!use_asan_backup_ref_ptr || is_asan,
       "AsanBackupRefPtr requires AddressSanitizer")

assert(!use_raw_ptr_asan_unowned_impl || is_asan,
       "AsanUnownedPtr requires AddressSanitizer")

# AsanBackupRefPtr is not supported outside Chromium. The implementation is
# entangled with `//base`. The code is only physically located with the rest of
# `raw_ptr` to keep it together.
assert(build_with_chromium || !use_asan_backup_ref_ptr,
       "AsanBackupRefPtr is not supported outside Chromium")

assert(!use_asan_backup_ref_ptr || use_raw_ptr_hookable_impl,
       "AsanBackupRefPtr requires RawPtrHookableImpl")

# pkeys support is explicitly disabled in all Cronet builds, as some test
# dependencies that use partition_allocator are compiled in AOSP against a
# version of glibc that does not include pkeys syscall numbers.
is_pkeys_available =
    (is_linux || is_chromeos) && current_cpu == "x64" && !is_cronet_build
declare_args() {
  enable_pkeys = is_pkeys_available
}
assert(!enable_pkeys || is_pkeys_available,
       "Pkeys are only supported on x64 linux and ChromeOS")

# Some implementations of raw_ptr<>, like BackupRefPtr, require zeroing when
# constructing, destructing or moving out of a pointer. When using these
# implementations, raw_ptrs<> will be always be zeroed, no matter what
# GN args or flags are present.
#
# Other implementations of raw_ptr<>, like NoOpImpl, don't require zeroing
# and do not do so by default. This can lead to subtle bugs when testing
# against one of the zeroing impls and then deploying on a platform that is
# using a non-zeroing implementation. Setting the following GN args to
# true triggers zeroing even for implementations that don't require it.
# This provides consistency with the other impls. This is the recommended
# setting.
#
# Setting these to false will make raw_ptr<> behave more like raw C++ pointer
# `T*`, making NoOpImpl act like an actual no-op, so use it if you're worried
# about performance of your project. Use at your own risk, as it's unsupported
# and untested within Chromium.
#
# Even when these are set to true, the raw_ptr trait AllowUninitialized
# provides a finer-grained mechanism for opting out of initialization on a
# pointer by pointer basis when using a non-zeroing implementation.
#
# Caveat: _zero_on_move and _on_destruct will prevent the type from being
# trivially copyable, _zero_on_construct and _on_destruct will prevent the
# type from being trivially default constructible.
declare_args() {
  raw_ptr_zero_on_construct = raw_ptr_zero_on_construct_default
  raw_ptr_zero_on_move = raw_ptr_zero_on_move_default
  raw_ptr_zero_on_destruct = raw_ptr_zero_on_destruct_default
}

declare_args() {
  # Assert that PartitionAlloc and MiraclePtr run on C++20 when set to true.
  # Embedders may opt-out of using C++ 20 build.
  assert_cpp20 = assert_cpp20_default
}