This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: RFC: getifaddrs returns -1 with errno == 0, fix
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: libc-alpha at sourceware dot org
- Date: Tue, 17 Sep 2013 19:52:04 -0300
- Subject: Re: RFC: getifaddrs returns -1 with errno == 0, fix
- Authentication-results: sourceware.org; auth=none
- References: <or4nhrsl7s dot fsf at livre dot home>
On Feb 4, 2013, Alexandre Oliva <aoliva@redhat.com> wrote:
> 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?
Ping?
for ChangeLog
* sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Grow
buffer and retry when message is fragmented.
---
sysdeps/unix/sysv/linux/ifaddrs.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c
index 89fda15..c9decc3 100644
--- 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