Update googleurl to the version from Sat Nov 5 08:06:16 2022
This is corresponding to the Chromium commit 9880a0d69c8b70d4cd18f6705afcc4f73aba0b9b.
In this CL, I have also finally mocked out raw_ptr with a typedef, since
it keeps breaking every roll, and supporting it seems untenable.
Change-Id: Ia9b0c01d961a9586e1642df3dc27ce4573f6d484
diff --git a/AUTHORS b/AUTHORS
index 59ecce0..b32867a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -134,6 +134,7 @@
Arnaud Renevier <a.renevier@samsung.com>
Arpita Bahuguna <a.bah@samsung.com>
Arthur Lussos <developer0420@gmail.com>
+Artur Akerberg <artur.aker@gmail.com>
Arun Kulkarni <kulkarni.a@samsung.com>
Arun Kumar <arun87.kumar@samsung.com>
Arun Mankuzhi <arun.m@samsung.com>
@@ -514,6 +515,7 @@
Jan Keitel <jan.keitel@gmail.com>
Jan Rucka <ruckajan10@gmail.com>
Jan Sauer <jan@jansauer.de>
+Jan-Michael Brummer <jan.brummer@tabos.org>
Janusz Majnert <jmajnert@gmail.com>
Janwar Dinata <j.dinata@gmail.com>
Jared Shumway <jaredshumway94@gmail.com>
@@ -598,6 +600,7 @@
Jongheon Kim <sapzape@gmail.com>
JongKwon Lee <jongkwon.lee@navercorp.com>
Jongmok Kim <jongmok.kim@navercorp.com>
+Jongmok Kim <johny.kimc@gmail.com>
Jongsoo Lee <leejongsoo@gmail.com>
Joone Hur <joone.hur@intel.com>
Joonghun Park <pjh0718@gmail.com>
@@ -1319,6 +1322,7 @@
Yizhou Jiang <yizhou.jiang@intel.com>
Yoav Weiss <yoav@yoav.ws>
Yoav Zilberberg <yoav.zilberberg@gmail.com>
+Yoichiro Hibara <hibarayoichiro871@gmail.com>
Yong Ling <yongling@tencent.com>
Yong Shin <sy3620@gmail.com>
Yong Wang <ccyongwang@tencent.com>
@@ -1403,8 +1407,9 @@
Endless Mobile, Inc. <*@endlessm.com>
EngFlow, Inc. <*@engflow.com>
Estimote, Inc. <*@estimote.com>
-Facebook, Inc. <*@fb.com>
-Facebook, Inc. <*@oculus.com>
+Meta Platforms, Inc. <*@fb.com>
+Meta Platforms, Inc. <*@meta.com>
+Meta Platforms, Inc. <*@oculus.com>
Google Inc. <*@google.com>
Grammarly, Inc. <*@grammarly.com>
Hewlett-Packard Development Company, L.P. <*@hp.com>
@@ -1446,6 +1451,7 @@
Tableau Software <*@tableau.com>
Talon Cyber Security Ltd. <*@talon-sec.com>
TeamSpeak Systems GmbH <*@teamspeak.com>
+The Browser Company <*@thebrowser.company>
The Chromium Authors <*@chromium.org>
The MathWorks, Inc. <binod.pant@mathworks.com>
THEO Technologies <*@theoplayer.com>
diff --git a/README.md b/README.md
index 40fd7f1..5965c48 100644
--- a/README.md
+++ b/README.md
@@ -17,8 +17,8 @@
the following commands in the root of the checkout:
1. `copybara copy.bara.sky import <path-to-chrome>/src --folder-dir .`
-1. `bazel test --cxxopt="-std=c++14" //...`
- (C++14 is replacible with later C++ versions)
+1. `bazel test --cxxopt="-std=c++17" //...`
+ (C++17 is replacible with later C++ versions)
1. Fix all of the compilation errors, potentially modifying the BUILD files and
the polyfill headers in `polyfill/` as appropriate.
1. Check the new version into Git.
diff --git a/base/BUILD b/base/BUILD
index 32c3b9c..a1410fb 100644
--- a/base/BUILD
+++ b/base/BUILD
@@ -32,7 +32,6 @@
"functional/identity.h",
"functional/invoke.h",
"functional/not_fn.h",
- "memory/raw_ptr.h",
"memory/raw_ptr_exclusion.h",
"no_destructor.h",
"numerics/checked_math.h",
@@ -53,6 +52,7 @@
"strings/string_piece_forward.h",
"strings/string_piece.h",
"strings/string_util.h",
+ "strings/string_util_impl_helpers.h",
"strings/string_util_internal.h",
"strings/string_number_conversions.h",
"strings/utf_string_conversions.h",
diff --git a/base/cxx20_to_address.h b/base/cxx20_to_address.h
index ef67a9b..04d0f71 100644
--- a/base/cxx20_to_address.h
+++ b/base/cxx20_to_address.h
@@ -5,10 +5,24 @@
#ifndef BASE_CXX20_TO_ADDRESS_H_
#define BASE_CXX20_TO_ADDRESS_H_
+#include <memory>
#include <type_traits>
namespace gurl_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.
// Note: This does consider specializations of pointer_traits<>::to_address,
// even though it's a C++20 member function, because CheckedContiguousIterator
@@ -23,14 +37,12 @@
}
template <typename Ptr>
-constexpr auto to_address(const Ptr& p) noexcept
- -> decltype(std::pointer_traits<Ptr>::to_address(p)) {
- return std::pointer_traits<Ptr>::to_address(p);
-}
-
-template <typename Ptr, typename... None>
-constexpr auto to_address(const Ptr& p, None...) noexcept {
- return gurl_base::to_address(p.operator->());
+constexpr auto to_address(const Ptr& p) noexcept {
+ if constexpr (has_std_to_address<Ptr>::value) {
+ return std::pointer_traits<Ptr>::to_address(p);
+ } else {
+ return gurl_base::to_address(p.operator->());
+ }
}
} // namespace base
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
index 157a79f..68d1c96 100644
--- a/base/debug/crash_logging.cc
+++ b/base/debug/crash_logging.cc
@@ -4,6 +4,8 @@
#include "base/debug/crash_logging.h"
+#include <ostream>
+
#include "base/strings/string_piece.h"
#include "build/build_config.h"
diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h
index b4cf7bc..ec1df77 100644
--- a/base/debug/crash_logging.h
+++ b/base/debug/crash_logging.h
@@ -12,7 +12,7 @@
#include <type_traits>
#include "polyfills/base/base_export.h"
-#include "base/memory/raw_ptr.h"
+#include "polyfills/base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -48,7 +48,7 @@
//
// static auto* const crash_key = gurl_base::debug::AllocateCrashKeyString(
// "name", gurl_base::debug::CrashKeySize::Size32);
-// gurl_base::debug::SetCrashKeyString(crash_key);
+// gurl_base::debug::SetCrashKeyString(crash_key, "value");
//
// // Do other work before calling `gurl_base::debug::DumpWithoutCrashing()` later.
//
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h
deleted file mode 100644
index d65ab44..0000000
--- a/base/memory/raw_ptr.h
+++ /dev/null
@@ -1,1510 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_MEMORY_RAW_PTR_H_
-#define BASE_MEMORY_RAW_PTR_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <climits>
-#include <cstddef>
-#include <functional>
-#include <type_traits>
-#include <utility>
-
-#include "polyfills/base/allocator/buildflags.h"
-
-#include "polyfills/base/check.h"
-#include "base/compiler_specific.h"
-#include "polyfills/base/dcheck_is_on.h"
-#include "polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h"
-#include "build/build_config.h"
-#include "build/buildflag.h"
-
-#if BUILDFLAG(USE_BACKUP_REF_PTR) || \
- defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-// USE_BACKUP_REF_PTR implies USE_PARTITION_ALLOC, needed for code under
-// allocator/partition_allocator/ to be built.
-#include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
-#include "base/allocator/partition_allocator/partition_address_space.h"
-#include "base/allocator/partition_allocator/partition_alloc_constants.h"
-#include "polyfills/base/base_export.h"
-#endif // BUILDFLAG(USE_BACKUP_REF_PTR) ||
- // defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-
-#if defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-#include "base/allocator/partition_allocator/partition_tag.h"
-#include "base/allocator/partition_allocator/partition_tag_types.h"
-#include "base/allocator/partition_allocator/tagging.h"
-#include "polyfills/base/check_op.h"
-#endif // defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-
-#if BUILDFLAG(IS_WIN)
-#include "base/win/win_handle_types.h"
-#endif
-
-namespace cc {
-class Scheduler;
-}
-namespace gurl_base::internal {
-class DelayTimerBase;
-}
-namespace content::responsiveness {
-class Calculator;
-}
-
-namespace gurl_base {
-
-// NOTE: All methods should be `ALWAYS_INLINE`. raw_ptr is meant to be a
-// lightweight replacement of a raw pointer, hence performance is critical.
-
-// The following types are the different RawPtrType template option possible for
-// a `raw_ptr`:
-// - RawPtrMayDangle disables dangling pointers check when the object is
-// released.
-// - RawPtrBanDanglingIfSupported may enable dangling pointers check on object
-// destruction.
-//
-// We describe those types here so that they can be used outside of `raw_ptr` as
-// object markers, and their meaning might vary depending on where those markers
-// are being used. For instance, we are using those in `UnretainedWrapper` to
-// change behavior depending on RawPtrType.
-struct RawPtrMayDangle {};
-struct RawPtrBanDanglingIfSupported {};
-
-namespace raw_ptr_traits {
-template <typename T>
-struct RawPtrTypeToImpl;
-}
-
-namespace internal {
-// These classes/structures are part of the raw_ptr implementation.
-// DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
-
-// This type trait verifies a type can be used as a pointer offset.
-//
-// We support pointer offsets in signed (ptrdiff_t) or unsigned (size_t) values.
-// Smaller types are also allowed.
-template <typename Z>
-static constexpr bool offset_type =
- std::is_integral_v<Z> && sizeof(Z) <= sizeof(ptrdiff_t);
-
-struct RawPtrNoOpImpl {
- // Wraps a pointer.
- template <typename T>
- static ALWAYS_INLINE T* WrapRawPtr(T* ptr) {
- return ptr;
- }
-
- // Notifies the allocator when a wrapped pointer is being removed or replaced.
- template <typename T>
- static ALWAYS_INLINE void ReleaseWrappedPtr(T*) {}
-
- // Unwraps the pointer, while asserting that memory hasn't been freed. The
- // function is allowed to crash on nullptr.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForDereference(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // Unwraps the pointer, while asserting that memory hasn't been freed. The
- // function must handle nullptr gracefully.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // Unwraps the pointer, without making an assertion on whether memory was
- // freed or not.
- template <typename T>
- static ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // Upcasts the wrapped pointer.
- template <typename To, typename From>
- static ALWAYS_INLINE constexpr To* Upcast(From* wrapped_ptr) {
- static_assert(std::is_convertible<From*, To*>::value,
- "From must be convertible to To.");
- // Note, this cast may change the address if upcasting to base that lies in
- // the middle of the derived object.
- return wrapped_ptr;
- }
-
- // Advance the wrapped pointer by `delta_elems`.
- template <typename T,
- typename Z,
- typename = std::enable_if_t<offset_type<Z>, void>>
- static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) {
- return wrapped_ptr + delta_elems;
- }
-
- template <typename T>
- static ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1,
- T* wrapped_ptr2) {
- return wrapped_ptr1 - wrapped_ptr2;
- }
-
- // Returns a copy of a wrapped pointer, without making an assertion on whether
- // memory was freed or not.
- template <typename T>
- static ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // This is for accounting only, used by unit tests.
- static ALWAYS_INLINE void IncrementSwapCountForTest() {}
- static ALWAYS_INLINE void IncrementLessCountForTest() {}
- static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
-};
-
-#if defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-
-constexpr int kValidAddressBits = 48;
-constexpr uintptr_t kAddressMask = (1ull << kValidAddressBits) - 1;
-constexpr int kTagBits = sizeof(uintptr_t) * 8 - kValidAddressBits;
-
-// MTECheckedPtr has no business with the topmost bits reserved for the
-// tag used by true ARM MTE, so we strip it out here.
-constexpr uintptr_t kTagMask =
- ~kAddressMask & partition_alloc::internal::kPtrUntagMask;
-
-constexpr int kTopBitShift = 63;
-constexpr uintptr_t kTopBit = 1ull << kTopBitShift;
-static_assert(kTopBit << 1 == 0, "kTopBit should really be the top bit");
-static_assert((kTopBit & kTagMask) > 0,
- "kTopBit bit must be inside the tag region");
-
-// This functionality is outside of MTECheckedPtrImpl, so that it can be
-// overridden by tests.
-struct MTECheckedPtrImplPartitionAllocSupport {
- // Checks if the necessary support is enabled in PartitionAlloc for `ptr`.
- template <typename T>
- static ALWAYS_INLINE bool EnabledForPtr(T* ptr) {
- // Disambiguation: UntagPtr removes the hardware MTE tag, whereas this class
- // is responsible for handling the software MTE tag.
- auto addr = partition_alloc::UntagPtr(ptr);
- return partition_alloc::IsManagedByPartitionAlloc(addr);
- }
-
- // Returns pointer to the tag that protects are pointed by |addr|.
- static ALWAYS_INLINE void* TagPointer(uintptr_t addr) {
- return partition_alloc::PartitionTagPointer(addr);
- }
-};
-
-template <typename PartitionAllocSupport>
-struct MTECheckedPtrImpl {
- // This implementation assumes that pointers are 64 bits long and at least 16
- // top bits are unused. The latter is harder to verify statically, but this is
- // true for all currently supported 64-bit architectures (GURL_DCHECK when wrapping
- // will verify that).
- static_assert(sizeof(void*) >= 8, "Need 64-bit pointers");
-
- // Wraps a pointer, and returns its uintptr_t representation.
- template <typename T>
- static ALWAYS_INLINE T* WrapRawPtr(T* ptr) {
- // Disambiguation: UntagPtr removes the hardware MTE tag, whereas this
- // function is responsible for adding the software MTE tag.
- uintptr_t addr = partition_alloc::UntagPtr(ptr);
- GURL_DCHECK_EQ(ExtractTag(addr), 0ull);
-
- // Return a not-wrapped |addr|, if it's either nullptr or if the protection
- // for this pointer is disabled.
- if (!PartitionAllocSupport::EnabledForPtr(ptr)) {
- return ptr;
- }
-
- // Read the tag and place it in the top bits of the address.
- // Even if PartitionAlloc's tag has less than kTagBits, we'll read
- // what's given and pad the rest with 0s.
- static_assert(sizeof(partition_alloc::PartitionTag) * 8 <= kTagBits, "");
- uintptr_t tag = *(static_cast<volatile partition_alloc::PartitionTag*>(
- PartitionAllocSupport::TagPointer(addr)));
- GURL_DCHECK(tag);
-
- tag <<= kValidAddressBits;
- addr |= tag;
- // See the disambiguation comment above.
- // TODO(kdlee): Ensure that ptr's hardware MTE tag is preserved.
- // TODO(kdlee): Ensure that hardware and software MTE tags don't conflict.
- return static_cast<T*>(partition_alloc::internal::TagAddr(addr));
- }
-
- // Notifies the allocator when a wrapped pointer is being removed or replaced.
- // No-op for MTECheckedPtrImpl.
- template <typename T>
- static ALWAYS_INLINE void ReleaseWrappedPtr(T*) {}
-
- // Unwraps the pointer's uintptr_t representation, while asserting that memory
- // hasn't been freed. The function is allowed to crash on nullptr.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForDereference(T* wrapped_ptr) {
- // Disambiguation: UntagPtr removes the hardware MTE tag, whereas this
- // function is responsible for removing the software MTE tag.
- uintptr_t wrapped_addr = partition_alloc::UntagPtr(wrapped_ptr);
- uintptr_t tag = ExtractTag(wrapped_addr);
- if (tag > 0) {
- // Read the tag provided by PartitionAlloc.
- //
- // Cast to volatile to ensure memory is read. E.g. in a tight loop, the
- // compiler could cache the value in a register and thus could miss that
- // another thread freed memory and changed tag.
- uintptr_t read_tag =
- *static_cast<volatile partition_alloc::PartitionTag*>(
- PartitionAllocSupport::TagPointer(ExtractAddress(wrapped_addr)));
- if (UNLIKELY(tag != read_tag))
- IMMEDIATE_CRASH();
- // See the disambiguation comment above.
- // TODO(kdlee): Ensure that ptr's hardware MTE tag is preserved.
- // TODO(kdlee): Ensure that hardware and software MTE tags don't conflict.
- return static_cast<T*>(
- partition_alloc::internal::TagAddr(ExtractAddress(wrapped_addr)));
- }
- return wrapped_ptr;
- }
-
- // Unwraps the pointer's uintptr_t representation, while asserting that memory
- // hasn't been freed. The function must handle nullptr gracefully.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction(T* wrapped_ptr) {
- // SafelyUnwrapPtrForDereference handles nullptr case well.
- return SafelyUnwrapPtrForDereference(wrapped_ptr);
- }
-
- // Unwraps the pointer's uintptr_t representation, without making an assertion
- // on whether memory was freed or not.
- template <typename T>
- static ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison(T* wrapped_ptr) {
- return ExtractPtr(wrapped_ptr);
- }
-
- // Upcasts the wrapped pointer.
- template <typename To, typename From>
- static ALWAYS_INLINE constexpr To* Upcast(From* wrapped_ptr) {
- static_assert(std::is_convertible<From*, To*>::value,
- "From must be convertible to To.");
-
- // The top-bit tag must not affect the result of upcast.
- return static_cast<To*>(wrapped_ptr);
- }
-
- // Advance the wrapped pointer by `delta_elems`.
- template <typename T,
- typename Z,
- typename = std::enable_if_t<offset_type<Z>, void>>
- static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) {
- return wrapped_ptr + delta_elems;
- }
-
- template <typename T>
- static ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1,
- T* wrapped_ptr2) {
- // Ensure that both pointers come from the same allocation.
- //
- // Disambiguation: UntagPtr removes the hardware MTE tag, whereas this
- // class is responsible for handling the software MTE tag.
- //
- // MTECheckedPtr doesn't use 0 as a valid tag; depending on which
- // subtraction operator is called, we may be getting the actual
- // untagged T* or the wrapped pointer (passed as a T*) in one or
- // both args. We can only check slot cohabitation when both args
- // come with tags.
- const uintptr_t tag1 = ExtractTag(partition_alloc::UntagPtr(wrapped_ptr1));
- const uintptr_t tag2 = ExtractTag(partition_alloc::UntagPtr(wrapped_ptr2));
- if (tag1 && tag2) {
- GURL_CHECK(tag1 == tag2);
- return wrapped_ptr1 - wrapped_ptr2;
- }
-
- // If one or the other arg come untagged, we have to perform the
- // subtraction entirely without tags.
- return reinterpret_cast<T*>(
- ExtractAddress(partition_alloc::UntagPtr(wrapped_ptr1))) -
- reinterpret_cast<T*>(
- ExtractAddress(partition_alloc::UntagPtr(wrapped_ptr2)));
- }
-
- // Returns a copy of a wrapped pointer, without making an assertion
- // on whether memory was freed or not.
- template <typename T>
- static ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // This is for accounting only, used by unit tests.
- static ALWAYS_INLINE void IncrementSwapCountForTest() {}
- static ALWAYS_INLINE void IncrementLessCountForTest() {}
- static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
-
- private:
- static ALWAYS_INLINE uintptr_t ExtractAddress(uintptr_t wrapped_ptr) {
- return wrapped_ptr & kAddressMask;
- }
-
- template <typename T>
- static ALWAYS_INLINE T* ExtractPtr(T* wrapped_ptr) {
- // Disambiguation: UntagPtr/TagAddr handle the hardware MTE tag, whereas
- // this function is responsible for removing the software MTE tag.
- // TODO(kdlee): Ensure that wrapped_ptr's hardware MTE tag is preserved.
- // TODO(kdlee): Ensure that hardware and software MTE tags don't conflict.
- return static_cast<T*>(partition_alloc::internal::TagAddr(
- ExtractAddress(partition_alloc::UntagPtr(wrapped_ptr))));
- }
-
- static ALWAYS_INLINE uintptr_t ExtractTag(uintptr_t wrapped_ptr) {
- return (wrapped_ptr & kTagMask) >> kValidAddressBits;
- }
-};
-
-#endif // defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
-
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
-BASE_EXPORT void CheckThatAddressIsntWithinFirstPartitionPage(
- uintptr_t address);
-#endif
-
-template <bool AllowDangling = false>
-struct BackupRefPtrImpl {
- // Note that `BackupRefPtrImpl` itself is not thread-safe. If multiple threads
- // modify the same smart pointer object without synchronization, a data race
- // will occur.
-
- static ALWAYS_INLINE bool IsSupportedAndNotNull(uintptr_t address) {
- // This covers the nullptr case, as address 0 is never in GigaCage.
- bool is_in_brp_pool =
- partition_alloc::IsManagedByPartitionAllocBRPPool(address);
-
- // There are many situations where the compiler can prove that
- // ReleaseWrappedPtr is called on a value that is always nullptr, but the
- // way the check above is written, the compiler can't prove that nullptr is
- // not managed by PartitionAlloc; and so the compiler has to emit a useless
- // check and dead code.
- // To avoid that without making the runtime check slower, explicitly promise
- // to the compiler that is_in_brp_pool will always be false for nullptr.
- //
- // This condition would look nicer and might also theoretically be nicer for
- // the optimizer if it was written as "if (!address) { ... }", but
- // LLVM currently has issues with optimizing that away properly; see:
- // https://bugs.llvm.org/show_bug.cgi?id=49403
- // https://reviews.llvm.org/D97848
- // https://chromium-review.googlesource.com/c/chromium/src/+/2727400/2/base/memory/checked_ptr.h#120
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
- GURL_CHECK(address || !is_in_brp_pool);
-#endif
-#if HAS_BUILTIN(__builtin_assume)
- __builtin_assume(address || !is_in_brp_pool);
-#endif
-
- // There may be pointers immediately after the allocation, e.g.
- // {
- // // Assume this allocation happens outside of PartitionAlloc.
- // raw_ptr<T> ptr = new T[20];
- // for (size_t i = 0; i < 20; i ++) { ptr++; }
- // }
- //
- // Such pointers are *not* at risk of accidentally falling into BRP pool,
- // because:
- // 1) On 64-bit systems, BRP pool is preceded by a forbidden region.
- // 2) On 32-bit systems, the guard pages and metadata of super pages in BRP
- // pool aren't considered to be part of that pool.
- //
- // This allows us to make a stronger assertion that if
- // IsManagedByPartitionAllocBRPPool returns true for a valid pointer,
- // it must be at least partition page away from the beginning of a super
- // page.
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
- if (is_in_brp_pool) {
- CheckThatAddressIsntWithinFirstPartitionPage(address);
- }
-#endif
-
- return is_in_brp_pool;
- }
-
- // Wraps a pointer.
- template <typename T>
- static ALWAYS_INLINE T* WrapRawPtr(T* ptr) {
- uintptr_t address = partition_alloc::UntagPtr(ptr);
- if (IsSupportedAndNotNull(address)) {
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
- GURL_CHECK(ptr != nullptr);
-#endif
- AcquireInternal(address);
- }
-#if !defined(PA_HAS_64_BITS_POINTERS)
- else {
- partition_alloc::internal::AddressPoolManagerBitmap::
- BanSuperPageFromBRPPool(address);
- }
-#endif
-
- return ptr;
- }
-
- // Notifies the allocator when a wrapped pointer is being removed or replaced.
- template <typename T>
- static ALWAYS_INLINE void ReleaseWrappedPtr(T* wrapped_ptr) {
- uintptr_t address = partition_alloc::UntagPtr(wrapped_ptr);
- if (IsSupportedAndNotNull(address)) {
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
- GURL_CHECK(wrapped_ptr != nullptr);
-#endif
- ReleaseInternal(address);
- }
- // We are unable to counteract BanSuperPageFromBRPPool(), called from
- // WrapRawPtr(). We only use one bit per super-page and, thus can't tell if
- // there's more than one associated raw_ptr<T> at a given time. The risk of
- // exhausting the entire address space is minuscule, therefore, we couldn't
- // resist the perf gain of a single relaxed store (in the above mentioned
- // function) over much more expensive two CAS operations, which we'd have to
- // use if we were to un-ban a super-page.
- }
-
- // Unwraps the pointer, while asserting that memory hasn't been freed. The
- // function is allowed to crash on nullptr.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForDereference(T* wrapped_ptr) {
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
- uintptr_t address = partition_alloc::UntagPtr(wrapped_ptr);
- if (IsSupportedAndNotNull(address)) {
- GURL_CHECK(wrapped_ptr != nullptr);
- GURL_CHECK(IsPointeeAlive(address));
- }
-#endif
- return wrapped_ptr;
- }
-
- // Unwraps the pointer, while asserting that memory hasn't been freed. The
- // function must handle nullptr gracefully.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // Unwraps the pointer, without making an assertion on whether memory was
- // freed or not.
- template <typename T>
- static ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // Upcasts the wrapped pointer.
- template <typename To, typename From>
- static ALWAYS_INLINE constexpr To* Upcast(From* wrapped_ptr) {
- static_assert(std::is_convertible<From*, To*>::value,
- "From must be convertible to To.");
- // Note, this cast may change the address if upcasting to base that lies in
- // the middle of the derived object.
- return wrapped_ptr;
- }
-
- // Advance the wrapped pointer by `delta_elems`.
- template <typename T,
- typename Z,
- typename = std::enable_if_t<offset_type<Z>, void>>
- static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) {
-#if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
- // First check if the new address lands within the same allocation
- // (end-of-allocation address is ok too). It has a non-trivial cost, but
- // it's cheaper and more secure than the previous implementation that
- // rewrapped the pointer (wrapped the new pointer and unwrapped the old
- // one).
- uintptr_t address = partition_alloc::UntagPtr(wrapped_ptr);
- // TODO(bartekn): Consider adding support for non-BRP pool too.
- if (IsSupportedAndNotNull(address))
- GURL_CHECK(IsValidDelta(address, delta_elems * static_cast<Z>(sizeof(T))));
- return wrapped_ptr + delta_elems;
-#else
- // In the "before allocation" mode, on 32-bit, we can run into a problem
- // that the end-of-allocation address could fall out of "GigaCage", if this
- // is the last slot of the super page, thus pointing to the guard page. This
- // mean the ref-count won't be decreased when the pointer is released
- // (leak).
- //
- // We could possibly solve it in a few different ways:
- // - Add the trailing guard page to "GigaCage", but we'd have to think very
- // hard if this doesn't create another hole.
- // - Add an address adjustment to "GigaCage" check, similar as the one in
- // PartitionAllocGetSlotStartInBRPPool(), but that seems fragile, not to
- // mention adding an extra instruction to an inlined hot path.
- // - Let the leak happen, since it should a very rare condition.
- // - Go back to the previous solution of rewrapping the pointer, but that
- // had an issue of losing protection in case the pointer ever gets shifter
- // before the end of allocation.
- //
- // We decided to cross that bridge once we get there... if we ever get
- // there. Currently there are no plans to switch back to the "before
- // allocation" mode.
- //
- // This problem doesn't exist in the "previous slot" mode, or any mode that
- // involves putting extras after the allocation, because the
- // end-of-allocation address belongs to the same slot.
- static_assert(false);
-#endif
- }
-
- template <typename T>
- static ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1,
- T* wrapped_ptr2) {
- uintptr_t address1 = partition_alloc::UntagPtr(wrapped_ptr1);
- uintptr_t address2 = partition_alloc::UntagPtr(wrapped_ptr2);
- // Ensure that both pointers are within the same slot, and pool!
- // TODO(bartekn): Consider adding support for non-BRP pool too.
- if (IsSupportedAndNotNull(address1)) {
- GURL_CHECK(IsSupportedAndNotNull(address2));
- GURL_CHECK(IsValidDelta(address2, address1 - address2));
- } else {
- GURL_CHECK(!IsSupportedAndNotNull(address2));
- }
- return wrapped_ptr1 - wrapped_ptr2;
- }
-
- // Returns a copy of a wrapped pointer, without making an assertion on whether
- // memory was freed or not.
- // This method increments the reference count of the allocation slot.
- template <typename T>
- static ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) {
- return WrapRawPtr(wrapped_ptr);
- }
-
- // Report the current wrapped pointer if pointee isn't alive anymore.
- template <typename T>
- static ALWAYS_INLINE void ReportIfDangling(T* wrapped_ptr) {
- ReportIfDanglingInternal(partition_alloc::UntagPtr(wrapped_ptr));
- }
-
- // This is for accounting only, used by unit tests.
- static ALWAYS_INLINE void IncrementSwapCountForTest() {}
- static ALWAYS_INLINE void IncrementLessCountForTest() {}
- static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
-
- private:
- // We've evaluated several strategies (inline nothing, various parts, or
- // everything in |Wrap()| and |Release()|) using the Speedometer2 benchmark
- // to measure performance. The best results were obtained when only the
- // lightweight |IsManagedByPartitionAllocBRPPool()| check was inlined.
- // Therefore, we've extracted the rest into the functions below and marked
- // them as NOINLINE to prevent unintended LTO effects.
- static BASE_EXPORT NOINLINE void AcquireInternal(uintptr_t address);
- static BASE_EXPORT NOINLINE void ReleaseInternal(uintptr_t address);
- static BASE_EXPORT NOINLINE bool IsPointeeAlive(uintptr_t address);
- static BASE_EXPORT NOINLINE void ReportIfDanglingInternal(uintptr_t address);
- template <typename Z, typename = std::enable_if_t<offset_type<Z>, void>>
- static ALWAYS_INLINE bool IsValidDelta(uintptr_t address, Z delta_in_bytes) {
- if constexpr (std::is_signed_v<Z>)
- return IsValidSignedDelta(address, ptrdiff_t{delta_in_bytes});
- else
- return IsValidUnsignedDelta(address, size_t{delta_in_bytes});
- }
- static BASE_EXPORT NOINLINE bool IsValidSignedDelta(uintptr_t address,
- ptrdiff_t delta_in_bytes);
- static BASE_EXPORT NOINLINE bool IsValidUnsignedDelta(uintptr_t address,
- size_t delta_in_bytes);
-};
-
-#endif // BUILDFLAG(USE_BACKUP_REF_PTR)
-
-// Implementation that allows us to detect BackupRefPtr problems in ASan builds.
-struct AsanBackupRefPtrImpl {
- // Wraps a pointer.
- template <typename T>
- static ALWAYS_INLINE T* WrapRawPtr(T* ptr) {
- AsanCheckIfValidInstantiation(ptr);
- return ptr;
- }
-
- // Notifies the allocator when a wrapped pointer is being removed or replaced.
- template <typename T>
- static ALWAYS_INLINE void ReleaseWrappedPtr(T*) {}
-
- // Unwraps the pointer, while asserting that memory hasn't been freed. The
- // function is allowed to crash on nullptr.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForDereference(T* wrapped_ptr) {
- AsanCheckIfValidDereference(wrapped_ptr);
- return wrapped_ptr;
- }
-
- // Unwraps the pointer, while asserting that memory hasn't been freed. The
- // function must handle nullptr gracefully.
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction(T* wrapped_ptr) {
- AsanCheckIfValidExtraction(wrapped_ptr);
- return wrapped_ptr;
- }
-
- // Unwraps the pointer, without making an assertion on whether memory was
- // freed or not.
- template <typename T>
- static ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // Upcasts the wrapped pointer.
- template <typename To, typename From>
- static ALWAYS_INLINE constexpr To* Upcast(From* wrapped_ptr) {
- static_assert(std::is_convertible<From*, To*>::value,
- "From must be convertible to To.");
- // Note, this cast may change the address if upcasting to base that lies in
- // the middle of the derived object.
- return wrapped_ptr;
- }
-
- // Advance the wrapped pointer by `delta_elems`.
- template <typename T,
- typename Z,
- typename = std::enable_if_t<offset_type<Z>, void>>
- static ALWAYS_INLINE T* Advance(T* wrapped_ptr, Z delta_elems) {
- return wrapped_ptr + delta_elems;
- }
-
- template <typename T>
- static ALWAYS_INLINE ptrdiff_t GetDeltaElems(T* wrapped_ptr1,
- T* wrapped_ptr2) {
- return wrapped_ptr1 - wrapped_ptr2;
- }
-
- // Returns a copy of a wrapped pointer, without making an assertion on whether
- // memory was freed or not.
- template <typename T>
- static ALWAYS_INLINE T* Duplicate(T* wrapped_ptr) {
- return wrapped_ptr;
- }
-
- // This is for accounting only, used by unit tests.
- static ALWAYS_INLINE void IncrementSwapCountForTest() {}
- static ALWAYS_INLINE void IncrementLessCountForTest() {}
- static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {}
-
- private:
- static BASE_EXPORT NOINLINE void AsanCheckIfValidInstantiation(
- void const volatile* ptr);
- static BASE_EXPORT NOINLINE void AsanCheckIfValidDereference(
- void const volatile* ptr);
- static BASE_EXPORT NOINLINE void AsanCheckIfValidExtraction(
- void const volatile* ptr);
-};
-
-template <class Super>
-struct RawPtrCountingImplWrapperForTest
- : public raw_ptr_traits::RawPtrTypeToImpl<Super>::Impl {
- using SuperImpl = typename raw_ptr_traits::RawPtrTypeToImpl<Super>::Impl;
- template <typename T>
- static ALWAYS_INLINE T* WrapRawPtr(T* ptr) {
- ++wrap_raw_ptr_cnt;
- return SuperImpl::WrapRawPtr(ptr);
- }
-
- template <typename T>
- static ALWAYS_INLINE void ReleaseWrappedPtr(T* ptr) {
- ++release_wrapped_ptr_cnt;
- SuperImpl::ReleaseWrappedPtr(ptr);
- }
-
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForDereference(T* wrapped_ptr) {
- ++get_for_dereference_cnt;
- return SuperImpl::SafelyUnwrapPtrForDereference(wrapped_ptr);
- }
-
- template <typename T>
- static ALWAYS_INLINE T* SafelyUnwrapPtrForExtraction(T* wrapped_ptr) {
- ++get_for_extraction_cnt;
- return SuperImpl::SafelyUnwrapPtrForExtraction(wrapped_ptr);
- }
-
- template <typename T>
- static ALWAYS_INLINE T* UnsafelyUnwrapPtrForComparison(T* wrapped_ptr) {
- ++get_for_comparison_cnt;
- return SuperImpl::UnsafelyUnwrapPtrForComparison(wrapped_ptr);
- }
-
- static ALWAYS_INLINE void IncrementSwapCountForTest() {
- ++wrapped_ptr_swap_cnt;
- }
-
- static ALWAYS_INLINE void IncrementLessCountForTest() {
- ++wrapped_ptr_less_cnt;
- }
-
- static ALWAYS_INLINE void IncrementPointerToMemberOperatorCountForTest() {
- ++pointer_to_member_operator_cnt;
- }
-
- static void ClearCounters() {
- wrap_raw_ptr_cnt = 0;
- release_wrapped_ptr_cnt = 0;
- get_for_dereference_cnt = 0;
- get_for_extraction_cnt = 0;
- get_for_comparison_cnt = 0;
- wrapped_ptr_swap_cnt = 0;
- wrapped_ptr_less_cnt = 0;
- pointer_to_member_operator_cnt = 0;
- }
-
- static inline int wrap_raw_ptr_cnt = INT_MIN;
- static inline int release_wrapped_ptr_cnt = INT_MIN;
- static inline int get_for_dereference_cnt = INT_MIN;
- static inline int get_for_extraction_cnt = INT_MIN;
- static inline int get_for_comparison_cnt = INT_MIN;
- static inline int wrapped_ptr_swap_cnt = INT_MIN;
- static inline int wrapped_ptr_less_cnt = INT_MIN;
- static inline int pointer_to_member_operator_cnt = INT_MIN;
-};
-
-} // namespace internal
-
-namespace raw_ptr_traits {
-
-// IsSupportedType<T>::value answers whether raw_ptr<T> 1) compiles and 2) is
-// always safe at runtime. Templates that may end up using `raw_ptr<T>` should
-// use IsSupportedType to ensure that raw_ptr is not used with unsupported
-// types. As an example, see how gurl_base::internal::StorageTraits uses
-// IsSupportedType as a condition for using gurl_base::internal::UnretainedWrapper
-// (which has a `ptr_` field that will become `raw_ptr<T>` after the Big
-// Rewrite).
-template <typename T, typename SFINAE = void>
-struct IsSupportedType {
- static constexpr bool value = true;
-};
-
-// raw_ptr<T> is not compatible with function pointer types. Also, they don't
-// even need the raw_ptr protection, because they don't point on heap.
-template <typename T>
-struct IsSupportedType<T, std::enable_if_t<std::is_function<T>::value>> {
- static constexpr bool value = false;
-};
-
-// This section excludes some types from raw_ptr<T> to avoid them from being
-// used inside gurl_base::Unretained in performance sensitive places. These were
-// identified from sampling profiler data. See crbug.com/1287151 for more info.
-template <>
-struct IsSupportedType<cc::Scheduler> {
- static constexpr bool value = false;
-};
-template <>
-struct IsSupportedType<gurl_base::internal::DelayTimerBase> {
- static constexpr bool value = false;
-};
-template <>
-struct IsSupportedType<content::responsiveness::Calculator> {
- static constexpr bool value = false;
-};
-
-// IsRawPtrCountingImpl<T>::value answers whether T is a specialization of
-// RawPtrCountingImplWrapperForTest, to know whether Impl is for testing
-// purposes.
-template <typename T>
-struct IsRawPtrCountingImpl : std::false_type {};
-
-template <typename T>
-struct IsRawPtrCountingImpl<internal::RawPtrCountingImplWrapperForTest<T>>
- : std::true_type {};
-
-#if __OBJC__
-// raw_ptr<T> is not compatible with pointers to Objective-C classes for a
-// multitude of reasons. They may fail to compile in many cases, and wouldn't
-// work well with tagged pointers. Anyway, Objective-C objects have their own
-// way of tracking lifespan, hence don't need the raw_ptr protection as much.
-//
-// Such pointers are detected by checking if they're convertible to |id| type.
-template <typename T>
-struct IsSupportedType<T,
- std::enable_if_t<std::is_convertible<T*, id>::value>> {
- static constexpr bool value = false;
-};
-#endif // __OBJC__
-
-#if BUILDFLAG(IS_WIN)
-// raw_ptr<HWND__> is unsafe at runtime - if the handle happens to also
-// represent a valid pointer into a PartitionAlloc-managed region then it can
-// lead to manipulating random memory when treating it as BackupRefPtr
-// ref-count. See also https://crbug.com/1262017.
-//
-// TODO(https://crbug.com/1262017): Cover other handle types like HANDLE,
-// HLOCAL, HINTERNET, or HDEVINFO. Maybe we should avoid using raw_ptr<T> when
-// T=void (as is the case in these handle types). OTOH, explicit,
-// non-template-based raw_ptr<void> should be allowed. Maybe this can be solved
-// by having 2 traits: IsPointeeAlwaysSafe (to be used in templates) and
-// IsPointeeUsuallySafe (to be used in the static_assert in raw_ptr). The
-// upside of this approach is that it will safely handle gurl_base::Bind closing over
-// HANDLE. The downside of this approach is that gurl_base::Bind closing over a
-// void* pointer will not get UaF protection.
-#define CHROME_WINDOWS_HANDLE_TYPE(name) \
- template <> \
- struct IsSupportedType<name##__, void> { \
- static constexpr bool value = false; \
- };
-#include "base/win/win_handle_types_list.inc"
-#undef CHROME_WINDOWS_HANDLE_TYPE
-#endif
-
-template <typename T>
-struct RawPtrTypeToImpl {};
-
-template <typename T>
-struct RawPtrTypeToImpl<internal::RawPtrCountingImplWrapperForTest<T>> {
- using Impl = internal::RawPtrCountingImplWrapperForTest<T>;
-};
-
-template <>
-struct RawPtrTypeToImpl<RawPtrMayDangle> {
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
- using Impl = internal::BackupRefPtrImpl</*AllowDangling=*/true>;
-#elif BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
- using Impl = internal::AsanBackupRefPtrImpl;
-#elif defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
- using Impl = internal::MTECheckedPtrImpl<
- internal::MTECheckedPtrImplPartitionAllocSupport>;
-#else
- using Impl = internal::RawPtrNoOpImpl;
-#endif
-};
-
-template <>
-struct RawPtrTypeToImpl<RawPtrBanDanglingIfSupported> {
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
- using Impl = internal::BackupRefPtrImpl</*AllowDangling=*/false>;
-#elif BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
- using Impl = internal::AsanBackupRefPtrImpl;
-#elif defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
- using Impl = internal::MTECheckedPtrImpl<
- internal::MTECheckedPtrImplPartitionAllocSupport>;
-#else
- using Impl = internal::RawPtrNoOpImpl;
-#endif
-};
-
-} // namespace raw_ptr_traits
-
-// `raw_ptr<T>` is a non-owning smart pointer that has improved memory-safety
-// over raw pointers. It behaves just like a raw pointer on platforms where
-// USE_BACKUP_REF_PTR is off, and almost like one when it's on (the main
-// difference is that it's zero-initialized and cleared on destruction and
-// move). Unlike `std::unique_ptr<T>`, `gurl_base::scoped_refptr<T>`, etc., it
-// doesn’t manage ownership or lifetime of an allocated object - you are still
-// responsible for freeing the object when no longer used, just as you would
-// with a raw C++ pointer.
-//
-// Compared to a raw C++ pointer, on platforms where USE_BACKUP_REF_PTR is on,
-// `raw_ptr<T>` incurs additional performance overhead for initialization,
-// destruction, and assignment (including `ptr++` and `ptr += ...`). There is
-// no overhead when dereferencing a pointer.
-//
-// `raw_ptr<T>` is beneficial for security, because it can prevent a significant
-// percentage of Use-after-Free (UaF) bugs from being exploitable. `raw_ptr<T>`
-// has limited impact on stability - dereferencing a dangling pointer remains
-// Undefined Behavior. Note that the security protection is not yet enabled by
-// default.
-//
-// raw_ptr<T> is marked as [[gsl::Pointer]] which allows the compiler to catch
-// some bugs where the raw_ptr holds a dangling pointer to a temporary object.
-// However the [[gsl::Pointer]] analysis expects that such types do not have a
-// non-default move constructor/assignment. Thus, it's possible to get an error
-// where the pointer is not actually dangling, and have to work around the
-// compiler. We have not managed to construct such an example in Chromium yet.
-
-using DefaultRawPtrType = RawPtrBanDanglingIfSupported;
-
-template <typename T, typename RawPtrType = DefaultRawPtrType>
-class TRIVIAL_ABI GSL_POINTER raw_ptr {
- using Impl = typename raw_ptr_traits::RawPtrTypeToImpl<RawPtrType>::Impl;
- using DanglingRawPtr = std::conditional_t<
- raw_ptr_traits::IsRawPtrCountingImpl<Impl>::value,
- raw_ptr<T, internal::RawPtrCountingImplWrapperForTest<RawPtrMayDangle>>,
- raw_ptr<T, RawPtrMayDangle>>;
-
- public:
- static_assert(raw_ptr_traits::IsSupportedType<T>::value,
- "raw_ptr<T> doesn't work with this kind of pointee type T");
-
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
- // BackupRefPtr requires a non-trivial default constructor, destructor, etc.
- constexpr ALWAYS_INLINE raw_ptr() noexcept : wrapped_ptr_(nullptr) {}
-
- ALWAYS_INLINE raw_ptr(const raw_ptr& p) noexcept
- : wrapped_ptr_(Impl::Duplicate(p.wrapped_ptr_)) {}
-
- ALWAYS_INLINE raw_ptr(raw_ptr&& p) noexcept {
- wrapped_ptr_ = p.wrapped_ptr_;
- p.wrapped_ptr_ = nullptr;
- }
-
- ALWAYS_INLINE raw_ptr& operator=(const raw_ptr& p) noexcept {
- // Duplicate before releasing, in case the pointer is assigned to itself.
- //
- // Unlike the move version of this operator, don't add |this != &p| branch,
- // for performance reasons. Even though Duplicate() is not cheap, we
- // practically never assign a raw_ptr<T> to itself. We suspect that a
- // cumulative cost of a conditional branch, even if always correctly
- // predicted, would exceed that.
- T* new_ptr = Impl::Duplicate(p.wrapped_ptr_);
- Impl::ReleaseWrappedPtr(wrapped_ptr_);
- wrapped_ptr_ = new_ptr;
- return *this;
- }
-
- ALWAYS_INLINE raw_ptr& operator=(raw_ptr&& p) noexcept {
- // Unlike the the copy version of this operator, this branch is necessaty
- // for correctness.
- if (LIKELY(this != &p)) {
- Impl::ReleaseWrappedPtr(wrapped_ptr_);
- wrapped_ptr_ = p.wrapped_ptr_;
- p.wrapped_ptr_ = nullptr;
- }
- return *this;
- }
-
- ALWAYS_INLINE ~raw_ptr() noexcept {
- Impl::ReleaseWrappedPtr(wrapped_ptr_);
- // Work around external issues where raw_ptr is used after destruction.
- wrapped_ptr_ = nullptr;
- }
-
-#else // BUILDFLAG(USE_BACKUP_REF_PTR)
-
- // raw_ptr can be trivially default constructed (leaving |wrapped_ptr_|
- // uninitialized). This is needed for compatibility with raw pointers.
- //
- // TODO(lukasza): Always initialize |wrapped_ptr_|. Fix resulting build
- // errors. Analyze performance impact.
- constexpr ALWAYS_INLINE raw_ptr() noexcept = default;
-
- // In addition to nullptr_t ctor above, raw_ptr needs to have these
- // as |=default| or |constexpr| to avoid hitting -Wglobal-constructors in
- // cases like this:
- // struct SomeStruct { int int_field; raw_ptr<int> ptr_field; };
- // SomeStruct g_global_var = { 123, nullptr };
- ALWAYS_INLINE raw_ptr(const raw_ptr&) noexcept = default;
- ALWAYS_INLINE raw_ptr(raw_ptr&&) noexcept = default;
- ALWAYS_INLINE raw_ptr& operator=(const raw_ptr&) noexcept = default;
- ALWAYS_INLINE raw_ptr& operator=(raw_ptr&&) noexcept = default;
-
- ALWAYS_INLINE ~raw_ptr() noexcept = default;
-
-#endif // BUILDFLAG(USE_BACKUP_REF_PTR)
-
- // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr.
- // NOLINTNEXTLINE(google-explicit-constructor)
- constexpr ALWAYS_INLINE raw_ptr(std::nullptr_t) noexcept
- : wrapped_ptr_(nullptr) {}
-
- // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr.
- // NOLINTNEXTLINE(google-explicit-constructor)
- ALWAYS_INLINE raw_ptr(T* p) noexcept : wrapped_ptr_(Impl::WrapRawPtr(p)) {}
-
- // Deliberately implicit in order to support implicit upcast.
- template <typename U,
- typename Unused = std::enable_if_t<
- std::is_convertible<U*, T*>::value &&
- !std::is_void<typename std::remove_cv<T>::type>::value>>
- // NOLINTNEXTLINE(google-explicit-constructor)
- ALWAYS_INLINE raw_ptr(const raw_ptr<U, RawPtrType>& ptr) noexcept
- : wrapped_ptr_(
- Impl::Duplicate(Impl::template Upcast<T, U>(ptr.wrapped_ptr_))) {}
- // Deliberately implicit in order to support implicit upcast.
- template <typename U,
- typename Unused = std::enable_if_t<
- std::is_convertible<U*, T*>::value &&
- !std::is_void<typename std::remove_cv<T>::type>::value>>
- // NOLINTNEXTLINE(google-explicit-constructor)
- ALWAYS_INLINE raw_ptr(raw_ptr<U, RawPtrType>&& ptr) noexcept
- : wrapped_ptr_(Impl::template Upcast<T, U>(ptr.wrapped_ptr_)) {
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
- ptr.wrapped_ptr_ = nullptr;
-#endif
- }
-
- ALWAYS_INLINE raw_ptr& operator=(std::nullptr_t) noexcept {
- Impl::ReleaseWrappedPtr(wrapped_ptr_);
- wrapped_ptr_ = nullptr;
- return *this;
- }
- ALWAYS_INLINE raw_ptr& operator=(T* p) noexcept {
- Impl::ReleaseWrappedPtr(wrapped_ptr_);
- wrapped_ptr_ = Impl::WrapRawPtr(p);
- return *this;
- }
-
- // Upcast assignment
- template <typename U,
- typename Unused = std::enable_if_t<
- std::is_convertible<U*, T*>::value &&
- !std::is_void<typename std::remove_cv<T>::type>::value>>
- ALWAYS_INLINE raw_ptr& operator=(const raw_ptr<U, RawPtrType>& ptr) noexcept {
- // Make sure that pointer isn't assigned to itself (look at pointer address,
- // not its value).
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
- GURL_CHECK(reinterpret_cast<uintptr_t>(this) !=
- reinterpret_cast<uintptr_t>(&ptr));
-#endif
- Impl::ReleaseWrappedPtr(wrapped_ptr_);
- wrapped_ptr_ =
- Impl::Duplicate(Impl::template Upcast<T, U>(ptr.wrapped_ptr_));
- return *this;
- }
- template <typename U,
- typename Unused = std::enable_if_t<
- std::is_convertible<U*, T*>::value &&
- !std::is_void<typename std::remove_cv<T>::type>::value>>
- ALWAYS_INLINE raw_ptr& operator=(raw_ptr<U, RawPtrType>&& ptr) noexcept {
- // Make sure that pointer isn't assigned to itself (look at pointer address,
- // not its value).
-#if GURL_DCHECK_IS_ON() || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
- GURL_CHECK(reinterpret_cast<uintptr_t>(this) !=
- reinterpret_cast<uintptr_t>(&ptr));
-#endif
- Impl::ReleaseWrappedPtr(wrapped_ptr_);
- wrapped_ptr_ = Impl::template Upcast<T, U>(ptr.wrapped_ptr_);
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
- ptr.wrapped_ptr_ = nullptr;
-#endif
- return *this;
- }
-
- // Avoid using. The goal of raw_ptr is to be as close to raw pointer as
- // possible, so use it only if absolutely necessary (e.g. for const_cast).
- ALWAYS_INLINE T* get() const { return GetForExtraction(); }
-
- explicit ALWAYS_INLINE operator bool() const { return !!wrapped_ptr_; }
-
- template <typename U = T,
- typename Unused = std::enable_if_t<
- !std::is_void<typename std::remove_cv<U>::type>::value>>
- ALWAYS_INLINE U& operator*() const {
- return *GetForDereference();
- }
- ALWAYS_INLINE T* operator->() const { return GetForDereference(); }
-
- // Disables `(my_raw_ptr->*pmf)(...)` as a workaround for
- // the ICE in GCC parsing the code, reported at
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103455
- template <typename PMF>
- void operator->*(PMF) const = delete;
-
- // Deliberately implicit, because raw_ptr is supposed to resemble raw ptr.
- // NOLINTNEXTLINE(runtime/explicit)
- ALWAYS_INLINE operator T*() const { return GetForExtraction(); }
- template <typename U>
- explicit ALWAYS_INLINE operator U*() const {
- // This operator may be invoked from static_cast, meaning the types may not
- // be implicitly convertible, hence the need for static_cast here.
- return static_cast<U*>(GetForExtraction());
- }
-
- ALWAYS_INLINE raw_ptr& operator++() {
- wrapped_ptr_ = Impl::Advance(wrapped_ptr_, 1);
- return *this;
- }
- ALWAYS_INLINE raw_ptr& operator--() {
- wrapped_ptr_ = Impl::Advance(wrapped_ptr_, -1);
- return *this;
- }
- ALWAYS_INLINE raw_ptr operator++(int /* post_increment */) {
- raw_ptr result = *this;
- ++(*this);
- return result;
- }
- ALWAYS_INLINE raw_ptr operator--(int /* post_decrement */) {
- raw_ptr result = *this;
- --(*this);
- return result;
- }
- template <typename Z, typename = std::enable_if_t<internal::offset_type<Z>>>
- ALWAYS_INLINE raw_ptr& operator+=(Z delta_elems) {
- wrapped_ptr_ = Impl::Advance(wrapped_ptr_, delta_elems);
- return *this;
- }
- template <typename Z, typename = std::enable_if_t<internal::offset_type<Z>>>
- ALWAYS_INLINE raw_ptr& operator-=(Z delta_elems) {
- return *this += -delta_elems;
- }
-
- template <typename Z, typename = std::enable_if_t<internal::offset_type<Z>>>
- friend ALWAYS_INLINE raw_ptr operator+(const raw_ptr& p, Z delta_elems) {
- raw_ptr result = p;
- return result += delta_elems;
- }
- template <typename Z, typename = std::enable_if_t<internal::offset_type<Z>>>
- friend ALWAYS_INLINE raw_ptr operator-(const raw_ptr& p, Z delta_elems) {
- raw_ptr result = p;
- return result -= delta_elems;
- }
- friend ALWAYS_INLINE ptrdiff_t operator-(const raw_ptr& p1,
- const raw_ptr& p2) {
- return Impl::GetDeltaElems(p1.wrapped_ptr_, p2.wrapped_ptr_);
- }
- friend ALWAYS_INLINE ptrdiff_t operator-(T* p1, const raw_ptr& p2) {
- return Impl::GetDeltaElems(p1, p2.wrapped_ptr_);
- }
- friend ALWAYS_INLINE ptrdiff_t operator-(const raw_ptr& p1, T* p2) {
- return Impl::GetDeltaElems(p1.wrapped_ptr_, p2);
- }
-
- // Stop referencing the underlying pointer and free its memory. Compared to
- // raw delete calls, this avoids the raw_ptr to be temporarily dangling
- // during the free operation, which will lead to taking the slower path that
- // involves quarantine.
- ALWAYS_INLINE void ClearAndDelete() noexcept {
- delete GetForExtractionAndReset();
- }
- ALWAYS_INLINE void ClearAndDeleteArray() noexcept {
- delete[] GetForExtractionAndReset();
- }
-
- // Clear the underlying pointer and return another raw_ptr instance
- // that is allowed to dangle.
- // This can be useful in cases such as:
- // ```
- // ptr.ExtractAsDangling()->SelfDestroy();
- // ```
- // ```
- // c_style_api_do_something_and_destroy(ptr.ExtractAsDangling());
- // ```
- // NOTE, avoid using this method as it indicates an error-prone memory
- // ownership pattern. If possible, use smart pointers like std::unique_ptr<>
- // instead of raw_ptr<>.
- // If you have to use it, avoid saving the return value in a long-lived
- // variable (or worse, a field)! It's meant to be used as a temporary, to be
- // passed into a cleanup & freeing function, and destructed at the end of the
- // statement.
- ALWAYS_INLINE DanglingRawPtr ExtractAsDangling() noexcept {
- if constexpr (std::is_same_v<
- typename std::remove_reference<decltype(*this)>::type,
- DanglingRawPtr>) {
- DanglingRawPtr res(std::move(*this));
- // Not all implementation clear the source pointer on move, so do it
- // here just in case. Should be cheap.
- operator=(nullptr);
- return res;
- } else {
- T* ptr = GetForExtraction();
- DanglingRawPtr res(ptr);
- operator=(nullptr);
- return res;
- }
- }
-
- // Comparison operators between raw_ptr and raw_ptr<U>/U*/std::nullptr_t.
- // Strictly speaking, it is not necessary to provide these: the compiler can
- // use the conversion operator implicitly to allow comparisons to fall back to
- // comparisons between raw pointers. However, `operator T*`/`operator U*` may
- // perform safety checks with a higher runtime cost, so to avoid this, provide
- // explicit comparison operators for all combinations of parameters.
-
- // Comparisons between `raw_ptr`s. This unusual declaration and separate
- // definition below is because `GetForComparison()` is a private method. The
- // more conventional approach of defining a comparison operator between
- // `raw_ptr` and `raw_ptr<U>` in the friend declaration itself does not work,
- // because a comparison operator defined inline would not be allowed to call
- // `raw_ptr<U>`'s private `GetForComparison()` method.
- template <typename U, typename V, typename I>
- friend ALWAYS_INLINE bool operator==(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs);
- template <typename U>
- friend ALWAYS_INLINE bool operator!=(const raw_ptr& lhs,
- const raw_ptr<U, Impl>& rhs) {
- return !(lhs == rhs);
- }
- template <typename U, typename V, typename I>
- friend ALWAYS_INLINE bool operator<(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs);
- template <typename U, typename V, typename I>
- friend ALWAYS_INLINE bool operator>(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs);
- template <typename U, typename V, typename I>
- friend ALWAYS_INLINE bool operator<=(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs);
- template <typename U, typename V, typename I>
- friend ALWAYS_INLINE bool operator>=(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs);
-
- // Comparisons with U*. These operators also handle the case where the RHS is
- // T*.
- template <typename U>
- friend ALWAYS_INLINE bool operator==(const raw_ptr& lhs, U* rhs) {
- return lhs.GetForComparison() == rhs;
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator!=(const raw_ptr& lhs, U* rhs) {
- return !(lhs == rhs);
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator==(U* lhs, const raw_ptr& rhs) {
- return rhs == lhs; // Reverse order to call the operator above.
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator!=(U* lhs, const raw_ptr& rhs) {
- return rhs != lhs; // Reverse order to call the operator above.
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator<(const raw_ptr& lhs, U* rhs) {
- return lhs.GetForComparison() < rhs;
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator<=(const raw_ptr& lhs, U* rhs) {
- return lhs.GetForComparison() <= rhs;
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator>(const raw_ptr& lhs, U* rhs) {
- return lhs.GetForComparison() > rhs;
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator>=(const raw_ptr& lhs, U* rhs) {
- return lhs.GetForComparison() >= rhs;
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator<(U* lhs, const raw_ptr& rhs) {
- return lhs < rhs.GetForComparison();
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator<=(U* lhs, const raw_ptr& rhs) {
- return lhs <= rhs.GetForComparison();
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator>(U* lhs, const raw_ptr& rhs) {
- return lhs > rhs.GetForComparison();
- }
- template <typename U>
- friend ALWAYS_INLINE bool operator>=(U* lhs, const raw_ptr& rhs) {
- return lhs >= rhs.GetForComparison();
- }
-
- // Comparisons with `std::nullptr_t`.
- friend ALWAYS_INLINE bool operator==(const raw_ptr& lhs, std::nullptr_t) {
- return !lhs;
- }
- friend ALWAYS_INLINE bool operator!=(const raw_ptr& lhs, std::nullptr_t) {
- return !!lhs; // Use !! otherwise the costly implicit cast will be used.
- }
- friend ALWAYS_INLINE bool operator==(std::nullptr_t, const raw_ptr& rhs) {
- return !rhs;
- }
- friend ALWAYS_INLINE bool operator!=(std::nullptr_t, const raw_ptr& rhs) {
- return !!rhs; // Use !! otherwise the costly implicit cast will be used.
- }
-
- friend ALWAYS_INLINE void swap(raw_ptr& lhs, raw_ptr& rhs) noexcept {
- Impl::IncrementSwapCountForTest();
- std::swap(lhs.wrapped_ptr_, rhs.wrapped_ptr_);
- }
-
- // If T can be serialised into trace, its alias is also
- // serialisable.
- template <class U = T>
- typename perfetto::check_traced_value_support<U>::type WriteIntoTrace(
- perfetto::TracedValue&& context) const {
- perfetto::WriteIntoTracedValue(std::move(context), get());
- }
-
- ALWAYS_INLINE void ReportIfDangling() const noexcept {
-#if BUILDFLAG(USE_BACKUP_REF_PTR)
- Impl::ReportIfDangling(wrapped_ptr_);
-#endif
- }
-
- private:
- // This getter is meant for situations where the pointer is meant to be
- // dereferenced. It is allowed to crash on nullptr (it may or may not),
- // because it knows that the caller will crash on nullptr.
- ALWAYS_INLINE T* GetForDereference() const {
- return Impl::SafelyUnwrapPtrForDereference(wrapped_ptr_);
- }
- // This getter is meant for situations where the raw pointer is meant to be
- // extracted outside of this class, but not necessarily with an intention to
- // dereference. It mustn't crash on nullptr.
- ALWAYS_INLINE T* GetForExtraction() const {
- return Impl::SafelyUnwrapPtrForExtraction(wrapped_ptr_);
- }
- // This getter is meant *only* for situations where the pointer is meant to be
- // compared (guaranteeing no dereference or extraction outside of this class).
- // Any verifications can and should be skipped for performance reasons.
- ALWAYS_INLINE T* GetForComparison() const {
- return Impl::UnsafelyUnwrapPtrForComparison(wrapped_ptr_);
- }
-
- ALWAYS_INLINE T* GetForExtractionAndReset() {
- T* ptr = GetForExtraction();
- operator=(nullptr);
- return ptr;
- }
-
- T* wrapped_ptr_;
-
- template <typename U, typename V>
- friend class raw_ptr;
-};
-
-template <typename U, typename V, typename I>
-ALWAYS_INLINE bool operator==(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs) {
- return lhs.GetForComparison() == rhs.GetForComparison();
-}
-
-template <typename U, typename V, typename I>
-ALWAYS_INLINE bool operator<(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs) {
- return lhs.GetForComparison() < rhs.GetForComparison();
-}
-
-template <typename U, typename V, typename I>
-ALWAYS_INLINE bool operator>(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs) {
- return lhs.GetForComparison() > rhs.GetForComparison();
-}
-
-template <typename U, typename V, typename I>
-ALWAYS_INLINE bool operator<=(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs) {
- return lhs.GetForComparison() <= rhs.GetForComparison();
-}
-
-template <typename U, typename V, typename I>
-ALWAYS_INLINE bool operator>=(const raw_ptr<U, I>& lhs,
- const raw_ptr<V, I>& rhs) {
- return lhs.GetForComparison() >= rhs.GetForComparison();
-}
-
-template <typename T>
-struct IsRawPtr : std::false_type {};
-
-template <typename T, typename I>
-struct IsRawPtr<raw_ptr<T, I>> : std::true_type {};
-
-template <typename T>
-inline constexpr bool IsRawPtrV = IsRawPtr<T>::value;
-
-// Template helpers for working with T* or raw_ptr<T>.
-template <typename T>
-struct IsPointer : std::false_type {};
-
-template <typename T>
-struct IsPointer<T*> : std::true_type {};
-
-template <typename T, typename I>
-struct IsPointer<raw_ptr<T, I>> : std::true_type {};
-
-template <typename T>
-inline constexpr bool IsPointerV = IsPointer<T>::value;
-
-template <typename T>
-struct RemovePointer {
- using type = T;
-};
-
-template <typename T>
-struct RemovePointer<T*> {
- using type = T;
-};
-
-template <typename T, typename I>
-struct RemovePointer<raw_ptr<T, I>> {
- using type = T;
-};
-
-template <typename T>
-using RemovePointerT = typename RemovePointer<T>::type;
-
-} // namespace base
-
-using gurl_base::raw_ptr;
-
-// DisableDanglingPtrDetection option for raw_ptr annotates
-// "intentional-and-safe" dangling pointers. It is meant to be used at the
-// margin, only if there is no better way to re-architecture the code.
-//
-// Usage:
-// raw_ptr<T, DisableDanglingPtrDetection> dangling_ptr;
-//
-// When using it, please provide a justification about what guarantees it will
-// never be dereferenced after becoming dangling.
-using DisableDanglingPtrDetection = gurl_base::RawPtrMayDangle;
-
-// See `docs/dangling_ptr.md`
-// Annotates known dangling raw_ptr. Those haven't been triaged yet. All the
-// occurrences are meant to be removed. See https://crbug.com/1291138.
-using DanglingUntriaged = DisableDanglingPtrDetection;
-
-// The following template parameters are only meaningful when `raw_ptr`
-// is `MTECheckedPtr` (never the case unless a particular GN arg is set
-// true.) `raw_ptr` users need not worry about this and can refer solely
-// to `DisableDanglingPtrDetection` and `DanglingUntriaged` above.
-//
-// The `raw_ptr` definition allows users to specify an implementation.
-// When `MTECheckedPtr` is in play, we need to augment this
-// implementation setting with another layer that allows the `raw_ptr`
-// to degrade into the no-op version.
-#if defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-
-// Direct pass-through to no-op implementation.
-using DegradeToNoOpWhenMTE = gurl_base::internal::RawPtrNoOpImpl;
-
-// As above, but with the "untriaged dangling" annotation.
-using DanglingUntriagedDegradeToNoOpWhenMTE = gurl_base::internal::RawPtrNoOpImpl;
-
-// As above, but with the "explicitly disable protection" annotation.
-using DisableDanglingPtrDetectionDegradeToNoOpWhenMTE =
- gurl_base::internal::RawPtrNoOpImpl;
-
-#else
-
-// Direct pass-through to default implementation specified by `raw_ptr`
-// template.
-using DegradeToNoOpWhenMTE = gurl_base::RawPtrBanDanglingIfSupported;
-
-// Direct pass-through to `DanglingUntriaged`.
-using DanglingUntriagedDegradeToNoOpWhenMTE = DanglingUntriaged;
-
-// Direct pass-through to `DisableDanglingPtrDetection`.
-using DisableDanglingPtrDetectionDegradeToNoOpWhenMTE =
- DisableDanglingPtrDetection;
-
-#endif // defined(PA_ENABLE_MTE_CHECKED_PTR_SUPPORT_WITH_64_BITS_POINTERS)
-
-namespace std {
-
-// Override so set/map lookups do not create extra raw_ptr. This also allows
-// dangling pointers to be used for lookup.
-template <typename T, typename RawPtrType>
-struct less<raw_ptr<T, RawPtrType>> {
- using Impl =
- typename gurl_base::raw_ptr_traits::RawPtrTypeToImpl<RawPtrType>::Impl;
- using is_transparent = void;
-
- bool operator()(const raw_ptr<T, RawPtrType>& lhs,
- const raw_ptr<T, RawPtrType>& rhs) const {
- Impl::IncrementLessCountForTest();
- return lhs < rhs;
- }
-
- bool operator()(T* lhs, const raw_ptr<T, RawPtrType>& rhs) const {
- Impl::IncrementLessCountForTest();
- return lhs < rhs;
- }
-
- bool operator()(const raw_ptr<T, RawPtrType>& lhs, T* rhs) const {
- Impl::IncrementLessCountForTest();
- return lhs < rhs;
- }
-};
-
-// Define for cases where raw_ptr<T> holds a pointer to an array of type T.
-// This is consistent with definition of std::iterator_traits<T*>.
-// Algorithms like std::binary_search need that.
-template <typename T, typename Impl>
-struct iterator_traits<raw_ptr<T, Impl>> {
- using difference_type = ptrdiff_t;
- using value_type = std::remove_cv_t<T>;
- using pointer = T*;
- using reference = T&;
- using iterator_category = std::random_access_iterator_tag;
-};
-
-} // namespace std
-
-#endif // BASE_MEMORY_RAW_PTR_H_
diff --git a/base/memory/raw_ptr_exclusion.h b/base/memory/raw_ptr_exclusion.h
index f881c04..2a30e26 100644
--- a/base/memory/raw_ptr_exclusion.h
+++ b/base/memory/raw_ptr_exclusion.h
@@ -6,8 +6,10 @@
#define BASE_MEMORY_RAW_PTR_EXCLUSION_H_
#include "polyfills/base/allocator/buildflags.h"
+#include "base/compiler_specific.h"
#include "build/build_config.h"
+#if HAS_ATTRIBUTE(annotate)
#if defined(OFFICIAL_BUILD) && !BUILDFLAG(FORCE_ENABLE_RAW_PTR_EXCLUSION)
// The annotation changed compiler output and increased binary size so disable
// for official builds.
@@ -18,5 +20,8 @@
// Example: RAW_PTR_EXCLUSION Foo* foo_;
#define RAW_PTR_EXCLUSION __attribute__((annotate("raw_ptr_exclusion")))
#endif
+#else
+#define RAW_PTR_EXCLUSION
+#endif
#endif // BASE_MEMORY_RAW_PTR_EXCLUSION_H_
diff --git a/base/no_destructor.h b/base/no_destructor.h
index b183e4f..d2bb766 100644
--- a/base/no_destructor.h
+++ b/base/no_destructor.h
@@ -10,28 +10,50 @@
#include <utility>
namespace gurl_base {
-// A tag type used for NoDestructor to allow it to be created for a type that
-// has a trivial destructor. Use for cases where the same class might have
-// different implementations that vary on destructor triviality or when the
-// LSan hiding properties of NoDestructor are needed.
-struct AllowForTriviallyDestructibleType;
-// A wrapper that makes it easy to create an object of type T with static
-// storage duration that:
-// - is only constructed on first access
-// - never invokes the destructor
-// in order to satisfy the styleguide ban on global constructors and
-// destructors.
+// Helper type to create a function-local static variable of type `T` when `T`
+// has a non-trivial destructor. Storing a `T` in a `gurl_base::NoDestructor<T>` will
+// prevent `~T()` from running, even when the variable goes out of scope.
//
-// Runtime constant example:
-// const std::string& GetLineSeparator() {
-// // Forwards to std::string(size_t, char, const Allocator&) constructor.
-// static const gurl_base::NoDestructor<std::string> s(5, '-');
+// Useful when a variable has static storage duration but its type has a
+// non-trivial destructor. Chromium bans global constructors and destructors:
+// using a function-local static variable prevents the former, while using
+// `gurl_base::NoDestructor<T>` prevents the latter.
+//
+// ## Caveats
+//
+// - Must only be used as a function-local static variable. Declaring a global
+// variable of type `gurl_base::NoDestructor<T>` will still generate a global
+// constructor; declaring a local or member variable will lead to memory leaks
+// or other surprising and undesirable behaviour.
+//
+// - If the data is rarely used, consider creating it on demand rather than
+// caching it for the lifetime of the program. Though `gurl_base::NoDestructor<T>`
+// does not heap allocate, the compiler still reserves space in bss for
+// storing `T`, which costs memory at runtime.
+//
+// - If `T` is trivially destructible, do not use `gurl_base::NoDestructor<T>`:
+//
+// const uint64_t GetUnstableSessionSeed() {
+// // No need to use `gurl_base::NoDestructor<T>` as `uint64_t` is trivially
+// // destructible and does not require a global destructor.
+// static const uint64_t kSessionSeed = gurl_base::RandUint64();
+// return kSessionSeed;
+// }
+//
+// ## Example Usage
+//
+// const std::string& GetDefaultText() {
+// // Required since `static const std::string` requires a global destructor.
+// static const gurl_base::NoDestructor<std::string> s("Hello world!");
// return *s;
// }
//
-// More complex initialization with a lambda:
-// const std::string& GetSessionNonce() {
+// More complex initialization using a lambda:
+//
+// const std::string& GetRandomNonce() {
+// // `nonce` is initialized with random data the first time this function is
+// // called, but its value is fixed thereafter.
// static const gurl_base::NoDestructor<std::string> nonce([] {
// std::string s(16);
// crypto::RandString(s.data(), s.size());
@@ -40,29 +62,24 @@
// return *nonce;
// }
//
-// NoDestructor<T> stores the object inline, so it also avoids a pointer
-// indirection and a malloc. Also note that since C++11 static local variable
-// initialization is thread-safe and so is this pattern. Code should prefer to
-// use NoDestructor<T> over:
-// - A function scoped static T* or T& that is dynamically initialized.
-// - A global gurl_base::LazyInstance<T>.
+// ## Thread safety
//
-// Note that since the destructor is never run, this *will* leak memory if used
-// as a stack or member variable. Furthermore, a NoDestructor<T> should never
-// have global scope as that may require a static initializer.
-template <typename T, typename O = std::nullptr_t>
+// Initialisation of function-local static variables is thread-safe since C++11.
+// The standard guarantees that:
+//
+// - function-local static variables will be initialised the first time
+// execution passes through the declaration.
+//
+// - if another thread's execution concurrently passes through the declaration
+// in the middle of initialisation, that thread will wait for the in-progress
+// initialisation to complete.
+template <typename T>
class NoDestructor {
public:
static_assert(
- !std::is_trivially_destructible<T>::value ||
- std::is_same<O, AllowForTriviallyDestructibleType>::value,
- "gurl_base::NoDestructor is not needed because the templated class has a "
- "trivial destructor");
-
- static_assert(std::is_same<O, AllowForTriviallyDestructibleType>::value ||
- std::is_same<O, std::nullptr_t>::value,
- "AllowForTriviallyDestructibleType is the only valid option "
- "for the second template parameter of NoDestructor");
+ !std::is_trivially_destructible_v<T>,
+ "T is trivially destructible; please use a function-local static "
+ "of type T directly instead");
// Not constexpr; just write static constexpr T x = ...; if the value should
// be a constexpr.
diff --git a/base/stl_util.h b/base/stl_util.h
index 74ce611..2511412 100644
--- a/base/stl_util.h
+++ b/base/stl_util.h
@@ -26,17 +26,6 @@
} // namespace internal
-// Implementation of C++23's std::to_underlying.
-//
-// Note: This has an additional `std::is_enum<EnumT>` requirement to be SFINAE
-// friendly prior to C++20.
-//
-// Reference: https://en.cppreference.com/w/cpp/utility/to_underlying
-template <typename EnumT, typename = std::enable_if_t<std::is_enum<EnumT>{}>>
-constexpr std::underlying_type_t<EnumT> to_underlying(EnumT e) noexcept {
- return static_cast<std::underlying_type_t<EnumT>>(e);
-}
-
// Returns a const reference to the underlying container of a container adapter.
// Works for std::priority_queue, std::queue, and std::stack.
template <class A>
@@ -59,14 +48,6 @@
obj->reserve(0);
}
-// Counts the number of instances of val in a container.
-template <typename Container, typename T>
-typename std::iterator_traits<
- typename Container::const_iterator>::difference_type
-STLCount(const Container& container, const T& val) {
- return std::count(container.begin(), container.end(), val);
-}
-
// O(1) implementation of const casting an iterator for any sequence,
// associative or unordered associative container in the STL.
//
diff --git a/base/strings/escape.cc b/base/strings/escape.cc
index 96657a3..d855c1c 100644
--- a/base/strings/escape.cc
+++ b/base/strings/escape.cc
@@ -49,7 +49,7 @@
bool keep_escaped = false) {
std::string escaped;
escaped.reserve(text.length() * 3);
- for (unsigned int i = 0; i < text.length(); ++i) {
+ for (size_t i = 0; i < text.length(); ++i) {
unsigned char c = static_cast<unsigned char>(text[i]);
if (use_plus && ' ' == c) {
escaped.push_back('+');
diff --git a/base/strings/safe_sprintf.cc b/base/strings/safe_sprintf.cc
index 5071377..0b53dff 100644
--- a/base/strings/safe_sprintf.cc
+++ b/base/strings/safe_sprintf.cc
@@ -10,7 +10,7 @@
#include <algorithm>
#include <limits>
-#include "base/memory/raw_ptr.h"
+#include "polyfills/base/memory/raw_ptr.h"
#include "build/build_config.h"
#if !defined(NDEBUG)
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc
index bdcc2ff..76d72b2 100644
--- a/base/strings/safe_sprintf_unittest.cc
+++ b/base/strings/safe_sprintf_unittest.cc
@@ -12,6 +12,7 @@
#include <limits>
#include <memory>
+
#include "polyfills/base/check_op.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -482,7 +483,14 @@
} // anonymous namespace
-TEST(SafeSPrintfTest, Truncation) {
+// TODO(crbug.com/1369007): Fails when OOB protection is turned on.
+#if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) || \
+ BUILDFLAG(ENABLE_MTE_CHECKED_PTR_SUPPORT)
+#define MAYBE_Truncation DISABLED_Truncation
+#else
+#define MAYBE_Truncation Truncation
+#endif
+TEST(SafeSPrintfTest, MAYBE_Truncation) {
// We use PrintLongString() to print a complex long string and then
// truncate to all possible lengths. This ends up exercising a lot of
// different code paths in SafeSPrintf() and IToASCII(), as truncation can
diff --git a/base/strings/string_number_conversions_fuzzer.cc b/base/strings/string_number_conversions_fuzzer.cc
deleted file mode 100644
index cea3d3c..0000000
--- a/base/strings/string_number_conversions_fuzzer.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/strings/string_number_conversions.h"
-
-template <class NumberType, class StringPieceType, class StringType>
-void CheckRoundtripsT(const uint8_t* data,
- const size_t size,
- StringType (*num_to_string)(NumberType),
- bool (*string_to_num)(StringPieceType, NumberType*)) {
- // Ensure we can read a NumberType from |data|
- if (size < sizeof(NumberType))
- return;
- const NumberType v1 = *reinterpret_cast<const NumberType*>(data);
-
- // Because we started with an arbitrary NumberType value, not an arbitrary
- // string, we expect that the function |string_to_num| (e.g. StringToInt) will
- // return true, indicating a perfect conversion.
- NumberType v2;
- GURL_CHECK(string_to_num(num_to_string(v1), &v2));
-
- // Given that this was a perfect conversion, we expect the original NumberType
- // value to equal the newly parsed one.
- GURL_CHECK_EQ(v1, v2);
-}
-
-template <class NumberType>
-void CheckRoundtrips(const uint8_t* data,
- const size_t size,
- bool (*string_to_num)(gurl_base::StringPiece, NumberType*)) {
- return CheckRoundtripsT<NumberType, gurl_base::StringPiece, std::string>(
- data, size, &gurl_base::NumberToString, string_to_num);
-}
-
-template <class NumberType>
-void CheckRoundtrips16(const uint8_t* data,
- const size_t size,
- bool (*string_to_num)(gurl_base::StringPiece16,
- NumberType*)) {
- return CheckRoundtripsT<NumberType, gurl_base::StringPiece16, std::u16string>(
- data, size, &gurl_base::NumberToString16, string_to_num);
-}
-
-// Entry point for LibFuzzer.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- // For each instantiation of NumberToString f and its corresponding StringTo*
- // function g, check that f(g(x)) = x holds for fuzzer-determined values of x.
- CheckRoundtrips<int>(data, size, &gurl_base::StringToInt);
- CheckRoundtrips16<int>(data, size, &gurl_base::StringToInt);
- CheckRoundtrips<unsigned int>(data, size, &gurl_base::StringToUint);
- CheckRoundtrips16<unsigned int>(data, size, &gurl_base::StringToUint);
- CheckRoundtrips<int64_t>(data, size, &gurl_base::StringToInt64);
- CheckRoundtrips16<int64_t>(data, size, &gurl_base::StringToInt64);
- CheckRoundtrips<uint64_t>(data, size, &gurl_base::StringToUint64);
- CheckRoundtrips16<uint64_t>(data, size, &gurl_base::StringToUint64);
- CheckRoundtrips<size_t>(data, size, &gurl_base::StringToSizeT);
- CheckRoundtrips16<size_t>(data, size, &gurl_base::StringToSizeT);
-
- gurl_base::StringPiece string_piece_input(reinterpret_cast<const char*>(data),
- size);
- std::string string_input(reinterpret_cast<const char*>(data), size);
-
- int out_int;
- gurl_base::StringToInt(string_piece_input, &out_int);
- unsigned out_uint;
- gurl_base::StringToUint(string_piece_input, &out_uint);
- int64_t out_int64;
- gurl_base::StringToInt64(string_piece_input, &out_int64);
- uint64_t out_uint64;
- gurl_base::StringToUint64(string_piece_input, &out_uint64);
- size_t out_size;
- gurl_base::StringToSizeT(string_piece_input, &out_size);
-
- // Test for StringPiece16 if size is even.
- if (size % 2 == 0) {
- gurl_base::StringPiece16 string_piece_input16(
- reinterpret_cast<const char16_t*>(data), size / 2);
-
- gurl_base::StringToInt(string_piece_input16, &out_int);
- gurl_base::StringToUint(string_piece_input16, &out_uint);
- gurl_base::StringToInt64(string_piece_input16, &out_int64);
- gurl_base::StringToUint64(string_piece_input16, &out_uint64);
- gurl_base::StringToSizeT(string_piece_input16, &out_size);
- }
-
- double out_double;
- gurl_base::StringToDouble(string_input, &out_double);
-
- gurl_base::HexStringToInt(string_piece_input, &out_int);
- gurl_base::HexStringToUInt(string_piece_input, &out_uint);
- gurl_base::HexStringToInt64(string_piece_input, &out_int64);
- gurl_base::HexStringToUInt64(string_piece_input, &out_uint64);
- std::vector<uint8_t> out_bytes;
- gurl_base::HexStringToBytes(string_piece_input, &out_bytes);
-
- gurl_base::HexEncode(data, size);
-
- // Convert the numbers back to strings.
- gurl_base::NumberToString(out_int);
- gurl_base::NumberToString16(out_int);
- gurl_base::NumberToString(out_uint);
- gurl_base::NumberToString16(out_uint);
- gurl_base::NumberToString(out_int64);
- gurl_base::NumberToString16(out_int64);
- gurl_base::NumberToString(out_uint64);
- gurl_base::NumberToString16(out_uint64);
- gurl_base::NumberToString(out_double);
- gurl_base::NumberToString16(out_double);
-
- return 0;
-}
diff --git a/base/strings/string_tokenizer_fuzzer.cc b/base/strings/string_tokenizer_fuzzer.cc
deleted file mode 100644
index a0c0788..0000000
--- a/base/strings/string_tokenizer_fuzzer.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-#include <tuple>
-
-#include "base/strings/string_tokenizer.h"
-
-void GetAllTokens(gurl_base::StringTokenizer& t) {
- while (t.GetNext()) {
- std::ignore = t.token();
- }
-}
-
-// Entry point for LibFuzzer.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- uint8_t size_t_bytes = sizeof(size_t);
- if (size < size_t_bytes + 1) {
- return 0;
- }
-
- // Calculate pattern size based on remaining bytes, otherwise fuzzing is
- // inefficient with bailouts in most cases.
- size_t pattern_size =
- *reinterpret_cast<const size_t*>(data) % (size - size_t_bytes);
-
- std::string pattern(reinterpret_cast<const char*>(data + size_t_bytes),
- pattern_size);
- std::string input(
- reinterpret_cast<const char*>(data + size_t_bytes + pattern_size),
- size - pattern_size - size_t_bytes);
-
- // Allow quote_chars and options to be set. Otherwise full coverage
- // won't be possible since IsQuote, FullGetNext and other functions
- // won't be called.
- for (bool return_delims : {false, true}) {
- for (bool return_empty_strings : {false, true}) {
- int options = 0;
- if (return_delims)
- options |= gurl_base::StringTokenizer::RETURN_DELIMS;
- if (return_empty_strings)
- options |= gurl_base::StringTokenizer::RETURN_EMPTY_TOKENS;
-
- gurl_base::StringTokenizer t(input, pattern);
- t.set_options(options);
- GetAllTokens(t);
-
- gurl_base::StringTokenizer t_quote(input, pattern);
- t_quote.set_quote_chars("\"");
- t_quote.set_options(options);
- GetAllTokens(t_quote);
- }
- }
-
- return 0;
-}
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 482bb6e..f92029f 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -16,13 +16,14 @@
#include <wchar.h>
#include <wctype.h>
-#include <algorithm>
#include <limits>
#include <type_traits>
#include <vector>
#include "polyfills/base/check_op.h"
#include "base/no_destructor.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_util_impl_helpers.h"
#include "base/strings/string_util_internal.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "base/strings/utf_string_conversions.h"
@@ -82,14 +83,6 @@
return internal::ToUpperASCIIImpl(str);
}
-int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
- return internal::CompareCaseInsensitiveASCIIT(a, b);
-}
-
-int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
- return internal::CompareCaseInsensitiveASCIIT(a, b);
-}
-
const std::string& EmptyString() {
static const gurl_base::NoDestructor<std::string> s;
return *s;
@@ -256,7 +249,7 @@
}
bool EqualsASCII(StringPiece16 str, StringPiece ascii) {
- return std::equal(ascii.begin(), ascii.end(), str.begin(), str.end());
+ return ranges::equal(ascii, str);
}
bool StartsWith(StringPiece str,
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 56cf483..b7bee67 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -12,7 +12,6 @@
#include <stddef.h>
#include <stdint.h>
-#include <algorithm>
#include <initializer_list>
#include <sstream>
#include <string>
@@ -25,6 +24,7 @@
#include "base/containers/span.h"
#include "base/cxx20_to_address.h"
#include "base/strings/string_piece.h" // For implicit conversions.
+#include "base/strings/string_util_internal.h"
#include "build/build_config.h"
namespace gurl_base {
@@ -123,8 +123,8 @@
// so we don't want to use it here.
template <typename CharT,
typename = std::enable_if_t<std::is_integral<CharT>::value>>
-CharT ToLowerASCII(CharT c) {
- return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+constexpr CharT ToLowerASCII(CharT c) {
+ return internal::ToLowerASCII(c);
}
// ASCII-specific toupper. The standard library's toupper is locale sensitive,
@@ -165,19 +165,14 @@
// (unlike strcasecmp which can return values greater or less than 1/-1). For
// full Unicode support, use gurl_base::i18n::ToLower or gurl_base::i18n::FoldCase
// and then just call the normal string operators on the result.
-BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b);
-BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
-
-namespace internal {
-template <typename CharT, typename CharU>
-inline bool EqualsCaseInsensitiveASCIIT(BasicStringPiece<CharT> a,
- BasicStringPiece<CharU> b) {
- return std::equal(a.begin(), a.end(), b.begin(), b.end(),
- [](auto lhs, auto rhs) {
- return ToLowerASCII(lhs) == ToLowerASCII(rhs);
- });
+BASE_EXPORT constexpr int CompareCaseInsensitiveASCII(StringPiece a,
+ StringPiece b) {
+ return internal::CompareCaseInsensitiveASCIIT(a, b);
}
-} // namespace internal
+BASE_EXPORT constexpr int CompareCaseInsensitiveASCII(StringPiece16 a,
+ StringPiece16 b) {
+ return internal::CompareCaseInsensitiveASCIIT(a, b);
+}
// Equality for ASCII case-insensitive comparisons. For full Unicode support,
// use gurl_base::i18n::ToLower or gurl_base::i18n::FoldCase and then compare with either
diff --git a/base/strings/string_util_impl_helpers.h b/base/strings/string_util_impl_helpers.h
new file mode 100644
index 0000000..970a912
--- /dev/null
+++ b/base/strings/string_util_impl_helpers.h
@@ -0,0 +1,582 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_UTIL_IMPL_HELPERS_H_
+#define BASE_STRINGS_STRING_UTIL_IMPL_HELPERS_H_
+
+#include <algorithm>
+
+#include "polyfills/base/check.h"
+#include "polyfills/base/check_op.h"
+#include "polyfills/base/logging.h"
+#include "polyfills/base/notreached.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_piece.h"
+#include "base/third_party/icu/icu_utf.h"
+
+namespace gurl_base::internal {
+
+// Used by ReplaceStringPlaceholders to track the position in the string of
+// replaced parameters.
+struct ReplacementOffset {
+ ReplacementOffset(uintptr_t parameter, size_t offset)
+ : parameter(parameter), offset(offset) {}
+
+ // Index of the parameter.
+ size_t parameter;
+
+ // Starting position in the string.
+ size_t offset;
+};
+
+static bool CompareParameter(const ReplacementOffset& elem1,
+ const ReplacementOffset& elem2) {
+ return elem1.parameter < elem2.parameter;
+}
+
+// Assuming that a pointer is the size of a "machine word", then
+// uintptr_t is an integer type that is also a machine word.
+using MachineWord = uintptr_t;
+
+inline bool IsMachineWordAligned(const void* pointer) {
+ return !(reinterpret_cast<MachineWord>(pointer) & (sizeof(MachineWord) - 1));
+}
+
+template <typename T, typename CharT = typename T::value_type>
+std::basic_string<CharT> ToLowerASCIIImpl(T str) {
+ std::basic_string<CharT> ret;
+ ret.reserve(str.size());
+ for (size_t i = 0; i < str.size(); i++)
+ ret.push_back(ToLowerASCII(str[i]));
+ return ret;
+}
+
+template <typename T, typename CharT = typename T::value_type>
+std::basic_string<CharT> ToUpperASCIIImpl(T str) {
+ std::basic_string<CharT> ret;
+ ret.reserve(str.size());
+ for (size_t i = 0; i < str.size(); i++)
+ ret.push_back(ToUpperASCII(str[i]));
+ return ret;
+}
+
+template <typename T, typename CharT = typename T::value_type>
+TrimPositions TrimStringT(T input,
+ T trim_chars,
+ TrimPositions positions,
+ std::basic_string<CharT>* output) {
+ // Find the edges of leading/trailing whitespace as desired. Need to use
+ // a StringPiece version of input to be able to call find* on it with the
+ // StringPiece version of trim_chars (normally the trim_chars will be a
+ // constant so avoid making a copy).
+ const size_t last_char = input.length() - 1;
+ const size_t first_good_char =
+ (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
+ const size_t last_good_char = (positions & TRIM_TRAILING)
+ ? input.find_last_not_of(trim_chars)
+ : last_char;
+
+ // When the string was all trimmed, report that we stripped off characters
+ // from whichever position the caller was interested in. For empty input, we
+ // stripped no characters, but we still need to clear |output|.
+ if (input.empty() || first_good_char == std::basic_string<CharT>::npos ||
+ last_good_char == std::basic_string<CharT>::npos) {
+ bool input_was_empty = input.empty(); // in case output == &input
+ output->clear();
+ return input_was_empty ? TRIM_NONE : positions;
+ }
+
+ // Trim.
+ output->assign(input.data() + first_good_char,
+ last_good_char - first_good_char + 1);
+
+ // Return where we trimmed from.
+ return static_cast<TrimPositions>(
+ (first_good_char == 0 ? TRIM_NONE : TRIM_LEADING) |
+ (last_good_char == last_char ? TRIM_NONE : TRIM_TRAILING));
+}
+
+template <typename T, typename CharT = typename T::value_type>
+T TrimStringPieceT(T input, T trim_chars, TrimPositions positions) {
+ size_t begin =
+ (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
+ size_t end = (positions & TRIM_TRAILING)
+ ? input.find_last_not_of(trim_chars) + 1
+ : input.size();
+ return input.substr(std::min(begin, input.size()), end - begin);
+}
+
+template <typename T, typename CharT = typename T::value_type>
+std::basic_string<CharT> CollapseWhitespaceT(
+ T text,
+ bool trim_sequences_with_line_breaks) {
+ std::basic_string<CharT> result;
+ result.resize(text.size());
+
+ // Set flags to pretend we're already in a trimmed whitespace sequence, so we
+ // will trim any leading whitespace.
+ bool in_whitespace = true;
+ bool already_trimmed = true;
+
+ size_t chars_written = 0;
+ for (auto c : text) {
+ if (IsWhitespace(c)) {
+ if (!in_whitespace) {
+ // Reduce all whitespace sequences to a single space.
+ in_whitespace = true;
+ result[chars_written++] = L' ';
+ }
+ if (trim_sequences_with_line_breaks && !already_trimmed &&
+ ((c == '\n') || (c == '\r'))) {
+ // Whitespace sequences containing CR or LF are eliminated entirely.
+ already_trimmed = true;
+ --chars_written;
+ }
+ } else {
+ // Non-whitespace characters are copied straight across.
+ in_whitespace = false;
+ already_trimmed = false;
+ result[chars_written++] = c;
+ }
+ }
+
+ if (in_whitespace && !already_trimmed) {
+ // Any trailing whitespace is eliminated.
+ --chars_written;
+ }
+
+ result.resize(chars_written);
+ return result;
+}
+
+template <class Char>
+bool DoIsStringASCII(const Char* characters, size_t length) {
+ // Bitmasks to detect non ASCII characters for character sizes of 8, 16 and 32
+ // bits.
+ constexpr MachineWord NonASCIIMasks[] = {
+ 0, MachineWord(0x8080808080808080ULL), MachineWord(0xFF80FF80FF80FF80ULL),
+ 0, MachineWord(0xFFFFFF80FFFFFF80ULL),
+ };
+
+ if (!length)
+ return true;
+ constexpr MachineWord non_ascii_bit_mask = NonASCIIMasks[sizeof(Char)];
+ static_assert(non_ascii_bit_mask, "Error: Invalid Mask");
+ MachineWord all_char_bits = 0;
+ const Char* end = characters + length;
+
+ // Prologue: align the input.
+ while (!IsMachineWordAligned(characters) && characters < end)
+ all_char_bits |= static_cast<MachineWord>(*characters++);
+ if (all_char_bits & non_ascii_bit_mask)
+ return false;
+
+ // Compare the values of CPU word size.
+ constexpr size_t chars_per_word = sizeof(MachineWord) / sizeof(Char);
+ constexpr int batch_count = 16;
+ while (characters <= end - batch_count * chars_per_word) {
+ all_char_bits = 0;
+ for (int i = 0; i < batch_count; ++i) {
+ all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
+ characters += chars_per_word;
+ }
+ if (all_char_bits & non_ascii_bit_mask)
+ return false;
+ }
+
+ // Process the remaining words.
+ all_char_bits = 0;
+ while (characters <= end - chars_per_word) {
+ all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
+ characters += chars_per_word;
+ }
+
+ // Process the remaining bytes.
+ while (characters < end)
+ all_char_bits |= static_cast<MachineWord>(*characters++);
+
+ return !(all_char_bits & non_ascii_bit_mask);
+}
+
+template <bool (*Validator)(base_icu::UChar32)>
+inline bool DoIsStringUTF8(StringPiece str) {
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(str.data());
+ size_t src_len = str.length();
+ size_t char_index = 0;
+
+ while (char_index < src_len) {
+ base_icu::UChar32 code_point;
+ CBU8_NEXT(src, char_index, src_len, code_point);
+ if (!Validator(code_point))
+ return false;
+ }
+ return true;
+}
+
+template <typename T, typename CharT = typename T::value_type>
+bool StartsWithT(T str, T search_for, CompareCase case_sensitivity) {
+ if (search_for.size() > str.size())
+ return false;
+
+ BasicStringPiece<CharT> source = str.substr(0, search_for.size());
+
+ switch (case_sensitivity) {
+ case CompareCase::SENSITIVE:
+ return source == search_for;
+
+ case CompareCase::INSENSITIVE_ASCII:
+ return std::equal(search_for.begin(), search_for.end(), source.begin(),
+ CaseInsensitiveCompareASCII<CharT>());
+
+ default:
+ GURL_NOTREACHED();
+ return false;
+ }
+}
+
+template <typename T, typename CharT = typename T::value_type>
+bool EndsWithT(T str, T search_for, CompareCase case_sensitivity) {
+ if (search_for.size() > str.size())
+ return false;
+
+ BasicStringPiece<CharT> source =
+ str.substr(str.size() - search_for.size(), search_for.size());
+
+ switch (case_sensitivity) {
+ case CompareCase::SENSITIVE:
+ return source == search_for;
+
+ case CompareCase::INSENSITIVE_ASCII:
+ return std::equal(source.begin(), source.end(), search_for.begin(),
+ CaseInsensitiveCompareASCII<CharT>());
+
+ default:
+ GURL_NOTREACHED();
+ return false;
+ }
+}
+
+// A Matcher for DoReplaceMatchesAfterOffset() that matches substrings.
+template <class CharT>
+struct SubstringMatcher {
+ BasicStringPiece<CharT> find_this;
+
+ size_t Find(const std::basic_string<CharT>& input, size_t pos) {
+ return input.find(find_this.data(), pos, find_this.length());
+ }
+ size_t MatchSize() { return find_this.length(); }
+};
+
+// Type deduction helper for SubstringMatcher.
+template <typename T, typename CharT = typename T::value_type>
+auto MakeSubstringMatcher(T find_this) {
+ return SubstringMatcher<CharT>{find_this};
+}
+
+// A Matcher for DoReplaceMatchesAfterOffset() that matches single characters.
+template <class CharT>
+struct CharacterMatcher {
+ BasicStringPiece<CharT> find_any_of_these;
+
+ size_t Find(const std::basic_string<CharT>& input, size_t pos) {
+ return input.find_first_of(find_any_of_these.data(), pos,
+ find_any_of_these.length());
+ }
+ constexpr size_t MatchSize() { return 1; }
+};
+
+// Type deduction helper for CharacterMatcher.
+template <typename T, typename CharT = typename T::value_type>
+auto MakeCharacterMatcher(T find_any_of_these) {
+ return CharacterMatcher<CharT>{find_any_of_these};
+}
+
+enum class ReplaceType { REPLACE_ALL, REPLACE_FIRST };
+
+// Runs in O(n) time in the length of |str|, and transforms the string without
+// reallocating when possible. Returns |true| if any matches were found.
+//
+// This is parameterized on a |Matcher| traits type, so that it can be the
+// implementation for both ReplaceChars() and ReplaceSubstringsAfterOffset().
+template <typename Matcher, typename T, typename CharT = typename T::value_type>
+bool DoReplaceMatchesAfterOffset(std::basic_string<CharT>* str,
+ size_t initial_offset,
+ Matcher matcher,
+ T replace_with,
+ ReplaceType replace_type) {
+ using CharTraits = std::char_traits<CharT>;
+
+ const size_t find_length = matcher.MatchSize();
+ if (!find_length)
+ return false;
+
+ // If the find string doesn't appear, there's nothing to do.
+ size_t first_match = matcher.Find(*str, initial_offset);
+ if (first_match == std::basic_string<CharT>::npos)
+ return false;
+
+ // If we're only replacing one instance, there's no need to do anything
+ // complicated.
+ const size_t replace_length = replace_with.length();
+ if (replace_type == ReplaceType::REPLACE_FIRST) {
+ str->replace(first_match, find_length, replace_with.data(), replace_length);
+ return true;
+ }
+
+ // If the find and replace strings are the same length, we can simply use
+ // replace() on each instance, and finish the entire operation in O(n) time.
+ if (find_length == replace_length) {
+ auto* buffer = &((*str)[0]);
+ for (size_t offset = first_match; offset != std::basic_string<CharT>::npos;
+ offset = matcher.Find(*str, offset + replace_length)) {
+ CharTraits::copy(buffer + offset, replace_with.data(), replace_length);
+ }
+ return true;
+ }
+
+ // Since the find and replace strings aren't the same length, a loop like the
+ // one above would be O(n^2) in the worst case, as replace() will shift the
+ // entire remaining string each time. We need to be more clever to keep things
+ // O(n).
+ //
+ // When the string is being shortened, it's possible to just shift the matches
+ // down in one pass while finding, and truncate the length at the end of the
+ // search.
+ //
+ // If the string is being lengthened, more work is required. The strategy used
+ // here is to make two find() passes through the string. The first pass counts
+ // the number of matches to determine the new size. The second pass will
+ // either construct the new string into a new buffer (if the existing buffer
+ // lacked capacity), or else -- if there is room -- create a region of scratch
+ // space after |first_match| by shifting the tail of the string to a higher
+ // index, and doing in-place moves from the tail to lower indices thereafter.
+ size_t str_length = str->length();
+ size_t expansion = 0;
+ if (replace_length > find_length) {
+ // This operation lengthens the string; determine the new length by counting
+ // matches.
+ const size_t expansion_per_match = (replace_length - find_length);
+ size_t num_matches = 0;
+ for (size_t match = first_match; match != std::basic_string<CharT>::npos;
+ match = matcher.Find(*str, match + find_length)) {
+ expansion += expansion_per_match;
+ ++num_matches;
+ }
+ const size_t final_length = str_length + expansion;
+
+ if (str->capacity() < final_length) {
+ // If we'd have to allocate a new buffer to grow the string, build the
+ // result directly into the new allocation via append().
+ std::basic_string<CharT> src(str->get_allocator());
+ str->swap(src);
+ str->reserve(final_length);
+
+ size_t pos = 0;
+ for (size_t match = first_match;; match = matcher.Find(src, pos)) {
+ str->append(src, pos, match - pos);
+ str->append(replace_with.data(), replace_length);
+ pos = match + find_length;
+
+ // A mid-loop test/break enables skipping the final Find() call; the
+ // number of matches is known, so don't search past the last one.
+ if (!--num_matches)
+ break;
+ }
+
+ // Handle substring after the final match.
+ str->append(src, pos, str_length - pos);
+ return true;
+ }
+
+ // Prepare for the copy/move loop below -- expand the string to its final
+ // size by shifting the data after the first match to the end of the resized
+ // string.
+ size_t shift_src = first_match + find_length;
+ size_t shift_dst = shift_src + expansion;
+
+ // Big |expansion| factors (relative to |str_length|) require padding up to
+ // |shift_dst|.
+ if (shift_dst > str_length)
+ str->resize(shift_dst);
+
+ str->replace(shift_dst, str_length - shift_src, *str, shift_src,
+ str_length - shift_src);
+ str_length = final_length;
+ }
+
+ // We can alternate replacement and move operations. This won't overwrite the
+ // unsearched region of the string so long as |write_offset| <= |read_offset|;
+ // that condition is always satisfied because:
+ //
+ // (a) If the string is being shortened, |expansion| is zero and
+ // |write_offset| grows slower than |read_offset|.
+ //
+ // (b) If the string is being lengthened, |write_offset| grows faster than
+ // |read_offset|, but |expansion| is big enough so that |write_offset|
+ // will only catch up to |read_offset| at the point of the last match.
+ auto* buffer = &((*str)[0]);
+ size_t write_offset = first_match;
+ size_t read_offset = first_match + expansion;
+ do {
+ if (replace_length) {
+ CharTraits::copy(buffer + write_offset, replace_with.data(),
+ replace_length);
+ write_offset += replace_length;
+ }
+ read_offset += find_length;
+
+ // min() clamps std::basic_string<CharT>::npos (the largest unsigned value)
+ // to str_length.
+ size_t match = std::min(matcher.Find(*str, read_offset), str_length);
+
+ size_t length = match - read_offset;
+ if (length) {
+ CharTraits::move(buffer + write_offset, buffer + read_offset, length);
+ write_offset += length;
+ read_offset += length;
+ }
+ } while (read_offset < str_length);
+
+ // If we're shortening the string, truncate it now.
+ str->resize(write_offset);
+ return true;
+}
+
+template <typename T, typename CharT = typename T::value_type>
+bool ReplaceCharsT(T input,
+ T find_any_of_these,
+ T replace_with,
+ std::basic_string<CharT>* output) {
+ // Commonly, this is called with output and input being the same string; in
+ // that case, skip the copy.
+ if (input.data() != output->data() || input.size() != output->size())
+ output->assign(input.data(), input.size());
+
+ return DoReplaceMatchesAfterOffset(output, 0,
+ MakeCharacterMatcher(find_any_of_these),
+ replace_with, ReplaceType::REPLACE_ALL);
+}
+
+template <class string_type>
+inline typename string_type::value_type* WriteIntoT(string_type* str,
+ size_t length_with_null) {
+ GURL_DCHECK_GE(length_with_null, 1u);
+ str->reserve(length_with_null);
+ str->resize(length_with_null - 1);
+ return &((*str)[0]);
+}
+
+// Generic version for all JoinString overloads. |list_type| must be a sequence
+// (gurl_base::span or std::initializer_list) of strings/StringPieces (std::string,
+// std::u16string, StringPiece or StringPiece16). |CharT| is either char or
+// char16_t.
+template <typename list_type,
+ typename T,
+ typename CharT = typename T::value_type>
+static std::basic_string<CharT> JoinStringT(list_type parts, T sep) {
+ if (std::empty(parts))
+ return std::basic_string<CharT>();
+
+ // Pre-allocate the eventual size of the string. Start with the size of all of
+ // the separators (note that this *assumes* parts.size() > 0).
+ size_t total_size = (parts.size() - 1) * sep.size();
+ for (const auto& part : parts)
+ total_size += part.size();
+ std::basic_string<CharT> result;
+ result.reserve(total_size);
+
+ auto iter = parts.begin();
+ GURL_DCHECK(iter != parts.end());
+ result.append(iter->data(), iter->size());
+ ++iter;
+
+ for (; iter != parts.end(); ++iter) {
+ result.append(sep.data(), sep.size());
+ result.append(iter->data(), iter->size());
+ }
+
+ // Sanity-check that we pre-allocated correctly.
+ GURL_DCHECK_EQ(total_size, result.size());
+
+ return result;
+}
+
+template <typename T, typename CharT = typename T::value_type>
+std::basic_string<CharT> DoReplaceStringPlaceholders(
+ T format_string,
+ const std::vector<std::basic_string<CharT>>& subst,
+ std::vector<size_t>* offsets) {
+ size_t substitutions = subst.size();
+ GURL_DCHECK_LT(substitutions, 11U);
+
+ size_t sub_length = 0;
+ for (const auto& cur : subst)
+ sub_length += cur.length();
+
+ std::basic_string<CharT> formatted;
+ formatted.reserve(format_string.length() + sub_length);
+
+ std::vector<ReplacementOffset> r_offsets;
+ for (auto i = format_string.begin(); i != format_string.end(); ++i) {
+ if ('$' == *i) {
+ if (i + 1 != format_string.end()) {
+ ++i;
+ if ('$' == *i) {
+ while (i != format_string.end() && '$' == *i) {
+ formatted.push_back('$');
+ ++i;
+ }
+ --i;
+ } else {
+ if (*i < '1' || *i > '9') {
+ GURL_DLOG(ERROR) << "Invalid placeholder: $"
+ << std::basic_string<CharT>(1, *i);
+ continue;
+ }
+ size_t index = static_cast<size_t>(*i - '1');
+ if (offsets) {
+ ReplacementOffset r_offset(index, formatted.size());
+ r_offsets.insert(
+ ranges::upper_bound(r_offsets, r_offset, &CompareParameter),
+ r_offset);
+ }
+ if (index < substitutions)
+ formatted.append(subst.at(index));
+ }
+ }
+ } else {
+ formatted.push_back(*i);
+ }
+ }
+ if (offsets) {
+ for (const auto& cur : r_offsets)
+ offsets->push_back(cur.offset);
+ }
+ return formatted;
+}
+
+// The following code is compatible with the OpenBSD lcpy interface. See:
+// http://www.gratisoft.us/todd/papers/strlcpy.html
+// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
+
+template <typename CHAR>
+size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
+ for (size_t i = 0; i < dst_size; ++i) {
+ if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
+ return i;
+ }
+
+ // We were left off at dst_size. We over copied 1 byte. Null terminate.
+ if (dst_size != 0)
+ dst[dst_size - 1] = 0;
+
+ // Count the rest of the |src|, and return it's length in characters.
+ while (src[dst_size])
+ ++dst_size;
+ return dst_size;
+}
+
+} // namespace gurl_base::internal
+
+#endif // BASE_STRINGS_STRING_UTIL_IMPL_HELPERS_H_
diff --git a/base/strings/string_util_internal.h b/base/strings/string_util_internal.h
index 1d6a41e..3a493dd 100644
--- a/base/strings/string_util_internal.h
+++ b/base/strings/string_util_internal.h
@@ -5,66 +5,21 @@
#ifndef BASE_STRINGS_STRING_UTIL_INTERNAL_H_
#define BASE_STRINGS_STRING_UTIL_INTERNAL_H_
-#include <algorithm>
-
-#include "polyfills/base/check.h"
-#include "polyfills/base/check_op.h"
-#include "polyfills/base/logging.h"
-#include "polyfills/base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
-#include "base/third_party/icu/icu_utf.h"
-namespace gurl_base {
+namespace gurl_base::internal {
-namespace internal {
-
-// Used by ReplaceStringPlaceholders to track the position in the string of
-// replaced parameters.
-struct ReplacementOffset {
- ReplacementOffset(uintptr_t parameter, size_t offset)
- : parameter(parameter), offset(offset) {}
-
- // Index of the parameter.
- size_t parameter;
-
- // Starting position in the string.
- size_t offset;
-};
-
-static bool CompareParameter(const ReplacementOffset& elem1,
- const ReplacementOffset& elem2) {
- return elem1.parameter < elem2.parameter;
-}
-
-// Assuming that a pointer is the size of a "machine word", then
-// uintptr_t is an integer type that is also a machine word.
-using MachineWord = uintptr_t;
-
-inline bool IsMachineWordAligned(const void* pointer) {
- return !(reinterpret_cast<MachineWord>(pointer) & (sizeof(MachineWord) - 1));
+// ASCII-specific tolower. The standard library's tolower is locale sensitive,
+// so we don't want to use it here.
+template <typename CharT,
+ typename = std::enable_if_t<std::is_integral<CharT>::value>>
+constexpr CharT ToLowerASCII(CharT c) {
+ return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
}
template <typename T, typename CharT = typename T::value_type>
-std::basic_string<CharT> ToLowerASCIIImpl(T str) {
- std::basic_string<CharT> ret;
- ret.reserve(str.size());
- for (size_t i = 0; i < str.size(); i++)
- ret.push_back(ToLowerASCII(str[i]));
- return ret;
-}
-
-template <typename T, typename CharT = typename T::value_type>
-std::basic_string<CharT> ToUpperASCIIImpl(T str) {
- std::basic_string<CharT> ret;
- ret.reserve(str.size());
- for (size_t i = 0; i < str.size(); i++)
- ret.push_back(ToUpperASCII(str[i]));
- return ret;
-}
-
-template <typename T, typename CharT = typename T::value_type>
-int CompareCaseInsensitiveASCIIT(T a, T b) {
+constexpr int CompareCaseInsensitiveASCIIT(T a, T b) {
// Find the first characters that aren't equal and compare them. If the end
// of one of the strings is found before a nonequal character, the lengths
// of the strings are compared.
@@ -89,524 +44,14 @@
return 1;
}
-template <typename T, typename CharT = typename T::value_type>
-TrimPositions TrimStringT(T input,
- T trim_chars,
- TrimPositions positions,
- std::basic_string<CharT>* output) {
- // Find the edges of leading/trailing whitespace as desired. Need to use
- // a StringPiece version of input to be able to call find* on it with the
- // StringPiece version of trim_chars (normally the trim_chars will be a
- // constant so avoid making a copy).
- const size_t last_char = input.length() - 1;
- const size_t first_good_char =
- (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
- const size_t last_good_char = (positions & TRIM_TRAILING)
- ? input.find_last_not_of(trim_chars)
- : last_char;
-
- // When the string was all trimmed, report that we stripped off characters
- // from whichever position the caller was interested in. For empty input, we
- // stripped no characters, but we still need to clear |output|.
- if (input.empty() || first_good_char == std::basic_string<CharT>::npos ||
- last_good_char == std::basic_string<CharT>::npos) {
- bool input_was_empty = input.empty(); // in case output == &input
- output->clear();
- return input_was_empty ? TRIM_NONE : positions;
- }
-
- // Trim.
- output->assign(input.data() + first_good_char,
- last_good_char - first_good_char + 1);
-
- // Return where we trimmed from.
- return static_cast<TrimPositions>(
- (first_good_char == 0 ? TRIM_NONE : TRIM_LEADING) |
- (last_good_char == last_char ? TRIM_NONE : TRIM_TRAILING));
+template <typename CharT, typename CharU>
+inline bool EqualsCaseInsensitiveASCIIT(BasicStringPiece<CharT> a,
+ BasicStringPiece<CharU> b) {
+ return ranges::equal(a, b, [](auto lhs, auto rhs) {
+ return ToLowerASCII(lhs) == ToLowerASCII(rhs);
+ });
}
-template <typename T, typename CharT = typename T::value_type>
-T TrimStringPieceT(T input, T trim_chars, TrimPositions positions) {
- size_t begin =
- (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
- size_t end = (positions & TRIM_TRAILING)
- ? input.find_last_not_of(trim_chars) + 1
- : input.size();
- return input.substr(std::min(begin, input.size()), end - begin);
-}
-
-template <typename T, typename CharT = typename T::value_type>
-std::basic_string<CharT> CollapseWhitespaceT(
- T text,
- bool trim_sequences_with_line_breaks) {
- std::basic_string<CharT> result;
- result.resize(text.size());
-
- // Set flags to pretend we're already in a trimmed whitespace sequence, so we
- // will trim any leading whitespace.
- bool in_whitespace = true;
- bool already_trimmed = true;
-
- size_t chars_written = 0;
- for (auto c : text) {
- if (IsWhitespace(c)) {
- if (!in_whitespace) {
- // Reduce all whitespace sequences to a single space.
- in_whitespace = true;
- result[chars_written++] = L' ';
- }
- if (trim_sequences_with_line_breaks && !already_trimmed &&
- ((c == '\n') || (c == '\r'))) {
- // Whitespace sequences containing CR or LF are eliminated entirely.
- already_trimmed = true;
- --chars_written;
- }
- } else {
- // Non-whitespace characters are copied straight across.
- in_whitespace = false;
- already_trimmed = false;
- result[chars_written++] = c;
- }
- }
-
- if (in_whitespace && !already_trimmed) {
- // Any trailing whitespace is eliminated.
- --chars_written;
- }
-
- result.resize(chars_written);
- return result;
-}
-
-template <class Char>
-bool DoIsStringASCII(const Char* characters, size_t length) {
- // Bitmasks to detect non ASCII characters for character sizes of 8, 16 and 32
- // bits.
- constexpr MachineWord NonASCIIMasks[] = {
- 0, MachineWord(0x8080808080808080ULL), MachineWord(0xFF80FF80FF80FF80ULL),
- 0, MachineWord(0xFFFFFF80FFFFFF80ULL),
- };
-
- if (!length)
- return true;
- constexpr MachineWord non_ascii_bit_mask = NonASCIIMasks[sizeof(Char)];
- static_assert(non_ascii_bit_mask, "Error: Invalid Mask");
- MachineWord all_char_bits = 0;
- const Char* end = characters + length;
-
- // Prologue: align the input.
- while (!IsMachineWordAligned(characters) && characters < end)
- all_char_bits |= static_cast<MachineWord>(*characters++);
- if (all_char_bits & non_ascii_bit_mask)
- return false;
-
- // Compare the values of CPU word size.
- constexpr size_t chars_per_word = sizeof(MachineWord) / sizeof(Char);
- constexpr int batch_count = 16;
- while (characters <= end - batch_count * chars_per_word) {
- all_char_bits = 0;
- for (int i = 0; i < batch_count; ++i) {
- all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
- characters += chars_per_word;
- }
- if (all_char_bits & non_ascii_bit_mask)
- return false;
- }
-
- // Process the remaining words.
- all_char_bits = 0;
- while (characters <= end - chars_per_word) {
- all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
- characters += chars_per_word;
- }
-
- // Process the remaining bytes.
- while (characters < end)
- all_char_bits |= static_cast<MachineWord>(*characters++);
-
- return !(all_char_bits & non_ascii_bit_mask);
-}
-
-template <bool (*Validator)(base_icu::UChar32)>
-inline bool DoIsStringUTF8(StringPiece str) {
- const uint8_t* src = reinterpret_cast<const uint8_t*>(str.data());
- size_t src_len = str.length();
- size_t char_index = 0;
-
- while (char_index < src_len) {
- base_icu::UChar32 code_point;
- CBU8_NEXT(src, char_index, src_len, code_point);
- if (!Validator(code_point))
- return false;
- }
- return true;
-}
-
-template <typename T, typename CharT = typename T::value_type>
-bool StartsWithT(T str, T search_for, CompareCase case_sensitivity) {
- if (search_for.size() > str.size())
- return false;
-
- BasicStringPiece<CharT> source = str.substr(0, search_for.size());
-
- switch (case_sensitivity) {
- case CompareCase::SENSITIVE:
- return source == search_for;
-
- case CompareCase::INSENSITIVE_ASCII:
- return std::equal(search_for.begin(), search_for.end(), source.begin(),
- CaseInsensitiveCompareASCII<CharT>());
-
- default:
- GURL_NOTREACHED();
- return false;
- }
-}
-
-template <typename T, typename CharT = typename T::value_type>
-bool EndsWithT(T str, T search_for, CompareCase case_sensitivity) {
- if (search_for.size() > str.size())
- return false;
-
- BasicStringPiece<CharT> source =
- str.substr(str.size() - search_for.size(), search_for.size());
-
- switch (case_sensitivity) {
- case CompareCase::SENSITIVE:
- return source == search_for;
-
- case CompareCase::INSENSITIVE_ASCII:
- return std::equal(source.begin(), source.end(), search_for.begin(),
- CaseInsensitiveCompareASCII<CharT>());
-
- default:
- GURL_NOTREACHED();
- return false;
- }
-}
-
-// A Matcher for DoReplaceMatchesAfterOffset() that matches substrings.
-template <class CharT>
-struct SubstringMatcher {
- BasicStringPiece<CharT> find_this;
-
- size_t Find(const std::basic_string<CharT>& input, size_t pos) {
- return input.find(find_this.data(), pos, find_this.length());
- }
- size_t MatchSize() { return find_this.length(); }
-};
-
-// Type deduction helper for SubstringMatcher.
-template <typename T, typename CharT = typename T::value_type>
-auto MakeSubstringMatcher(T find_this) {
- return SubstringMatcher<CharT>{find_this};
-}
-
-// A Matcher for DoReplaceMatchesAfterOffset() that matches single characters.
-template <class CharT>
-struct CharacterMatcher {
- BasicStringPiece<CharT> find_any_of_these;
-
- size_t Find(const std::basic_string<CharT>& input, size_t pos) {
- return input.find_first_of(find_any_of_these.data(), pos,
- find_any_of_these.length());
- }
- constexpr size_t MatchSize() { return 1; }
-};
-
-// Type deduction helper for CharacterMatcher.
-template <typename T, typename CharT = typename T::value_type>
-auto MakeCharacterMatcher(T find_any_of_these) {
- return CharacterMatcher<CharT>{find_any_of_these};
-}
-
-enum class ReplaceType { REPLACE_ALL, REPLACE_FIRST };
-
-// Runs in O(n) time in the length of |str|, and transforms the string without
-// reallocating when possible. Returns |true| if any matches were found.
-//
-// This is parameterized on a |Matcher| traits type, so that it can be the
-// implementation for both ReplaceChars() and ReplaceSubstringsAfterOffset().
-template <typename Matcher, typename T, typename CharT = typename T::value_type>
-bool DoReplaceMatchesAfterOffset(std::basic_string<CharT>* str,
- size_t initial_offset,
- Matcher matcher,
- T replace_with,
- ReplaceType replace_type) {
- using CharTraits = std::char_traits<CharT>;
-
- const size_t find_length = matcher.MatchSize();
- if (!find_length)
- return false;
-
- // If the find string doesn't appear, there's nothing to do.
- size_t first_match = matcher.Find(*str, initial_offset);
- if (first_match == std::basic_string<CharT>::npos)
- return false;
-
- // If we're only replacing one instance, there's no need to do anything
- // complicated.
- const size_t replace_length = replace_with.length();
- if (replace_type == ReplaceType::REPLACE_FIRST) {
- str->replace(first_match, find_length, replace_with.data(), replace_length);
- return true;
- }
-
- // If the find and replace strings are the same length, we can simply use
- // replace() on each instance, and finish the entire operation in O(n) time.
- if (find_length == replace_length) {
- auto* buffer = &((*str)[0]);
- for (size_t offset = first_match; offset != std::basic_string<CharT>::npos;
- offset = matcher.Find(*str, offset + replace_length)) {
- CharTraits::copy(buffer + offset, replace_with.data(), replace_length);
- }
- return true;
- }
-
- // Since the find and replace strings aren't the same length, a loop like the
- // one above would be O(n^2) in the worst case, as replace() will shift the
- // entire remaining string each time. We need to be more clever to keep things
- // O(n).
- //
- // When the string is being shortened, it's possible to just shift the matches
- // down in one pass while finding, and truncate the length at the end of the
- // search.
- //
- // If the string is being lengthened, more work is required. The strategy used
- // here is to make two find() passes through the string. The first pass counts
- // the number of matches to determine the new size. The second pass will
- // either construct the new string into a new buffer (if the existing buffer
- // lacked capacity), or else -- if there is room -- create a region of scratch
- // space after |first_match| by shifting the tail of the string to a higher
- // index, and doing in-place moves from the tail to lower indices thereafter.
- size_t str_length = str->length();
- size_t expansion = 0;
- if (replace_length > find_length) {
- // This operation lengthens the string; determine the new length by counting
- // matches.
- const size_t expansion_per_match = (replace_length - find_length);
- size_t num_matches = 0;
- for (size_t match = first_match; match != std::basic_string<CharT>::npos;
- match = matcher.Find(*str, match + find_length)) {
- expansion += expansion_per_match;
- ++num_matches;
- }
- const size_t final_length = str_length + expansion;
-
- if (str->capacity() < final_length) {
- // If we'd have to allocate a new buffer to grow the string, build the
- // result directly into the new allocation via append().
- std::basic_string<CharT> src(str->get_allocator());
- str->swap(src);
- str->reserve(final_length);
-
- size_t pos = 0;
- for (size_t match = first_match;; match = matcher.Find(src, pos)) {
- str->append(src, pos, match - pos);
- str->append(replace_with.data(), replace_length);
- pos = match + find_length;
-
- // A mid-loop test/break enables skipping the final Find() call; the
- // number of matches is known, so don't search past the last one.
- if (!--num_matches)
- break;
- }
-
- // Handle substring after the final match.
- str->append(src, pos, str_length - pos);
- return true;
- }
-
- // Prepare for the copy/move loop below -- expand the string to its final
- // size by shifting the data after the first match to the end of the resized
- // string.
- size_t shift_src = first_match + find_length;
- size_t shift_dst = shift_src + expansion;
-
- // Big |expansion| factors (relative to |str_length|) require padding up to
- // |shift_dst|.
- if (shift_dst > str_length)
- str->resize(shift_dst);
-
- str->replace(shift_dst, str_length - shift_src, *str, shift_src,
- str_length - shift_src);
- str_length = final_length;
- }
-
- // We can alternate replacement and move operations. This won't overwrite the
- // unsearched region of the string so long as |write_offset| <= |read_offset|;
- // that condition is always satisfied because:
- //
- // (a) If the string is being shortened, |expansion| is zero and
- // |write_offset| grows slower than |read_offset|.
- //
- // (b) If the string is being lengthened, |write_offset| grows faster than
- // |read_offset|, but |expansion| is big enough so that |write_offset|
- // will only catch up to |read_offset| at the point of the last match.
- auto* buffer = &((*str)[0]);
- size_t write_offset = first_match;
- size_t read_offset = first_match + expansion;
- do {
- if (replace_length) {
- CharTraits::copy(buffer + write_offset, replace_with.data(),
- replace_length);
- write_offset += replace_length;
- }
- read_offset += find_length;
-
- // min() clamps std::basic_string<CharT>::npos (the largest unsigned value)
- // to str_length.
- size_t match = std::min(matcher.Find(*str, read_offset), str_length);
-
- size_t length = match - read_offset;
- if (length) {
- CharTraits::move(buffer + write_offset, buffer + read_offset, length);
- write_offset += length;
- read_offset += length;
- }
- } while (read_offset < str_length);
-
- // If we're shortening the string, truncate it now.
- str->resize(write_offset);
- return true;
-}
-
-template <typename T, typename CharT = typename T::value_type>
-bool ReplaceCharsT(T input,
- T find_any_of_these,
- T replace_with,
- std::basic_string<CharT>* output) {
- // Commonly, this is called with output and input being the same string; in
- // that case, skip the copy.
- if (input.data() != output->data() || input.size() != output->size())
- output->assign(input.data(), input.size());
-
- return DoReplaceMatchesAfterOffset(output, 0,
- MakeCharacterMatcher(find_any_of_these),
- replace_with, ReplaceType::REPLACE_ALL);
-}
-
-template <class string_type>
-inline typename string_type::value_type* WriteIntoT(string_type* str,
- size_t length_with_null) {
- GURL_DCHECK_GE(length_with_null, 1u);
- str->reserve(length_with_null);
- str->resize(length_with_null - 1);
- return &((*str)[0]);
-}
-
-// Generic version for all JoinString overloads. |list_type| must be a sequence
-// (gurl_base::span or std::initializer_list) of strings/StringPieces (std::string,
-// std::u16string, StringPiece or StringPiece16). |CharT| is either char or
-// char16_t.
-template <typename list_type,
- typename T,
- typename CharT = typename T::value_type>
-static std::basic_string<CharT> JoinStringT(list_type parts, T sep) {
- if (std::empty(parts))
- return std::basic_string<CharT>();
-
- // Pre-allocate the eventual size of the string. Start with the size of all of
- // the separators (note that this *assumes* parts.size() > 0).
- size_t total_size = (parts.size() - 1) * sep.size();
- for (const auto& part : parts)
- total_size += part.size();
- std::basic_string<CharT> result;
- result.reserve(total_size);
-
- auto iter = parts.begin();
- GURL_DCHECK(iter != parts.end());
- result.append(iter->data(), iter->size());
- ++iter;
-
- for (; iter != parts.end(); ++iter) {
- result.append(sep.data(), sep.size());
- result.append(iter->data(), iter->size());
- }
-
- // Sanity-check that we pre-allocated correctly.
- GURL_DCHECK_EQ(total_size, result.size());
-
- return result;
-}
-
-template <typename T, typename CharT = typename T::value_type>
-std::basic_string<CharT> DoReplaceStringPlaceholders(
- T format_string,
- const std::vector<std::basic_string<CharT>>& subst,
- std::vector<size_t>* offsets) {
- size_t substitutions = subst.size();
- GURL_DCHECK_LT(substitutions, 11U);
-
- size_t sub_length = 0;
- for (const auto& cur : subst)
- sub_length += cur.length();
-
- std::basic_string<CharT> formatted;
- formatted.reserve(format_string.length() + sub_length);
-
- std::vector<ReplacementOffset> r_offsets;
- for (auto i = format_string.begin(); i != format_string.end(); ++i) {
- if ('$' == *i) {
- if (i + 1 != format_string.end()) {
- ++i;
- if ('$' == *i) {
- while (i != format_string.end() && '$' == *i) {
- formatted.push_back('$');
- ++i;
- }
- --i;
- } else {
- if (*i < '1' || *i > '9') {
- GURL_DLOG(ERROR) << "Invalid placeholder: $"
- << std::basic_string<CharT>(1, *i);
- continue;
- }
- size_t index = static_cast<size_t>(*i - '1');
- if (offsets) {
- ReplacementOffset r_offset(index, formatted.size());
- r_offsets.insert(
- ranges::upper_bound(r_offsets, r_offset, &CompareParameter),
- r_offset);
- }
- if (index < substitutions)
- formatted.append(subst.at(index));
- }
- }
- } else {
- formatted.push_back(*i);
- }
- }
- if (offsets) {
- for (const auto& cur : r_offsets)
- offsets->push_back(cur.offset);
- }
- return formatted;
-}
-
-// The following code is compatible with the OpenBSD lcpy interface. See:
-// http://www.gratisoft.us/todd/papers/strlcpy.html
-// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
-
-template <typename CHAR>
-size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
- for (size_t i = 0; i < dst_size; ++i) {
- if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
- return i;
- }
-
- // We were left off at dst_size. We over copied 1 byte. Null terminate.
- if (dst_size != 0)
- dst[dst_size - 1] = 0;
-
- // Count the rest of the |src|, and return it's length in characters.
- while (src[dst_size])
- ++dst_size;
- return dst_size;
-}
-
-} // namespace internal
-
-} // namespace base
+} // namespace gurl_base::internal
#endif // BASE_STRINGS_STRING_UTIL_INTERNAL_H_
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index d4326c7..4109f8e 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -1474,6 +1474,14 @@
// Differing values.
EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb"));
EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA"));
+
+ // For constexpr.
+ static_assert(CompareCaseInsensitiveASCII("", "") == 0);
+ static_assert(CompareCaseInsensitiveASCII("Asdf", "aSDf") == 0);
+ static_assert(CompareCaseInsensitiveASCII("Asdf", "aSDfA") == -1);
+ static_assert(CompareCaseInsensitiveASCII("AsdfA", "aSDf") == 1);
+ static_assert(CompareCaseInsensitiveASCII("AsdfA", "aSDfb") == -1);
+ static_assert(CompareCaseInsensitiveASCII("Asdfb", "aSDfA") == 1);
}
TEST(StringUtilTest, EqualsCaseInsensitiveASCII) {
diff --git a/base/strings/string_util_win.cc b/base/strings/string_util_win.cc
index f8d0243..c3569b3 100644
--- a/base/strings/string_util_win.cc
+++ b/base/strings/string_util_win.cc
@@ -4,7 +4,8 @@
#include "base/strings/string_util_win.h"
-#include "base/strings/string_util_internal.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_util_impl_helpers.h"
namespace gurl_base {
@@ -72,7 +73,7 @@
}
bool EqualsASCII(WStringPiece str, StringPiece ascii) {
- return std::equal(ascii.begin(), ascii.end(), str.begin(), str.end());
+ return ranges::equal(ascii, str);
}
bool StartsWith(WStringPiece str,
diff --git a/base/strings/utf_string_conversions_fuzzer.cc b/base/strings/utf_string_conversions_fuzzer.cc
deleted file mode 100644
index 3cc4521..0000000
--- a/base/strings/utf_string_conversions_fuzzer.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <tuple>
-
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-
-std::string output_std_string;
-std::wstring output_std_wstring;
-std::u16string output_string16;
-
-// Entry point for LibFuzzer.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- gurl_base::StringPiece string_piece_input(reinterpret_cast<const char*>(data),
- size);
-
- std::ignore = gurl_base::UTF8ToWide(string_piece_input);
- gurl_base::UTF8ToWide(reinterpret_cast<const char*>(data), size,
- &output_std_wstring);
- std::ignore = gurl_base::UTF8ToUTF16(string_piece_input);
- gurl_base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size,
- &output_string16);
-
- // Test for char16_t.
- if (size % 2 == 0) {
- gurl_base::StringPiece16 string_piece_input16(
- reinterpret_cast<const char16_t*>(data), size / 2);
- std::ignore = gurl_base::UTF16ToWide(output_string16);
- gurl_base::UTF16ToWide(reinterpret_cast<const char16_t*>(data), size / 2,
- &output_std_wstring);
- std::ignore = gurl_base::UTF16ToUTF8(string_piece_input16);
- gurl_base::UTF16ToUTF8(reinterpret_cast<const char16_t*>(data), size / 2,
- &output_std_string);
- }
-
- // Test for wchar_t.
- size_t wchar_t_size = sizeof(wchar_t);
- if (size % wchar_t_size == 0) {
- std::ignore = gurl_base::WideToUTF8(output_std_wstring);
- gurl_base::WideToUTF8(reinterpret_cast<const wchar_t*>(data),
- size / wchar_t_size, &output_std_string);
- std::ignore = gurl_base::WideToUTF16(output_std_wstring);
- gurl_base::WideToUTF16(reinterpret_cast<const wchar_t*>(data),
- size / wchar_t_size, &output_string16);
- }
-
- // Test for ASCII. This condition is needed to avoid hitting instant GURL_CHECK
- // failures.
- if (gurl_base::IsStringASCII(string_piece_input)) {
- output_string16 = gurl_base::ASCIIToUTF16(string_piece_input);
- gurl_base::StringPiece16 string_piece_input16(output_string16);
- std::ignore = gurl_base::UTF16ToASCII(string_piece_input16);
- }
-
- return 0;
-}
diff --git a/build/build_config.h b/build/build_config.h
index 8f90f47..6811872 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -245,6 +245,12 @@
#define BUILDFLAG_INTERNAL_IS_WIN() (0)
#endif
+#if defined(USE_OZONE)
+#define BUILDFLAG_INTERNAL_IS_OZONE() (1)
+#else
+#define BUILDFLAG_INTERNAL_IS_OZONE() (0)
+#endif
+
// Compiler detection. Note: clang masquerades as GCC on POSIX and as MSVC on
// Windows.
#if defined(__GNUC__)
diff --git a/copy.bara.sky b/copy.bara.sky
index f9d1a2a..89f70ce 100644
--- a/copy.bara.sky
+++ b/copy.bara.sky
@@ -24,9 +24,10 @@
"base/debug/crash_logging.cc",
"base/debug/crash_logging.h",
"base/debug/leak_annotations.h",
- "base/functional/*.h",
+ "base/functional/identity.h",
+ "base/functional/invoke.h",
+ "base/functional/not_fn.h",
"base/i18n/uchar.h",
- "base/memory/raw_ptr.h",
"base/memory/raw_ptr_exclusion.h",
"base/numerics/*.h",
"base/no_destructor.h",
@@ -47,6 +48,7 @@
],
exclude = [
"url/url_idna_icu_alternatives_android.cc",
+ "**/*_fuzzer.cc",
],
)
@@ -72,10 +74,11 @@
"base/check_op.h",
"base/component_export.h",
"base/cpu_reduction_experiment.h",
- "base/dcheck_is_on.h",
+ #"base/dcheck_is_on.h",
"base/debug/alias.h",
"base/export_template.h",
"base/logging.h",
+ "base/memory/raw_ptr.h",
"base/notreached.h",
"base/trace_event/memory_usage_estimator.h",
"third_party/perfetto/include/perfetto/tracing/traced_value.h",
@@ -107,7 +110,6 @@
core.replace("#include \"base/strings/string_number_conversions_win.h\"", ""),
core.replace("#include \"base/allocator/partition_allocator/partition_alloc_config.h\"", ""),
- core.replace("base/trace_event/base_tracing_forward.h", "polyfills/third_party/perfetto/include/perfetto/tracing/traced_value.h"),
# Use system ICU.
core.replace(
diff --git a/polyfills/BUILD b/polyfills/BUILD
index 6a58eec..ea1b73e 100644
--- a/polyfills/BUILD
+++ b/polyfills/BUILD
@@ -16,6 +16,7 @@
"base/debug/alias.h",
"base/export_template.h",
"base/logging.h",
+ "base/memory/raw_ptr.h",
"base/metrics/histogram_macros.h",
"base/notreached.h",
"base/trace_event/memory_usage_estimator.h",
diff --git a/polyfills/base/memory/raw_ptr.h b/polyfills/base/memory/raw_ptr.h
new file mode 100644
index 0000000..ec0e526
--- /dev/null
+++ b/polyfills/base/memory/raw_ptr.h
@@ -0,0 +1,17 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef POLYFILLS_BASE_MEMORY_RAW_PTR_H_
+#define POLYFILLS_BASE_MEMORY_RAW_PTR_H_
+
+namespace gurl_base {
+
+template<typename T>
+using raw_ptr = T*;
+
+} // namespace gurl_base
+
+using gurl_base::raw_ptr;
+
+#endif // POLYFILLS_BASE_MEMORY_RAW_PTR_H_
diff --git a/url/gurl_fuzzer.cc b/url/gurl_fuzzer.cc
deleted file mode 100644
index 170de8a..0000000
--- a/url/gurl_fuzzer.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2015 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/at_exit.h"
-#include "polyfills/base/check_op.h"
-#include "base/i18n/icu_util.h"
-#include "base/no_destructor.h"
-#include "url/gurl.h"
-
-struct TestCase {
- TestCase() { GURL_CHECK(gurl_base::i18n::InitializeICU()); }
-
- // used by ICU integration.
- gurl_base::AtExitManager at_exit_manager;
-};
-
-TestCase* test_case = new TestCase();
-
-// Checks that GURL's canonicalization is idempotent. This can help discover
-// issues like https://crbug.com/1128999.
-void CheckIdempotency(const GURL& url) {
- if (!url.is_valid())
- return;
- const std::string& spec = url.spec();
- GURL recanonicalized(spec);
- GURL_CHECK(recanonicalized.is_valid());
- GURL_CHECK_EQ(spec, recanonicalized.spec());
-}
-
-// Checks that |url.spec()| is preserved across a call to ReplaceComponents with
-// zero replacements, which is effectively a copy. This can help discover issues
-// like https://crbug.com/1075515.
-void CheckReplaceComponentsPreservesSpec(const GURL& url) {
- static const gurl_base::NoDestructor<GURL::Replacements> no_op;
- GURL copy = url.ReplaceComponents(*no_op);
- GURL_CHECK_EQ(url.is_valid(), copy.is_valid());
- if (url.is_valid()) {
- GURL_CHECK_EQ(url.spec(), copy.spec());
- }
-}
-
-// Entry point for LibFuzzer.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- if (size < 1)
- return 0;
- {
- gurl_base::StringPiece string_piece_input(reinterpret_cast<const char*>(data),
- size);
- const GURL url_from_string_piece(string_piece_input);
- CheckIdempotency(url_from_string_piece);
- CheckReplaceComponentsPreservesSpec(url_from_string_piece);
- }
- // Test for StringPiece16 if size is even.
- if (size % sizeof(char16_t) == 0) {
- gurl_base::StringPiece16 string_piece_input16(
- reinterpret_cast<const char16_t*>(data), size / sizeof(char16_t));
- const GURL url_from_string_piece16(string_piece_input16);
- CheckIdempotency(url_from_string_piece16);
- CheckReplaceComponentsPreservesSpec(url_from_string_piece16);
- }
- // Resolve relative url tests.
- {
- size_t size_t_bytes = sizeof(size_t);
- if (size < size_t_bytes + 1) {
- return 0;
- }
- size_t relative_size =
- *reinterpret_cast<const size_t*>(data) % (size - size_t_bytes);
- std::string relative_string(
- reinterpret_cast<const char*>(data + size_t_bytes), relative_size);
- gurl_base::StringPiece string_piece_part_input(
- reinterpret_cast<const char*>(data + size_t_bytes + relative_size),
- size - relative_size - size_t_bytes);
- const GURL url_from_string_piece_part(string_piece_part_input);
- CheckIdempotency(url_from_string_piece_part);
- CheckReplaceComponentsPreservesSpec(url_from_string_piece_part);
-
- url_from_string_piece_part.Resolve(relative_string);
-
- if (relative_size % sizeof(char16_t) == 0) {
- std::u16string relative_string16(
- reinterpret_cast<const char16_t*>(data + size_t_bytes),
- relative_size / sizeof(char16_t));
- url_from_string_piece_part.Resolve(relative_string16);
- }
- }
- return 0;
-}
diff --git a/url/origin.h b/url/origin.h
index 0d04628..2b8caa5 100644
--- a/url/origin.h
+++ b/url/origin.h
@@ -311,6 +311,13 @@
gurl_base::android::ScopedJavaLocalRef<jobject> CreateJavaObject() const;
static Origin FromJavaObject(
const gurl_base::android::JavaRef<jobject>& java_origin);
+ static jlong CreateNative(JNIEnv* env,
+ const gurl_base::android::JavaRef<jstring>& java_scheme,
+ const gurl_base::android::JavaRef<jstring>& java_host,
+ uint16_t port,
+ bool is_opaque,
+ uint64_t tokenHighBits,
+ uint64_t tokenLowBits);
#endif // BUILDFLAG(IS_ANDROID)
void WriteIntoTrace(perfetto::TracedValue context) const;
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index 61500a6..5f28acc 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -5,7 +5,7 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/memory/raw_ptr.h"
+#include "polyfills/base/memory/raw_ptr.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/url/url_canon_icu.cc b/url/url_canon_icu.cc
index 20c31a8..088235b 100644
--- a/url/url_canon_icu.cc
+++ b/url/url_canon_icu.cc
@@ -9,7 +9,7 @@
#include <string.h>
#include "polyfills/base/check.h"
-#include "base/memory/raw_ptr.h"
+#include "polyfills/base/memory/raw_ptr.h"
#include <unicode/ucnv.h>
#include <unicode/ucnv_cb.h>
#include <unicode/utypes.h>
diff --git a/url/url_canon_icu.h b/url/url_canon_icu.h
index 9a35df1..9b64722 100644
--- a/url/url_canon_icu.h
+++ b/url/url_canon_icu.h
@@ -9,7 +9,7 @@
#include "base/compiler_specific.h"
#include "polyfills/base/component_export.h"
-#include "base/memory/raw_ptr.h"
+#include "polyfills/base/memory/raw_ptr.h"
#include "url/url_canon.h"
typedef struct UConverter UConverter;
diff --git a/url/url_canon_icu_unittest.cc b/url/url_canon_icu_unittest.cc
index 0ac0fcb..fc3fb67 100644
--- a/url/url_canon_icu_unittest.cc
+++ b/url/url_canon_icu_unittest.cc
@@ -7,7 +7,7 @@
#include <stddef.h>
#include "polyfills/base/logging.h"
-#include "base/memory/raw_ptr.h"
+#include "polyfills/base/memory/raw_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include <unicode/ucnv.h>
#include "url/url_canon.h"
diff --git a/url/url_canon_query.cc b/url/url_canon_query.cc
index 4beac7a..d326ce8 100644
--- a/url/url_canon_query.cc
+++ b/url/url_canon_query.cc
@@ -39,18 +39,6 @@
namespace {
-// Returns true if the characters starting at |begin| and going until |end|
-// (non-inclusive) are all representable in 7-bits.
-template<typename CHAR, typename UCHAR>
-bool IsAllASCII(const CHAR* spec, const Component& query) {
- int end = query.end();
- for (int i = query.begin; i < end; i++) {
- if (static_cast<UCHAR>(spec[i]) >= 0x80)
- return false;
- }
- return true;
-}
-
// Appends the given string to the output, escaping characters that do not
// match the given |type| in SharedCharTypes. This version will accept 8 or 16
// bit characters, but assumes that they have only 7-bit values. It also assumes
@@ -93,29 +81,22 @@
static_cast<size_t>(query.len), output);
}
-template<typename CHAR, typename UCHAR>
+template <typename CHAR, typename UCHAR>
void DoConvertToQueryEncoding(const CHAR* spec,
const Component& query,
CharsetConverter* converter,
CanonOutput* output) {
- if (IsAllASCII<CHAR, UCHAR>(spec, query)) {
- // Easy: the input can just appended with no character set conversions.
- AppendRaw8BitQueryString(&spec[query.begin], query.len, output);
+ if (converter) {
+ // Run the converter to get an 8-bit string, then append it, escaping
+ // necessary values.
+ RawCanonOutput<1024> eight_bit;
+ RunConverter(spec, query, converter, &eight_bit);
+ AppendRaw8BitQueryString(eight_bit.data(), eight_bit.length(), output);
} else {
- // Harder: convert to the proper encoding first.
- if (converter) {
- // Run the converter to get an 8-bit string, then append it, escaping
- // necessary values.
- RawCanonOutput<1024> eight_bit;
- RunConverter(spec, query, converter, &eight_bit);
- AppendRaw8BitQueryString(eight_bit.data(), eight_bit.length(), output);
-
- } else {
- // No converter, do our own UTF-8 conversion.
- AppendStringOfType(&spec[query.begin], static_cast<size_t>(query.len),
- CHAR_QUERY, output);
- }
+ // No converter, do our own UTF-8 conversion.
+ AppendStringOfType(&spec[query.begin], static_cast<size_t>(query.len),
+ CHAR_QUERY, output);
}
}