// Copyright 2020 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 V8_SANDBOX_EXTERNAL_POINTER_INL_H_ #define V8_SANDBOX_EXTERNAL_POINTER_INL_H_ #include "include/v8-internal.h" #include "src/base/atomic-utils.h" #include "src/execution/isolate.h" #include "src/sandbox/external-pointer-table-inl.h" #include "src/sandbox/external-pointer.h" namespace v8 { namespace internal { #ifdef V8_ENABLE_SANDBOX template <ExternalPointerTag tag> const ExternalPointerTable& GetExternalPointerTable(const Isolate* isolate) { return IsSharedExternalPointerType(tag) ? isolate->shared_external_pointer_table() : isolate->external_pointer_table(); } template <ExternalPointerTag tag> ExternalPointerTable& GetExternalPointerTable(Isolate* isolate) { return IsSharedExternalPointerType(tag) ? isolate->shared_external_pointer_table() : isolate->external_pointer_table(); } #endif // V8_ENABLE_SANDBOX template <ExternalPointerTag tag> V8_INLINE void InitExternalPointerField(Address field_address, Isolate* isolate, Address value) { #ifdef V8_ENABLE_SANDBOX if (IsSandboxedExternalPointerType(tag)) { ExternalPointerTable& table = GetExternalPointerTable<tag>(isolate); ExternalPointerHandle handle = table.AllocateAndInitializeEntry(isolate, value, tag); // Use a Release_Store to ensure that the store of the pointer into the // table is not reordered after the store of the handle. Otherwise, other // threads may access an uninitialized table entry and crash. auto location = reinterpret_cast<ExternalPointerHandle*>(field_address); base::AsAtomic32::Release_Store(location, handle); return; } #endif // V8_ENABLE_SANDBOX WriteExternalPointerField<tag>(field_address, isolate, value); } template <ExternalPointerTag tag> V8_INLINE Address ReadExternalPointerField(Address field_address, const Isolate* isolate) { #ifdef V8_ENABLE_SANDBOX if (IsSandboxedExternalPointerType(tag)) { // Handles may be written to objects from other threads so the handle needs // to be loaded atomically. We assume that the load from the table cannot // be reordered before the load of the handle due to the data dependency // between the two loads and therefore use relaxed memory ordering. auto location = reinterpret_cast<ExternalPointerHandle*>(field_address); ExternalPointerHandle handle = base::AsAtomic32::Relaxed_Load(location); return GetExternalPointerTable<tag>(isolate).Get(handle, tag); } #endif // V8_ENABLE_SANDBOX return ReadMaybeUnalignedValue<Address>(field_address); } template <ExternalPointerTag tag> V8_INLINE void WriteExternalPointerField(Address field_address, Isolate* isolate, Address value) { #ifdef V8_ENABLE_SANDBOX if (IsSandboxedExternalPointerType(tag)) { // See comment above for why this is a Relaxed_Load. auto location = reinterpret_cast<ExternalPointerHandle*>(field_address); ExternalPointerHandle handle = base::AsAtomic32::Relaxed_Load(location); GetExternalPointerTable<tag>(isolate).Set(handle, value, tag); return; } #endif // V8_ENABLE_SANDBOX WriteMaybeUnalignedValue<Address>(field_address, value); } template <ExternalPointerTag tag> V8_INLINE void WriteLazilyInitializedExternalPointerField(Address field_address, Isolate* isolate, Address value) { #ifdef V8_ENABLE_SANDBOX if (IsSandboxedExternalPointerType(tag)) { // See comment above for why this uses a Relaxed_Load and Release_Store. ExternalPointerTable& table = GetExternalPointerTable<tag>(isolate); auto location = reinterpret_cast<ExternalPointerHandle*>(field_address); ExternalPointerHandle handle = base::AsAtomic32::Relaxed_Load(location); if (handle == kNullExternalPointerHandle) { // Field has not been initialized yet. ExternalPointerHandle handle = table.AllocateAndInitializeEntry(isolate, value, tag); base::AsAtomic32::Release_Store(location, handle); } else { table.Set(handle, value, tag); } return; } #endif // V8_ENABLE_SANDBOX WriteMaybeUnalignedValue<Address>(field_address, value); } } // namespace internal } // namespace v8 #endif // V8_SANDBOX_EXTERNAL_POINTER_INL_H_