Skip to content

Commit d223e3c

Browse files
committed
src: make AsyncResource destructor virtual
`AsyncResource` is intended to be a base class, and since we don’t know what API consumers will do with it in their own code, it’s good practice to make its destructor virtual. This should not be ABI-breaking since all class methods are inline. PR-URL: #20633 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent b795953 commit d223e3c

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

src/node.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ class AsyncResource {
712712
trigger_async_id);
713713
}
714714

715-
~AsyncResource() {
715+
virtual ~AsyncResource() {
716716
EmitAsyncDestroy(isolate_, async_context_);
717717
}
718718

test/addons/async-resource/binding.cc

+22
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ using v8::Object;
1717
using v8::String;
1818
using v8::Value;
1919

20+
int custom_async_resource_destructor_calls = 0;
21+
22+
class CustomAsyncResource : public AsyncResource {
23+
public:
24+
CustomAsyncResource(Isolate* isolate, Local<Object> resource)
25+
: AsyncResource(isolate, resource, "CustomAsyncResource") {}
26+
~CustomAsyncResource() {
27+
custom_async_resource_destructor_calls++;
28+
}
29+
};
30+
2031
void CreateAsyncResource(const FunctionCallbackInfo<Value>& args) {
2132
Isolate* isolate = args.GetIsolate();
2233
assert(args[0]->IsObject());
@@ -98,6 +109,16 @@ void GetResource(const FunctionCallbackInfo<Value>& args) {
98109
args.GetReturnValue().Set(r->get_resource());
99110
}
100111

112+
void RunSubclassTest(const FunctionCallbackInfo<Value>& args) {
113+
Isolate* isolate = args.GetIsolate();
114+
Local<Object> obj = Object::New(isolate);
115+
116+
assert(custom_async_resource_destructor_calls == 0);
117+
CustomAsyncResource* resource = new CustomAsyncResource(isolate, obj);
118+
delete static_cast<AsyncResource*>(resource);
119+
assert(custom_async_resource_destructor_calls == 1);
120+
}
121+
101122
void Initialize(Local<Object> exports) {
102123
NODE_SET_METHOD(exports, "createAsyncResource", CreateAsyncResource);
103124
NODE_SET_METHOD(exports, "destroyAsyncResource", DestroyAsyncResource);
@@ -107,6 +128,7 @@ void Initialize(Local<Object> exports) {
107128
NODE_SET_METHOD(exports, "getAsyncId", GetAsyncId);
108129
NODE_SET_METHOD(exports, "getTriggerAsyncId", GetTriggerAsyncId);
109130
NODE_SET_METHOD(exports, "getResource", GetResource);
131+
NODE_SET_METHOD(exports, "runSubclassTest", RunSubclassTest);
110132
}
111133

112134
} // anonymous namespace

test/addons/async-resource/test.js

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const assert = require('assert');
55
const binding = require(`./build/${common.buildType}/binding`);
66
const async_hooks = require('async_hooks');
77

8+
binding.runSubclassTest();
9+
810
const kObjectTag = Symbol('kObjectTag');
911
const rootAsyncId = async_hooks.executionAsyncId();
1012

0 commit comments

Comments
 (0)