Skip to content

Commit

Permalink
Merge pull request nodejs#1 from zawata/SetEmbedderIDInWrapper
Browse files Browse the repository at this point in the history
Set Embedder ID when wrapping object
  • Loading branch information
ianhattendorf committed Nov 2, 2022
2 parents 43e612d + 6daf590 commit 0ae02e3
Showing 1 changed file with 34 additions and 4 deletions.
38 changes: 34 additions & 4 deletions nan_object_wrap.h
Expand Up @@ -9,6 +9,15 @@
#ifndef NAN_OBJECT_WRAP_H_
#define NAN_OBJECT_WRAP_H_

#include <cstdint>

namespace {
// this can be any value so long as it's 16bits and doesn't conflict
// with any chromium IDs:
// https://source.chromium.org/chromium/chromium/src/+/936f9f68:gin/public/gin_embedders.h;l=18
static uint16_t kEmbedderId = 0xBEEF;
}

class ObjectWrap {
public:
ObjectWrap() {
Expand All @@ -29,10 +38,10 @@ class ObjectWrap {
template <class T>
static inline T* Unwrap(v8::Local<v8::Object> object) {
assert(!object.IsEmpty());
assert(object->InternalFieldCount() > 0);
assert(object->InternalFieldCount() > InternalFields::kSlot);
// Cast to ObjectWrap before casting to T. A direct cast from void
// to T won't work right when T has more than one base class.
void* ptr = GetInternalFieldPointer(object, 0);
void* ptr = GetInternalFieldPointer(object, InternalFields::kSlot);
ObjectWrap* wrap = static_cast<ObjectWrap*>(ptr);
return static_cast<T*>(wrap);
}
Expand All @@ -49,10 +58,31 @@ class ObjectWrap {


protected:
// These fields must match internal v8 EmbedderDataSlot Indicies.
// unfortunately they are not centralized anywhere so we have to make our own
// chromium examples:
// https://source.chromium.org/chromium/chromium/src/+/936f9f68:v8/src/heap/embedder-tracing.h;l=176
// https://source.chromium.org/chromium/chromium/src/+/936f9f68:gin/public/wrapper_info.h;l=19
enum InternalFields {
kWrapperType,
kSlot,
kInternalFieldCount
};

inline void Wrap(v8::Local<v8::Object> object) {
assert(persistent().IsEmpty());
assert(object->InternalFieldCount() > 0);
SetInternalFieldPointer(object, 0, this);
assert(object->InternalFieldCount() > InternalFields::kSlot);
/**
* In Isolates(contexts?) with cppgc enabled, v8 assumes the first type slot
* is a pointer to a "type info" struct which has an "Embedder ID" at the
* first 2 bytes. If the first 2 bytes at `this` contain an ID that matches
* an internal one then multiple issues can happen(mostly it will segfault)
* as v8 assumes it's an internal object. Simple fix is to set the slot to
* an ID that doesn't match any internal embedders(notably blink) so v8
* doesn't try to mess with it.
**/
SetInternalFieldPointer(object, InternalFields::kWrapperType, &kEmbedderId);
SetInternalFieldPointer(object, InternalFields::kSlot, this);
persistent().Reset(object);
MakeWeak();
}
Expand Down

0 comments on commit 0ae02e3

Please sign in to comment.