This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
RFC: getifaddrs returns -1 with errno == 0, fix
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: libc-alpha at sourceware dot org
- Date: Mon, 04 Feb 2013 21:39:03 -0200
- Subject: RFC: getifaddrs returns -1 with errno == 0, fix
postfix was misbehaving on my yeeloong (just upgraded to Parabola
GNU/Linux-blire) when I connected my freerunner to it. It printed
âfatal: inet_addr_local[getifaddrs]: getifaddrs: Successâ and failed to
start daemons, to send messages, to print the mail queue, everything.
Without the freerunner, it worked just fine.
It turned out that getifaddrs() was indeed returning -1 without setting
errno, because the buffer allocated by __netlink_request wasn't large
enough to hold the response. The received message was marked as
truncated, and we bailed out(_fail) without setting any errors.
Rather than just fail, I experimented with growing the buffer and
retrying. I found out I had to consume the rest of the response to the
earlier request first, so I grew the buffer by just the right amount,
and that worked fine.
As an afterthought, I wondered if it would make more sense to just paste
the subsequent msgs into a larger buffer and be done with it, rather
than re-issuing the request. I don't know enough about netlink to tell
whether that's guaranteed to get the correct answer. Indeed, I'm not
even sure it's safe to consume the pending message fragments like I did.
Thoughts? Comments? Should I go with this, or grow the buffer
accummulating remaining fragments?
--- a/sysdeps/unix/sysv/linux/ifaddrs.c
+++ b/sysdeps/unix/sysv/linux/ifaddrs.c
@@ -135,13 +135,14 @@ __netlink_request (struct netlink_handle *h, int type)
#ifdef PAGE_SIZE
/* Help the compiler optimize out the malloc call if PAGE_SIZE
is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
- const size_t buf_size = PAGE_SIZE;
+ size_t buf_size = PAGE_SIZE;
#else
- const size_t buf_size = __getpagesize ();
+ size_t buf_size = __getpagesize ();
#endif
bool use_malloc = false;
char *buf;
+ retry:
if (__libc_use_alloca (buf_size))
buf = alloca (buf_size);
else
@@ -176,7 +177,23 @@ __netlink_request (struct netlink_handle *h, int type)
continue;
if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
- goto out_fail;
+ {
+ /* Consume the rest of the truncated response, then retry
+ with a larger buffer. */
+ do
+ {
+ read_len = TEMP_FAILURE_RETRY (__recvmsg (h->fd, &msg, 0));
+ if (read_len < 0)
+ break;
+ buf_size += read_len;
+ }
+ while ((msg.msg_flags & MSG_TRUNC) != 0);
+
+ if (use_malloc)
+ free (buf);
+ goto retry;
+ }
+
size_t count = 0;
size_t remaining_len = read_len;
--
Alexandre Oliva, freedom fighter http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/ FSF Latin America board member
Free Software Evangelist Red Hat Brazil Compiler Engineer