* sysdeps/unix/sysv/linux/check_pf.c (make_request): Add out_fail2 label to be used after in6ailist is initialized. [BZ #16002] * sysdeps/unix/sysv/linux/check_pf.c (make_request): Use alloca_account and account alloca use for struct in6ailist. Index: glibc-2.19/sysdeps/unix/sysv/linux/check_pf.c =================================================================== --- glibc-2.19.orig/sysdeps/unix/sysv/linux/check_pf.c +++ glibc-2.19/sysdeps/unix/sysv/linux/check_pf.c @@ -106,6 +106,11 @@ cache_valid_p (void) static struct cached_data * make_request (int fd, pid_t pid) { + struct cached_data *result = NULL; + + size_t result_len = 0; + size_t result_cap = 32; + struct req { struct nlmsghdr nlh; @@ -137,19 +142,9 @@ make_request (int fd, pid_t pid) #else const size_t buf_size = __getpagesize (); #endif - bool use_malloc = false; char *buf; - if (__libc_use_alloca (buf_size)) - buf = alloca (buf_size); - else - { - buf = malloc (buf_size); - if (buf != NULL) - use_malloc = true; - else - goto out_fail; - } + buf = alloca (buf_size); struct iovec iov = { buf, buf_size }; @@ -159,12 +154,7 @@ make_request (int fd, pid_t pid) goto out_fail; bool done = false; - struct in6ailist - { - struct in6addrinfo info; - struct in6ailist *next; - } *in6ailist = NULL; - size_t in6ailistlen = 0; + bool seen_ipv4 = false; bool seen_ipv6 = false; @@ -239,28 +229,36 @@ make_request (int fd, pid_t pid) } } - struct in6ailist *newp = alloca (sizeof (*newp)); - newp->info.flags = (((ifam->ifa_flags - & (IFA_F_DEPRECATED - | IFA_F_OPTIMISTIC)) - ? in6ai_deprecated : 0) - | ((ifam->ifa_flags - & IFA_F_HOMEADDRESS) - ? in6ai_homeaddress : 0)); - newp->info.prefixlen = ifam->ifa_prefixlen; - newp->info.index = ifam->ifa_index; + if (result_len == 0 || result_len == result_cap) + { + result_cap = 2 * result_cap; + result = realloc (result, sizeof (*result) + + result_cap * sizeof (struct in6addrinfo)); + } + + if (!result) + goto out_fail; + + struct in6addrinfo *info = &result->in6ai[result_len++]; + + info->flags = (((ifam->ifa_flags + & (IFA_F_DEPRECATED + | IFA_F_OPTIMISTIC)) + ? in6ai_deprecated : 0) + | ((ifam->ifa_flags + & IFA_F_HOMEADDRESS) + ? in6ai_homeaddress : 0)); + info->prefixlen = ifam->ifa_prefixlen; + info->index = ifam->ifa_index; if (ifam->ifa_family == AF_INET) { - newp->info.addr[0] = 0; - newp->info.addr[1] = 0; - newp->info.addr[2] = htonl (0xffff); - newp->info.addr[3] = *(const in_addr_t *) address; + info->addr[0] = 0; + info->addr[1] = 0; + info->addr[2] = htonl (0xffff); + info->addr[3] = *(const in_addr_t *) address; } else - memcpy (newp->info.addr, address, sizeof (newp->info.addr)); - newp->next = in6ailist; - in6ailist = newp; - ++in6ailistlen; + memcpy (info->addr, address, sizeof (info->addr)); } else if (nlmh->nlmsg_type == NLMSG_DONE) /* We found the end, leave the loop. */ @@ -269,42 +267,29 @@ make_request (int fd, pid_t pid) } while (! done); - struct cached_data *result; - if (seen_ipv6 && in6ailist != NULL) + if (seen_ipv6 && result != NULL) { - result = malloc (sizeof (*result) - + in6ailistlen * sizeof (struct in6addrinfo)); - if (result == NULL) - goto out_fail; - result->timestamp = get_nl_timestamp (); result->usecnt = 2; result->seen_ipv4 = seen_ipv4; result->seen_ipv6 = true; - result->in6ailen = in6ailistlen; - - do - { - result->in6ai[--in6ailistlen] = in6ailist->info; - in6ailist = in6ailist->next; - } - while (in6ailist != NULL); + result->in6ailen = result_len; } else { + free (result); + atomic_add (&noai6ai_cached.usecnt, 2); noai6ai_cached.seen_ipv4 = seen_ipv4; noai6ai_cached.seen_ipv6 = seen_ipv6; result = &noai6ai_cached; } - if (use_malloc) - free (buf); return result; -out_fail: - if (use_malloc) - free (buf); + out_fail: + + free (result); return NULL; }