Question about internal field

29 views
Skip to first unread message

蔡曜丞(つむぎ)

unread,
Jun 10, 2025, 3:30:36 AMJun 10
to v8-users
Hi,

I'm updating v8 from v10.2.154.26 to v 12.4.254.
I found out kFinalizer is deprecated in the newer version so I have to rework the weakcall back part in my implementation.
When I simply change the kFinalizer in to kParameter in my SetWeak call, the program crashes when I calles SetAlignedPointerInInternalField in the destructor of my class under certain circumstance.
I'm wondering what's the correct way to use internal field, and the reason why it's crashing if I change WeakCallbackType from kFinalizer to kParameter.

The following is some code segment of my implementation.

class A {
    v8::Persistent<v8::Object> mObject;
}

A::~A ()
{
    if ( !mObject.IsEmpty() )
        mObject.ClearWeak();
    mObject.Reset();
}

void
A::Wrap (v8::Local<v8::Object> const &object)
{
    object->SetAlignedPointerInInternalField(0, this);
    mObject.Reset(v8::Isolate::GetCurrent(), object);
}

B::B() :A() {}

B::~B()
{
    if (!mObject.IsEmpty() && GetRuntime()->IsValid())
    {
        v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), mObject);
        obj->SetAlignedPointerInInternalField(0, NULL); // Crashes here, seems obj is already collected, Is this needed to prevent dangling pointer?
    }
}

C::C()
    :B()
{
    v8::Local<v8::Object> target =
    Initialize()->GetFunction(ctx).ToLocalChecked()
                ->NewInstance(ctx).ToLocalChecked();
   
    Wrap(target);
    mObject.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); // Was kFinalizer in previous version, no crash.
}

C::~C()
{
    mObject.ClearWeak();
}

void
B::WeakCallback(const v8::WeakCallbackInfo<C>& data)
{
    C* self = data.GetParameter();
    self->EarlyComplete();
    delete self;
}

jmr

unread,
Jul 19, 2025, 7:37:20 PMJul 19
to v8-users
I don't know how this worked in v10, but recent versions this is how you clean up native objects once js objects get collected:

static void weak_callback(const v8::WeakCallbackInfo<GarbageCollected>& data)
{
    data.GetParameter()->handle.Reset(); // Reset the handle that owns the object, you can't do ANYTHING else here. Effectively each GarbageCollected object in my case, has a handle to itself, keeping it alive.
    data.SetSecondPassCallback([](const v8::WeakCallbackInfo<GarbageCollected>& data) // Add a callback that gets called later by the GC, once the GC realises there are no more handles to the object. This is where actual GC happens.
    {
        delete data.GetParameter();
    });
}

J Decker

unread,
Jul 21, 2025, 4:41:06 AMJul 21
to v8-u...@googlegroups.com
On Tue, Jun 10, 2025 at 12:30 AM 蔡曜丞(つむぎ) <bobbyt...@gmail.com> wrote:
Hi,

I'm updating v8 from v10.2.154.26 to v 12.4.254.
I found out kFinalizer is deprecated in the newer version so I have to rework the weakcall back part in my implementation.
When I simply change the kFinalizer in to kParameter in my SetWeak call, the program crashes when I calles SetAlignedPointerInInternalField in the destructor of my class under certain circumstance.
I'm wondering what's the correct way to use internal field, and the reason why it's crashing if I change WeakCallbackType from kFinalizer to kParameter.

The following is some code segment of my implementation.

class A {
    v8::Persistent<v8::Object> mObject;
}

A::~A ()
{
    if ( !mObject.IsEmpty() )
        mObject.ClearWeak();
    mObject.Reset();
}

void
A::Wrap (v8::Local<v8::Object> const &object)
{
    object->SetAlignedPointerInInternalField(0, this);
    mObject.Reset(v8::Isolate::GetCurrent(), object);
}

B::B() :A() {}

B::~B()
{
    if (!mObject.IsEmpty() && GetRuntime()->IsValid())
    {
        v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(v8::Isolate::GetCurrent(), mObject);


I don't think a generic object has internal fields... all of my objects that have internal fields came from a FunctionTemplate which looks like

 volumeTemplate = FunctionTemplate::New( isolate, New );
volumeTemplate->SetClassName( String::NewFromUtf8Literal( isolate, "sack.vfs.Volume" ) );
volumeTemplate->InstanceTemplate()->SetInternalFieldCount( 1 ); // 1 required for wrap

...

save the function (or use getfunction later to get the constructor function instance

    c->volConstructor.Reset( isolate, volumeTemplate->GetFunction( isolate->GetCurrentContext() ).ToLocalChecked() );

get the constructor function 


   Local<Function> cons = Local<Function>::New( isolate, c->volConstructor );

// and then make an instance of that - this new object will have an internal field allocated for it.

   MaybeLocal<Object> mo = cons->NewInstance( context, argc, argv );


 
        obj->SetAlignedPointerInInternalField(0, NULL); // Crashes here, seems obj is already collected, Is this needed to prevent dangling pointer?
    }
}

C::C()
    :B()
{
    v8::Local<v8::Object> target =
    Initialize()->GetFunction(ctx).ToLocalChecked()
                ->NewInstance(ctx).ToLocalChecked();
   
    Wrap(target);
    mObject.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); // Was kFinalizer in previous version, no crash.
}

C::~C()
{
    mObject.ClearWeak();
}

void
B::WeakCallback(const v8::WeakCallbackInfo<C>& data)
{
    C* self = data.GetParameter();
    self->EarlyComplete();
    delete self;
}

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/v8-users/77f84ccf-b1ba-4967-81ab-89a312be8af3n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages