[heap] Provide base::Malloc::AllocateAtLeast and use in Worklist
Provides a v8::base::Malloc::AllocateAtLeast() method that is also UBSan-safe and use it in the GC's worklist. Depends on https://crrev.com/c/3834601 Bug: v8:13193 Change-Id: I1bd182e613fb3c6a5a6b90bf56f12bd210d5ef8c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3833818 Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Anton Bikineev <bikineev@chromium.org> Cr-Commit-Position: refs/heads/main@{#82562}
This commit is contained in:
parent
d35f3e2bef
commit
01a8325a2c
@ -52,6 +52,9 @@
|
||||
|
||||
#if V8_OS_DARWIN
|
||||
#include <mach/mach.h>
|
||||
#include <malloc/malloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#if V8_OS_LINUX
|
||||
@ -1262,5 +1265,14 @@ Stack::StackSlot Stack::GetCurrentStackPosition() {
|
||||
#undef MAP_ANONYMOUS
|
||||
#undef MADV_FREE
|
||||
|
||||
// static
|
||||
size_t Malloc::GetUsableSize(void* ptr) {
|
||||
#if defined(V8_OS_DARWIN)
|
||||
return malloc_size(ptr);
|
||||
#else // defined(V8_OS_DARWIN)
|
||||
return malloc_usable_size(ptr);
|
||||
#endif // !defined(V8_OS_DARWIN)
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
@ -20,6 +20,7 @@
|
||||
// This has to come after windows.h.
|
||||
#include <VersionHelpers.h>
|
||||
#include <dbghelp.h> // For SymLoadModule64 and al.
|
||||
#include <malloc.h> // For _msize()
|
||||
#include <mmsystem.h> // For timeGetTime().
|
||||
#include <tlhelp32.h> // For Module32First and al.
|
||||
|
||||
@ -1765,5 +1766,8 @@ Stack::StackSlot Stack::GetCurrentStackPosition() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
size_t Malloc::GetUsableSize(void* ptr) { return _msize(ptr); }
|
||||
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "src/base/base-export.h"
|
||||
#include "src/base/build_config.h"
|
||||
#include "src/base/compiler-specific.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/base/platform/semaphore.h"
|
||||
@ -661,6 +662,42 @@ class V8_BASE_EXPORT Stack {
|
||||
}
|
||||
};
|
||||
|
||||
class V8_BASE_EXPORT Malloc final {
|
||||
public:
|
||||
// Returns the usable size in bytes for a `ptr` allocated using `malloc()`.
|
||||
// Note that the bytes returned may not be generally accessed on e.g. UBSan
|
||||
// builds. Use `AllocateAtLeast()` for a malloc version that works with UBSan.
|
||||
static size_t GetUsableSize(void* ptr);
|
||||
|
||||
// Mimics C++23 `allocation_result`.
|
||||
template <class Pointer>
|
||||
struct AllocationResult {
|
||||
Pointer ptr;
|
||||
std::size_t count;
|
||||
};
|
||||
|
||||
// Allocates at least `n * sizeof(T)` uninitialized storage but may allocate
|
||||
// more which is indicated by the return value. Mimics C++23
|
||||
// `allocate_ate_least()`.
|
||||
template <typename T>
|
||||
V8_NODISCARD static AllocationResult<T*> AllocateAtLeast(std::size_t n) {
|
||||
const size_t min_wanted_size = n * sizeof(T);
|
||||
auto* memory = static_cast<T*>(malloc(min_wanted_size));
|
||||
const size_t usable_size = v8::base::Malloc::GetUsableSize(memory);
|
||||
#if V8_USE_UNDEFINED_BEHAVIOR_SANITIZER
|
||||
// UBSan (specifically, -fsanitize=bounds) assumes that any access outside
|
||||
// of the requested size for malloc is UB and will trap in ud2 instructions.
|
||||
// This can be worked around by using `realloc()` on the specific memory
|
||||
// regon, assuming that the allocator doesn't actually reallocate the
|
||||
// buffer.
|
||||
if (usable_size != min_wanted_size) {
|
||||
CHECK_EQ(static_cast<T*>(realloc(memory, usable_size)), memory);
|
||||
}
|
||||
#endif // V8_USE_UNDEFINED_BEHAVIOR_SANITIZER
|
||||
return {memory, usable_size};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/base/atomic-utils.h"
|
||||
#include "src/base/logging.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
|
||||
namespace heap::base {
|
||||
namespace internal {
|
||||
@ -220,10 +221,10 @@ class Worklist<EntryType, MinSegmentSize>::Segment final
|
||||
: public internal::SegmentBase {
|
||||
public:
|
||||
static Segment* Create(uint16_t min_segment_size) {
|
||||
// TODO(v8:13193): Refer to a cross-platform `malloc_usable_size()` to make
|
||||
// use of all the memory allocated by `malloc()`.
|
||||
void* memory = malloc(MallocSizeForCapacity(min_segment_size));
|
||||
return new (memory) Segment(min_segment_size);
|
||||
auto result = v8::base::Malloc::AllocateAtLeast<char>(
|
||||
MallocSizeForCapacity(min_segment_size));
|
||||
return new (result.ptr)
|
||||
Segment(CapacityForMallocSize(result.count * sizeof(char)));
|
||||
}
|
||||
|
||||
static void Delete(Segment* segment) { free(segment); }
|
||||
@ -243,6 +244,9 @@ class Worklist<EntryType, MinSegmentSize>::Segment final
|
||||
static constexpr size_t MallocSizeForCapacity(size_t num_entries) {
|
||||
return sizeof(Segment) + sizeof(EntryType) * num_entries;
|
||||
}
|
||||
static constexpr size_t CapacityForMallocSize(size_t malloc_size) {
|
||||
return (malloc_size - sizeof(Segment)) / sizeof(EntryType);
|
||||
}
|
||||
|
||||
constexpr explicit Segment(size_t capacity)
|
||||
: internal::SegmentBase(capacity) {}
|
||||
|
Loading…
Reference in New Issue
Block a user