summaryrefslogtreecommitdiff
path: root/ext/socket
diff options
context:
space:
mode:
authorKJ Tsanaktsidis <ktsanaktsidis@zendesk.com>2024-01-22 12:06:03 +1100
committerKJ Tsanaktsidis <kj@kjtsanaktsidis.id.au>2024-01-22 14:34:31 +1100
commit6c0e58a54e3fda604386d9c409e2a9998bbc9352 (patch)
tree653b9271c7182c83bfb7fe4d6e87e74ab4334cc4 /ext/socket
parentce5e7629b57904c34a529372f365e04d4f9abb06 (diff)
Make sure the correct error is raised for EAI_SYSTEM resolver fail
In case of EAI_SYSTEM, getaddrinfo is supposed to set more detail in errno; however, because we call getaddrinfo on a thread now, and errno is threadlocal, that information is being lost. Instead, we just raise whatever errno happens to be on the calling thread (which can be something very confusing, like `ECHILD`). Fix it by explicitly propagating errno back to the calling thread through the getaddrinfo_arg structure. [Bug #20198]
Diffstat (limited to 'ext/socket')
-rw-r--r--ext/socket/raddrinfo.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index 560312741f..cdb785f268 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -345,7 +345,7 @@ struct getaddrinfo_arg
char *node, *service;
struct addrinfo hints;
struct addrinfo *ai;
- int err, refcount, done, cancelled;
+ int err, gai_errno, refcount, done, cancelled;
rb_nativethread_lock_t lock;
rb_nativethread_cond_t cond;
};
@@ -406,8 +406,9 @@ do_getaddrinfo(void *ptr)
{
struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
- int err;
+ int err, gai_errno;
err = getaddrinfo(arg->node, arg->service, &arg->hints, &arg->ai);
+ gai_errno = errno;
#ifdef __linux__
/* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
* it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
@@ -420,6 +421,7 @@ do_getaddrinfo(void *ptr)
rb_nativethread_lock_lock(&arg->lock);
{
arg->err = err;
+ arg->gai_errno = gai_errno;
if (arg->cancelled) {
freeaddrinfo(arg->ai);
}
@@ -479,7 +481,7 @@ rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hint
{
int retry;
struct getaddrinfo_arg *arg;
- int err;
+ int err, gai_errno;
start:
retry = 0;
@@ -503,6 +505,7 @@ start:
{
if (arg->done) {
err = arg->err;
+ gai_errno = arg->gai_errno;
if (err == 0) *ai = arg->ai;
}
else if (arg->cancelled) {
@@ -525,6 +528,10 @@ start:
rb_thread_check_ints();
if (retry) goto start;
+ /* Because errno is threadlocal, the errno value we got from the call to getaddrinfo() in the thread
+ * (in case of EAI_SYSTEM return value) is not propagated to the caller of _this_ function. Set errno
+ * explicitly, as round-tripped through struct getaddrinfo_arg, to deal with that */
+ errno = gai_errno;
return err;
}
@@ -591,7 +598,7 @@ struct getnameinfo_arg
size_t hostlen;
char *serv;
size_t servlen;
- int err, refcount, done, cancelled;
+ int err, gni_errno, refcount, done, cancelled;
rb_nativethread_lock_t lock;
rb_nativethread_cond_t cond;
};
@@ -644,12 +651,14 @@ do_getnameinfo(void *ptr)
{
struct getnameinfo_arg *arg = (struct getnameinfo_arg *)ptr;
- int err;
+ int err, gni_errno;
err = getnameinfo(arg->sa, arg->salen, arg->host, (socklen_t)arg->hostlen, arg->serv, (socklen_t)arg->servlen, arg->flags);
+ gni_errno = errno;
int need_free = 0;
rb_nativethread_lock_lock(&arg->lock);
arg->err = err;
+ arg->gni_errno = gni_errno;
if (!arg->cancelled) {
arg->done = 1;
rb_native_cond_signal(&arg->cond);
@@ -691,7 +700,7 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
{
int retry;
struct getnameinfo_arg *arg;
- int err;
+ int err, gni_errno;
start:
retry = 0;
@@ -714,6 +723,7 @@ start:
rb_nativethread_lock_lock(&arg->lock);
if (arg->done) {
err = arg->err;
+ gni_errno = arg->gni_errno;
if (err == 0) {
if (host) memcpy(host, arg->host, hostlen);
if (serv) memcpy(serv, arg->serv, servlen);
@@ -738,6 +748,9 @@ start:
rb_thread_check_ints();
if (retry) goto start;
+ /* Make sure we copy the thread-local errno value from the getnameinfo thread back to this thread, so
+ * calling code sees the correct errno */
+ errno = gni_errno;
return err;
}