Files
v8/include/cppgc/explicit-management.h
Omer Katz f8a870eb01 [cppgc] Handle size overflows due to using AdditionalBytes
Whenever the API accepts an AdditionalBytes, it could potentially
overflow the size if additional bytes is huge. Limiting it to uint32_t
should suffice to prevent overflows on 64-bit machines. On 32-bit
machines we explicitly check for overflows.

Bug: 572627513
Change-Id: I6ccd57a6a1b9d02ba4644be2113602081fdbd9c0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8567760
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Omer Katz <omerkatz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#110706}
2026-10-14 05:48:30 -07:00

111 lines
3.7 KiB
C++

// Copyright 2021 the V8 project 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 INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#define INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_
#include <cstddef>
#include <limits>
#include "cppgc/allocation.h"
#include "cppgc/internal/logging.h"
#include "cppgc/type-traits.h"
namespace cppgc {
class HeapHandle;
namespace subtle {
template <typename T>
void FreeUnreferencedObject(HeapHandle& heap_handle, T& object);
template <typename T>
bool Resize(T& object, AdditionalBytes additional_bytes);
} // namespace subtle
namespace internal {
class ExplicitManagementImpl final {
private:
V8_EXPORT static void FreeUnreferencedObject(HeapHandle&, void*);
V8_EXPORT static bool Resize(void*, size_t);
template <typename T>
friend void subtle::FreeUnreferencedObject(HeapHandle&, T&);
template <typename T>
friend bool subtle::Resize(T&, AdditionalBytes);
};
} // namespace internal
namespace subtle {
/**
* Informs the garbage collector that `object` can be immediately reclaimed. The
* destructor may not be invoked immediately but only on next garbage
* collection.
*
* It is up to the embedder to guarantee that no other object holds a reference
* to `object` after calling `FreeUnreferencedObject()`. In case such a
* reference exists, it's use results in a use-after-free.
*
* To aid in using the API, `FreeUnreferencedObject()` may be called from
* destructors on objects that would be reclaimed in the same garbage collection
* cycle.
*
* \param heap_handle The corresponding heap.
* \param object Reference to an object that is of type `GarbageCollected` and
* should be immediately reclaimed.
*/
template <typename T>
void FreeUnreferencedObject(HeapHandle& heap_handle, T& object) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
internal::ExplicitManagementImpl::FreeUnreferencedObject(heap_handle,
&object);
}
/**
* Tries to resize `object` of type `T` with additional bytes on top of
* sizeof(T). Resizing is only useful with trailing inlined storage, see e.g.
* `MakeGarbageCollected(AllocationHandle&, AdditionalBytes)`.
*
* `Resize()` performs growing or shrinking as needed and may skip the operation
* for internal reasons, see return value.
*
* It is up to the embedder to guarantee that in case of shrinking a larger
* object down, the reclaimed area is not used anymore. Any subsequent use
* results in a use-after-free.
*
* The `object` must be live when calling `Resize()`.
*
* \param object Reference to an object that is of type `GarbageCollected` and
* should be resized.
* \param additional_bytes Bytes in addition to sizeof(T) that the object should
* provide.
* \returns true when the operation was successful and the result can be relied
* on, and false otherwise.
*/
template <typename T>
bool Resize(T& object, AdditionalBytes additional_bytes) {
static_assert(IsGarbageCollectedTypeV<T>,
"Object must be of type GarbageCollected.");
static_assert(sizeof(T) <= std::numeric_limits<uint32_t>::max());
const size_t new_object_size = sizeof(T) + additional_bytes.value;
// On 64-bit systems, since sizeof(T) and additional_bytes.value are both at
// most 32 bits, we know that their sum can't overflow. On 32-bit systems, we
// need to check it.
#if !defined(V8_HOST_ARCH_64_BIT)
if (new_object_size < sizeof(T)) {
return false;
}
#endif
return internal::ExplicitManagementImpl::Resize(&object, new_object_size);
}
} // namespace subtle
} // namespace cppgc
#endif // INCLUDE_CPPGC_EXPLICIT_MANAGEMENT_H_