partition_alloc-inl.h 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // Copyright (c) 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_INL_H_
  5. #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_INL_H_
  6. #include <algorithm>
  7. #include <cstring>
  8. #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
  9. #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
  10. #include "base/allocator/partition_allocator/partition_ref_count.h"
  11. #include "base/allocator/partition_allocator/random.h"
  12. #include "base/allocator/partition_allocator/tagging.h"
  13. #include "build/build_config.h"
  14. // Prefetch *x into memory.
  15. #if defined(__clang__) || defined(COMPILER_GCC)
  16. #define PA_PREFETCH(x) __builtin_prefetch(x)
  17. #else
  18. #define PA_PREFETCH(x)
  19. #endif
  20. namespace partition_alloc::internal {
  21. // This is a `memset` that resists being optimized away. Adapted from
  22. // boringssl/src/crypto/mem.c. (Copying and pasting is bad, but //base can't
  23. // depend on //third_party, and this is small enough.)
  24. PA_ALWAYS_INLINE void SecureMemset(void* ptr, uint8_t value, size_t size) {
  25. memset(ptr, value, size);
  26. // As best as we can tell, this is sufficient to break any optimisations that
  27. // might try to eliminate "superfluous" memsets. If there's an easy way to
  28. // detect memset_s, it would be better to use that.
  29. __asm__ __volatile__("" : : "r"(ptr) : "memory");
  30. }
  31. // Used to memset() memory for debugging purposes only.
  32. PA_ALWAYS_INLINE void DebugMemset(void* ptr, int value, size_t size) {
  33. // Only set the first 512kiB of the allocation. This is enough to detect uses
  34. // of uininitialized / freed memory, and makes tests run significantly
  35. // faster. Note that for direct-mapped allocations, memory is decomitted at
  36. // free() time, so freed memory usage cannot happen.
  37. size_t size_to_memset = std::min(size, size_t{1} << 19);
  38. memset(ptr, value, size_to_memset);
  39. }
  40. // Returns true if we've hit the end of a random-length period. We don't want to
  41. // invoke `RandomValue` too often, because we call this function in a hot spot
  42. // (`Free`), and `RandomValue` incurs the cost of atomics.
  43. #if !BUILDFLAG(PA_DCHECK_IS_ON)
  44. PA_ALWAYS_INLINE bool RandomPeriod() {
  45. static thread_local uint8_t counter = 0;
  46. if (PA_UNLIKELY(counter == 0)) {
  47. // It's OK to truncate this value.
  48. counter = static_cast<uint8_t>(RandomValue());
  49. }
  50. // If `counter` is 0, this will wrap. That is intentional and OK.
  51. counter--;
  52. return counter == 0;
  53. }
  54. #endif // !BUILDFLAG(PA_DCHECK_IS_ON)
  55. PA_ALWAYS_INLINE uintptr_t ObjectInnerPtr2Addr(const void* ptr) {
  56. return UntagPtr(ptr);
  57. }
  58. PA_ALWAYS_INLINE uintptr_t ObjectPtr2Addr(const void* object) {
  59. // TODO(bartekn): Check that |object| is indeed an object start.
  60. return ObjectInnerPtr2Addr(object);
  61. }
  62. PA_ALWAYS_INLINE void* SlotStartAddr2Ptr(uintptr_t slot_start) {
  63. // TODO(bartekn): Check that |slot_start| is indeed a slot start.
  64. return TagAddr(slot_start);
  65. }
  66. PA_ALWAYS_INLINE uintptr_t SlotStartPtr2Addr(const void* slot_start) {
  67. // TODO(bartekn): Check that |slot_start| is indeed a slot start.
  68. return UntagPtr(slot_start);
  69. }
  70. } // namespace partition_alloc::internal
  71. #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_INL_H_