Skip to content

Commit 3baafef

Browse files
committed
src: properly manage timer in cares ChannelWrap
This fixes a bug introduced in 727b291 where code managing the `uv_timer_t` for a `ChannelWrap` instance was left unchanged, when it should have changed the lifetime of the handle to being tied to the `ChannelWrap` instance’s lifetime. Fixes: nodejs#14599 Ref: nodejs#14518
1 parent 1abfbbb commit 3baafef

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

src/cares_wrap.cc

+22-15
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,9 @@ class ChannelWrap : public AsyncWrap {
136136

137137
void Setup();
138138
void EnsureServers();
139+
void CleanupTimer();
139140

140-
inline uv_timer_t* timer_handle() { return &timer_handle_; }
141+
inline uv_timer_t* timer_handle() { return timer_handle_; }
141142
inline ares_channel cares_channel() { return channel_; }
142143
inline bool query_last_ok() const { return query_last_ok_; }
143144
inline void set_query_last_ok(bool ok) { query_last_ok_ = ok; }
@@ -152,7 +153,7 @@ class ChannelWrap : public AsyncWrap {
152153
static void AresTimeout(uv_timer_t* handle);
153154

154155
private:
155-
uv_timer_t timer_handle_;
156+
uv_timer_t* timer_handle_;
156157
ares_channel channel_;
157158
bool query_last_ok_;
158159
bool is_servers_default_;
@@ -163,6 +164,7 @@ class ChannelWrap : public AsyncWrap {
163164
ChannelWrap::ChannelWrap(Environment* env,
164165
Local<Object> object)
165166
: AsyncWrap(env, object, PROVIDER_DNSCHANNEL),
167+
timer_handle_(nullptr),
166168
channel_(nullptr),
167169
query_last_ok_(true),
168170
is_servers_default_(true),
@@ -236,7 +238,8 @@ RB_GENERATE_STATIC(node_ares_task_list, node_ares_task, node, cmp_ares_tasks)
236238
/* This is called once per second by loop->timer. It is used to constantly */
237239
/* call back into c-ares for possibly processing timeouts. */
238240
void ChannelWrap::AresTimeout(uv_timer_t* handle) {
239-
ChannelWrap* channel = ContainerOf(&ChannelWrap::timer_handle_, handle);
241+
ChannelWrap* channel = static_cast<ChannelWrap*>(handle->data);
242+
CHECK_EQ(channel->timer_handle(), handle);
240243
CHECK_EQ(false, RB_EMPTY(channel->task_list()));
241244
ares_process_fd(channel->cares_channel(), ARES_SOCKET_BAD, ARES_SOCKET_BAD);
242245
}
@@ -505,25 +508,29 @@ void ChannelWrap::Setup() {
505508

506509
/* Initialize the timeout timer. The timer won't be started until the */
507510
/* first socket is opened. */
508-
uv_timer_init(env()->event_loop(), &timer_handle_);
509-
env()->RegisterHandleCleanup(
510-
reinterpret_cast<uv_handle_t*>(&timer_handle_),
511-
[](Environment* env, uv_handle_t* handle, void* arg) {
512-
uv_close(handle, [](uv_handle_t* handle) {
513-
ChannelWrap* channel = ContainerOf(
514-
&ChannelWrap::timer_handle_,
515-
reinterpret_cast<uv_timer_t*>(handle));
516-
channel->env()->FinishHandleCleanup(handle);
517-
});
518-
},
519-
nullptr);
511+
CleanupTimer();
512+
timer_handle_ = new uv_timer_t();
513+
timer_handle_->data = static_cast<void*>(this);
514+
uv_timer_init(env()->event_loop(), timer_handle_);
520515
}
521516

522517

523518
ChannelWrap::~ChannelWrap() {
524519
if (library_inited_)
525520
ares_library_cleanup();
521+
526522
ares_destroy(channel_);
523+
CleanupTimer();
524+
}
525+
526+
void ChannelWrap::CleanupTimer() {
527+
if (!timer_handle_) return;
528+
529+
uv_close(reinterpret_cast<uv_handle_t*>(timer_handle_),
530+
[](uv_handle_t* handle) {
531+
delete reinterpret_cast<uv_timer_t*>(handle);
532+
});
533+
timer_handle_ = nullptr;
527534
}
528535

529536

0 commit comments

Comments
 (0)