-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dns: fix crash while setting server during query #14891
Conversation
Occasional crash in this PR:
@addaleax Do you have any idea with this crash? |
I have got some questions before doing a full review, I hope you don't mind:
|
Heads up: This is going to conflict with #14826 |
I think an easier fix would be to wait with actually carrying out |
Easier, yes, and probably less error-prone, but that can cause unexpected delays, especially when using the default resolver. I am still in favor of permitting this behavior upstream if there is no good reason to disallow it. And if there is a good reason to disallow it, we should probably do the same instead of working around the actual problem like this. |
C-ARES is not designed for libuv. If we use it in multi-thread, some locks are needed. Imagine this situation in Node.js: dns.resolve4('google.com', common.mustCall(function(/* err, nameServers */) {
dns.setServers([ '8.8.8.8' ]);
}));
dns.resolve4('google.com', common.mustCall(function() {
// do nothing...
})); If the first |
Doesn't it block the event loop? |
Sorry, I don't really get your point here. How is this related to threads? (c-ares does not use threads internally as far as I know, but I might be wrong.) |
@tniessen But Node.js do |
Where do we stand here? |
@BridgeAR Sorry but I don't quite understand what you mean. |
@XadillaX you posted that this PR this has an issue, there was no proper review yet and the last update was more then two weeks before my post. Therefore my question is how this is further progressing. Did you look into the issue again? |
351c3d7
to
6e0e0ff
Compare
By the way, I just noticed the documentation explicitely prohibits this behavior:
|
@XadillaX I am not sure – can you explain what the job of the added threading in this PR is? Previously, everything was single-threaded with no synchronization needed… |
@addaleax You see this example: dns.resolve4('google.com', common.mustCall(function(/* err, nameServers */) {
dns.setServer([ '8.8.8.8' ]);
});
dns.resolve4('google.com', common.mustCall(function() {
// DO NOTHING
})); Sometime this example will crash because when we are doing the second |
@XadillaX Yes, I understand the problem. What I don’t understand so much is why using multi-threading is helpful to solve it. |
If I do not use multithread, the main eventloop will be blocked by lock. |
@XadillaX I see! There is at least one problem, though: If you look up the docs for Also, I think this adds a lot of complexity for behaviour that is arguably not a bug, because this is explicitly forbidden by our documentation. I could think of these alternative approaches:
What do you think? |
|
@XadillaX Yes, I don’t like 2 either. For 1 and 3, I think either is fine, and I wouldn’t worry about performance too much as I can’t imagine anybody is calling |
@addaleax Sorry I read it wrong. I read it as creating a new channel everytime Now I agree with 1 and 3. And I'll continue working for it. |
Ping @XadillaX you still want to follow up on this and rework the PR, right? |
Ping @XadillaX |
@XadillaX Yes – I think why this works a lot of the time is that I think for now you should be fine moving the added tests from this PR into a new file, don’t worry about |
/cc @addaleax I've updated the test case. |
addresses.INET4_HOST, | ||
common.mustCall(function() { | ||
// DO NOTHING | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tiny nit
A must call does not require a noop function.
}, common.expectsError({ | ||
code: 'ERR_DNS_SET_SERVERS_FAILED', | ||
message: /^c-ares failed to set servers: "There are pending queries\." \[.+\]$/g | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tiny nit
You could use common.expectsError(throwingFn, errorObj)
instead of assert.throws(throwingFn, common.expectsError(errorObj))
.
|
||
dns.resolve('localhost', function(err/*, ret*/) { | ||
// nothing | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use common.mustCall
for the noop functions in this test? Or are they actually not called at all? In that case a mustNotCall
could be used.
Landed in b3678df … finally. ;) Thanks for sticking with this PR and pushing it through! |
Fix this issue follow these two points: 1. Keep track of how many queries are currently open. If `setServers()` is called while there are open queries, error out. 2. For `Resolver` instances, use option 1. For dns.setServers(), just create a fresh new default channel every time it is called, and then set its servers list. PR-URL: #14891 Fixes: #14734 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Fix this issue follow these two points: 1. Keep track of how many queries are currently open. If `setServers()` is called while there are open queries, error out. 2. For `Resolver` instances, use option 1. For dns.setServers(), just create a fresh new default channel every time it is called, and then set its servers list. PR-URL: #14891 Fixes: #14734 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Fix this issue follow these two points: 1. Keep track of how many queries are currently open. If `setServers()` is called while there are open queries, error out. 2. For `Resolver` instances, use option 1. For dns.setServers(), just create a fresh new default channel every time it is called, and then set its servers list. PR-URL: #14891 Fixes: #14734 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Fix this issue follow these two points: 1. Keep track of how many queries are currently open. If `setServers()` is called while there are open queries, error out. 2. For `Resolver` instances, use option 1. For dns.setServers(), just create a fresh new default channel every time it is called, and then set its servers list. Fixes: #14734 PR-URL: #14891 Backport-PR-URL: #17778 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Fix this issue follow these two points:
setServers()
is called while there are open queries, error out.
Resolver
instances, use option 1. For dns.setServers(), justcreate a fresh new default channel every time it is called, and then
set its servers list.
Fixes: #14734
Checklist
make -j4 test
passesAffected core subsystem(s)
dns, cares