// 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. #ifndef BASE_FUNCTIONAL_BIND_INTERNAL_H_ #define BASE_FUNCTIONAL_BIND_INTERNAL_H_ #include #include #include #include #include #include #include #include "base/check.h" #include "base/compiler_specific.h" #include "base/functional/callback_internal.h" #include "base/functional/unretained_traits.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr_asan_bound_arg_tracker.h" #include "base/memory/raw_ref.h" #include "base/memory/raw_scoped_refptr_mismatch_checker.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" #include "base/types/always_false.h" #include "base/types/is_complete.h" #include "base/types/is_instantiation.h" #include "base/types/to_address.h" #include "build/build_config.h" #include "partition_alloc/partition_alloc_buildflags.h" #include "partition_alloc/partition_alloc_config.h" #include "third_party/abseil-cpp/absl/functional/function_ref.h" // See docs/callback.md for user documentation. // // Concepts: // Functor -- A movable type representing something that should be called. // All function pointers and `Callback<>` are functors even if the // invocation syntax differs. // RunType -- A function type (as opposed to function _pointer_ type) for // a `Callback<>::Run()`. Usually just a convenience typedef. // (Bound)Args -- A set of types that stores the arguments. // // Types: // `ForceVoidReturn<>` -- Helper class for translating function signatures to // equivalent forms with a `void` return type. // `FunctorTraits<>` -- Type traits used to determine the correct RunType and // invocation manner for a Functor. This is where // function signature adapters are applied. // `StorageTraits<>` -- Type traits that determine how a bound argument is // stored in `BindState<>`. // `InvokeHelper<>` -- Takes a Functor + arguments and actually invokes it. // Handles the differing syntaxes needed for `WeakPtr<>` // support. This is separate from `Invoker<>` to avoid // creating multiple versions of `Invoker<>`. // `Invoker<>` -- Unwraps the curried parameters and executes the Functor. // `BindState<>` -- Stores the curried parameters, and is the main entry point // into the `Bind()` system. #if BUILDFLAG(IS_WIN) namespace Microsoft { namespace WRL { template class ComPtr; } // namespace WRL } // namespace Microsoft #endif namespace base { template struct IsWeakReceiver; template struct BindUnwrapTraits; template struct CallbackCancellationTraits; template class FunctionRef; // A tag type to return when `Bind()` calls fail. In this case we intentionally // don't return `void`, since that would produce spurious errors like "variable // has incomplete type 'void'" when assigning the result of // `Bind{Once,Repeating}()` to an `auto`. struct BindFailedCheckPreviousErrors {}; namespace unretained_traits { // `UnretainedWrapper` will check and report if pointer is dangling upon // invocation. struct MayNotDangle {}; // `UnretainedWrapper` won't check if pointer is dangling upon invocation. For // extra safety, the receiver must be of type `MayBeDangling<>`. struct MayDangle {}; // `UnretainedWrapper` won't check if pointer is dangling upon invocation. The // receiver doesn't have to be a `raw_ptr<>`. This is just a temporary state, to // allow dangling pointers that would otherwise crash if `MayNotDangle` was // used. It should be replaced ASAP with `MayNotDangle` (after fixing the // dangling pointers) or with `MayDangle` if there is really no other way (after // making receivers `MayBeDangling<>`). struct MayDangleUntriaged {}; } // namespace unretained_traits namespace internal { template class UnretainedWrapper { // Note that if `PtrTraits` already includes `MayDangle`, `DanglingRawPtrType` // will be identical to `raw_ptr`. using DanglingRawPtrType = MayBeDangling; public: // We want the getter type to match the receiver parameter that it is passed // into, to minimize `raw_ptr` <-> `T*` conversions. We also would like to // match `StorageType`, but sometimes we can't have both, as shown in // https://docs.google.com/document/d/1dLM34aKqbNBfRdOYxxV_T-zQU4J5wjmXwIBJZr7JvZM/edit // When we can't have both, prefer the former, mostly because // `GetPtrType`=`raw_ptr` would break if e.g. `UnretainedWrapper()` is // constructed using `char*`, but the receiver is of type `std::string&`. // This is enforced by `static_assert()`s in `ParamCanBeBound`. using GetPtrType = std::conditional_t< raw_ptr_traits::IsSupportedType::value && std::same_as, DanglingRawPtrType, T*>; // Raw pointer makes sense only if there are no `PtrTrait`s. If there are, // it means that a `raw_ptr` is being passed, so use the ctors below instead. explicit UnretainedWrapper(T* o) requires(PtrTraits == RawPtrTraits::kEmpty) : ptr_(o) { VerifyPreconditions(); } explicit UnretainedWrapper(const raw_ptr& o) requires(raw_ptr_traits::IsSupportedType::value) : ptr_(o) { VerifyPreconditions(); } explicit UnretainedWrapper(raw_ptr&& o) requires(raw_ptr_traits::IsSupportedType::value) : ptr_(std::move(o)) { VerifyPreconditions(); } GetPtrType get() const { return GetInternal(ptr_); } // True if this type is valid. When this is false, a `static_assert` will have // been fired explaining why. static constexpr bool value = SupportsUnretained; private: // `ptr_` is either a `raw_ptr` or a regular C++ pointer. template requires std::same_as static GetPtrType GetInternal(U* ptr) { return ptr; } template requires std::same_as static GetPtrType GetInternal(const raw_ptr& ptr) { if constexpr (std::same_as) { ptr.ReportIfDangling(); } return ptr; } // `Unretained()` arguments often dangle by design (a common design pattern // is to manage an object's lifetime inside the callback itself, using // stateful information), so disable direct dangling pointer detection // of `ptr_`. // // If the callback is invoked, dangling pointer detection will be triggered // before invoking the bound functor (unless stated otherwise, see // `UnsafeDangling()` and `UnsafeDanglingUntriaged()`), when retrieving the // pointer value via `get()` above. using StorageType = std::conditional_t::value, DanglingRawPtrType, T*>; // Avoid converting between different `raw_ptr` types when calling `get()`. // It is allowable to convert `raw_ptr` -> `T*`, but not in the other // direction. See the comment by `GetPtrType` describing for more details. static_assert(std::is_pointer_v || std::same_as); // Forces `value` to be materialized, performing a compile-time check of the // preconditions if it hasn't already occurred. This is called from every // constructor so the wrappers in bind.h don't have to each check it, and so // no one can go around them and construct this underlying type directly. static constexpr void VerifyPreconditions() { // Using `static_assert(value);` here would work but fire an extra error. std::ignore = value; } StorageType ptr_; }; // Storage type for `std::reference_wrapper` so `BindState` can internally store // unprotected references using `raw_ref`. // // `std::reference_wrapper` and `T&` do not work, since the reference // lifetime is not safely protected by MiraclePtr. // // `UnretainedWrapper` and `raw_ptr` do not work, since `BindUnwrapTraits` // would try to pass by `T*` rather than `T&`. template class UnretainedRefWrapper { public: // Raw reference makes sense only if there are no `PtrTrait`s. If there are, // it means that a `raw_ref` is being passed, so use the ctors below instead. explicit UnretainedRefWrapper(T& o) requires(PtrTraits == RawPtrTraits::kEmpty) : ref_(o) { VerifyPreconditions(); } explicit UnretainedRefWrapper(const raw_ref& o) requires(raw_ptr_traits::IsSupportedType::value) : ref_(o) { VerifyPreconditions(); } explicit UnretainedRefWrapper(raw_ref&& o) requires(raw_ptr_traits::IsSupportedType::value) : ref_(std::move(o)) { VerifyPreconditions(); } T& get() const { return GetInternal(ref_); } // See comments in `UnretainedWrapper` regarding this and // `VerifyPreconditions()`. static constexpr bool value = SupportsUnretained; private: // `ref_` is either a `raw_ref` or a regular C++ reference. template requires std::same_as static T& GetInternal(U& ref) { return ref; } template requires std::same_as static T& GetInternal(const raw_ref& ref) { // The ultimate goal is to crash when a callback is invoked with a // dangling pointer. This is checked here. For now, it is configured to // either crash, DumpWithoutCrashing or be ignored. This depends on the // `PartitionAllocUnretainedDanglingPtr` feature. if constexpr (std::is_same_v) { ref.ReportIfDangling(); } // We can't use `operator*` here, we need to use `raw_ptr`'s // `GetForExtraction` instead of `GetForDereference`. If we did use // `GetForDereference` then we'd crash in ASAN builds on calling a bound // callback with a dangling reference parameter even if that parameter is // not used. This could hide a later unprotected issue that would be reached // in release builds. return ref.get(); } // `Unretained()` arguments often dangle by design (a common design pattern // is to manage an object's lifetime inside the callback itself, using // stateful information), so disable direct dangling pointer detection // of `ref_`. // // If the callback is invoked, dangling pointer detection will be triggered // before invoking the bound functor (unless stated otherwise, see // `UnsafeDangling()` and `UnsafeDanglingUntriaged()`), when retrieving the // pointer value via `get()` above. using StorageType = std::conditional_t::value, raw_ref, T&>; static constexpr void VerifyPreconditions() { std::ignore = value; } StorageType ref_; }; // Can't use `is_instantiation` to detect the unretained wrappers, since they // have non-type template params. template