Commit 286decef authored by Chris Palmer's avatar Chris Palmer Committed by Commit Bot

[PartitionAlloc] Random-periodically poison on free.

This version calls `RandomValue` less often, which exercises atomics less, so
should be faster.

Thanks to vtsyrklevich for the idea and technique.

Bug: 984742, 1006176, 1005678, 1005677, 1005248, 1005068, 1005066, 1006178, 1006071
Change-Id: I6a60e5a9b18588f56fff5b38a58c511f6ac0c850
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1817188
Commit-Queue: Chris Palmer <palmer@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#704306}
parent 6f7d1d8b
......@@ -11,8 +11,27 @@
#include "base/allocator/partition_allocator/partition_bucket.h"
#include "base/allocator/partition_allocator/partition_cookie.h"
#include "base/allocator/partition_allocator/partition_freelist_entry.h"
#include "base/allocator/partition_allocator/random.h"
#include "base/logging.h"
namespace {
// Returns true if we've hit the end of a random-length period. We don't want to
// invoke `RandomValue` too often, because we call this function in a hot spot
// (`Free`), and `RandomValue` incurs the cost of atomics.
#if !DCHECK_IS_ON()
bool RandomPeriod() {
static thread_local uint8_t counter = 0;
if (UNLIKELY(counter == 0)) {
counter = base::RandomValue();
}
counter--;
return counter == 0;
}
#endif
} // namespace
namespace base {
namespace internal {
......@@ -201,23 +220,29 @@ ALWAYS_INLINE size_t PartitionPage::get_raw_size() const {
}
ALWAYS_INLINE void PartitionPage::Free(void* ptr) {
#if DCHECK_IS_ON()
size_t slot_size = this->bucket->slot_size;
const size_t raw_size = get_raw_size();
if (raw_size) {
slot_size = raw_size;
}
#if DCHECK_IS_ON()
// If these asserts fire, you probably corrupted memory.
PartitionCookieCheckValue(ptr);
PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) + slot_size -
kCookieSize);
memset(ptr, kFreedByte, slot_size);
#else
// `memset` only once in a while.
if (UNLIKELY(RandomPeriod())) {
memset(ptr, kFreedByte, slot_size);
}
#endif
DCHECK(this->num_allocated_slots);
CHECK(ptr != freelist_head); // Catches an immediate double free.
// Catches an immediate double free.
CHECK(ptr != freelist_head);
// Look for double free one level deeper in debug.
DCHECK(!freelist_head || ptr != internal::PartitionFreelistEntry::Transform(
freelist_head->next));
......
......@@ -15,7 +15,7 @@ namespace base {
// `base::RandUint64` which is very unpredictable, but which is expensive due to
// the need to call into the kernel. Therefore this generator uses a fast,
// entirely user-space function after initialization.
uint32_t RandomValue();
BASE_EXPORT uint32_t RandomValue();
// Sets the seed for the random number generator to a known value, to cause the
// RNG to generate a predictable sequence of outputs. May be called multiple
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment