-
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: report out of memory properly #20317
Conversation
I added a test to your branch. It's in its own commit so you can remove that commit if you're 👎 on the test, but I think it's probably useful. |
lib/internal/errors.js
Outdated
@@ -639,8 +638,7 @@ function dnsException(code, syscall, hostname) { | |||
if (typeof code === 'number') { | |||
// FIXME(bnoordhuis) Remove this backwards compatibility nonsense and pass | |||
// the true error to the user. ENOTFOUND is not even a proper POSIX error! | |||
if (code === UV_EAI_MEMORY || | |||
code === UV_EAI_NODATA || | |||
if (code === UV_EAI_NODATA || | |||
code === UV_EAI_NONAME) { |
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.
Fits on one line now.
This addresses a part of a TODO by properly reporting an out of memory error to the user instead of reporting `ENOTFOUND`.
Add test that confirms that when libuv reports a memory error on a DNS query, that the memory error is passed through and not replaced with ENOTFOUND.
b91f209
to
1609ba1
Compare
Nit addressed. New CI: https://ci.nodejs.org/job/node-test-pull-request/14520/ @Trott I guess it is best to land this as separate commits and not squash? |
Ah, I fixed the commit message @Trott (typo in |
Hmmm...puzzling. A relevant test fails but only SmartOS. |
Re-running SmartOS just in case it was some kind of weird quirk: https://ci.nodejs.org/job/node-test-commit-smartos/17213/ |
So, |
@bnoordhuis could you have a look at the test failure? You added it originally. I personally can not see anything special or wrong in the test, so it seems to be a low level platform specific issue. /cc @nodejs/libuv |
Not much to look at. The system resolver reports |
@bnoordhuis thanks for clariying. But is |
@bnoordhuis reducing the hostname to a byteLength of 250 still returns the OOM error.
|
test/parallel/test-http-dns-error.js
Outdated
@@ -29,7 +29,7 @@ const assert = require('assert'); | |||
const http = require('http'); | |||
const https = require('https'); | |||
|
|||
const host = '*'.repeat(256); | |||
const host = '*'.repeat(250); |
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.
I know you were doing this just to see if the OOM error went away on SmartOS, but I think 256 was chosen specifically because 255 is the maximum length for a hostname. I believe the idea here is to trigger a hostname-too-long error specifically. So this change should not land, I suspect.
Here's a simple test case: const cares = process.binding('cares_wrap');
const {
UV_EAI_MEMORY,
UV_EAI_NODATA,
UV_EAI_NONAME
} = process.binding('uv');
var req = new cares.GetAddrInfoReqWrap();
req.family = 0;
req.hostname = '*'.repeat(256);
req.oncomplete = (e) => {
console.log(`error code was ${e}`);
console.log(`UV_EAI_MEMORY: ${UV_EAI_MEMORY}`);
console.log(`UV_EAI_NODATA: ${UV_EAI_NODATA}`);
console.log(`UV_EAI_NONAME: ${UV_EAI_NONAME}`);
}
var err = cares.getaddrinfo(req, req.hostname, req.family, 1024, false); This straightforward test case does not result in [root@0410827e-87c7-449e-b16c-d626f9743aa6 /home/iojs/build/workspace/node-test-commit-smartos/nodes/smartos16-64]# /var/tmp/node /var/tmp/test.js
error code was -3002
UV_EAI_MEMORY: -3006
UV_EAI_NODATA: -3007
UV_EAI_NONAME: -3008
[root@0410827e-87c7-449e-b16c-d626f9743aa6 /home/iojs/build/workspace/node-test-commit-smartos/nodes/smartos16-64]# So something more....subtle...is going on with the SmartOS hosts in CI. |
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.
Defensively giving this a red X while the 256
is down to 250
because I do think that may invalidate the intended test case.
Oh, wait, |
OK, here's code to replicate the problem: const cares = process.binding('cares_wrap');
const {
UV_EAI_MEMORY,
UV_EAI_NODATA,
UV_EAI_NONAME
} = process.binding('uv');
var req = new cares.GetAddrInfoReqWrap();
req.family = 0;
req.hostname = '*'.repeat(256);
req.oncomplete = (e) => {
console.log(`error code was ${e}`);
console.log(`UV_EAI_MEMORY: ${UV_EAI_MEMORY}`);
console.log(`UV_EAI_NODATA: ${UV_EAI_NODATA}`);
console.log(`UV_EAI_NONAME: ${UV_EAI_NONAME}`);
}
cares.getaddrinfo(req, req.hostname, req.family, 0, false); Running this on SmartOS: error code was -3006
UV_EAI_MEMORY: -3006
UV_EAI_NODATA: -3007
UV_EAI_NONAME: -3008
For comparison, running it locally on my Macbook results -3008 which is Back to SmartOS:
So there's something specific about length of 256 that results in an OOM error but I have to imagine that OOM error is spurious. (And I don't know why @BridgeAR got different results when changing the hostname length in the test to 250.) |
@Trott I did not plan on landing it with the test change. I am not really sure what to do with your findings though due to the difference with my change... |
Oh, for newly-looped-in people who want the TL;DR, I think the crux of the problem is described in #20317 (comment). |
(I suppose it could also be a |
Libuv calls |
I bet this SmartOS behavior is probably why |
Sure enough this C program confirms it's specific to SmartOS (or at least our SmartOS hosts in CI): #include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
struct addrinfo hints, *infoptr; // So no need to use memset global variables
int main() {
hints.ai_family = AF_INET; // AF_INET means IPv4 only addresses
int result = getaddrinfo("****************************************************************************************************************************************************************************************************************************************************************", NULL, &hints, &infoptr);
if (result) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
exit(1);
}
struct addrinfo *p;
char host[256];
for(p = infoptr; p != NULL; p = p->ai_next) {
getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof(host), NULL, 0,
NI_NUMERICHOST);
puts(host);
}
freeaddrinfo(infoptr);
return 0;
} (This is trivially modified from sample code at https://github.com/angrave/SystemProgramming/wiki/Networking,-Part-2:-Using-getaddrinfo.) On SmartOS, I put it in [root@527b0138-1d1d-6bcc-88a3-9968feaab1eb /var/tmp]# ./a.out
getaddrinfo: memory allocation failure
[root@527b0138-1d1d-6bcc-88a3-9968feaab1eb /var/tmp]# For comparison, when running on macOS: $ ./a.out
getaddrinfo: nodename nor servname provided, or not known
$ |
Looking through git history, I'm unconvinced of the correctness of my recollection that 256 length is significant. 64 is long enough to guarantee the hostname is invalid as long as there's no |
(If you change it to |
|
This addresses a part of a TODO by properly reporting an out of memory error to the user instead of reporting `ENOTFOUND`. PR-URL: nodejs#20317 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Add test that confirms that when libuv reports a memory error on a DNS query, that the memory error is passed through and not replaced with ENOTFOUND. PR-URL: nodejs#20317 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This addresses a part of a TODO by properly reporting an out of
memory error to the user instead of reporting
ENOTFOUND
.I only changed this single entry as this is super rare and should be
safe
to change.Since it is a OOM, we also have no test for it.
The other two are likely used a lot and a lot of userland code will rely on that.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes