Skip to content

Commit 9b611d2

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 9e99e95 commit 9b611d2

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

src/node.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ class AsyncResource {
733733
trigger_async_id);
734734
}
735735

736-
~AsyncResource() {
736+
virtual ~AsyncResource() {
737737
EmitAsyncDestroy(isolate_, async_context_);
738738
}
739739

test/addons/async-resource/binding.cc

Lines changed: 22 additions & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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)