-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
dns: refactor QueryWrap lifetime management
- Prefer RAII-style management over manual resource management. - Prefer `env->SetImmediate()` over a separate `uv_async_t`. - Perform `ares_destroy()` before possibly tearing down c-ares state. - Verify that the number of active queries is non-negative. - Let pending callbacks know when their underlying `QueryWrap` object has been destroyed. The last item has been a real bug, in that when Workers shut down during currently running DNS queries, they may run into use-after-free situations because: 1. Shutting the `Worker` down leads to the cleanup code deleting the `QueryWrap` objects first; then 2. deleting the `ChannelWrap` object (as it has been created before the `QueryWrap`s), whose destructor runs `ares_destroy()`, which in turn invokes all pending query callbacks with `ARES_ECANCELLED`, 3. which lead to use-after-free, as the callback tried to access the deleted `QueryWrap` object. The added test verifies that this is no longer an issue. PR-URL: #26253 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
- Loading branch information
Showing
2 changed files
with
87 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
'use strict'; | ||
const common = require('../common'); | ||
const { Resolver } = require('dns'); | ||
const dgram = require('dgram'); | ||
const { Worker, isMainThread } = require('worker_threads'); | ||
|
||
// Test that Workers can terminate while DNS queries are outstanding. | ||
|
||
if (isMainThread) { | ||
return new Worker(__filename); | ||
} | ||
|
||
const socket = dgram.createSocket('udp4'); | ||
|
||
socket.bind(0, common.mustCall(() => { | ||
const resolver = new Resolver(); | ||
resolver.setServers([`127.0.0.1:${socket.address().port}`]); | ||
resolver.resolve4('example.org', common.mustNotCall()); | ||
})); | ||
|
||
socket.on('message', common.mustCall(() => { | ||
process.exit(); | ||
})); |