Hi Waldemar,
there's an example of buildroot package that fails to build when using
isalnum_l:
http://autobuild.buildroot.net/results/b7ba1210d5aa184b133f0171da621d2b0083…
AFAICS include/ctype.h defines the following chain of macros for it:
isalnum_l -> __isalnum_l -> __isctype_l
and __isctype_l tries to dereference __ctype_b field in the l parameter
which is of incomplete type.
The easiest fix for that seems to be not providing macro definitions for
isalnum_l and friends.
I also tried to follow the way it was intended to work with macros, but
that seemed a bit too convoluted.
What do you think the fix could be?
--
Thanks.
-- Max
map_newlink() may abort when interface list changed between netlink
request for getting interfaces and getting addresses. This commit is
ported from the same change from glibc commit.
Signed-off-by: Vincent Hou <vincent.houyi(a)gmail.com>
---
Hi all,
App code making a getaddrinfo() call may get a occasional abort from
map_newlink(). The reason of the abort is getifaddrs() uses an out-dated
interface list.
In getaddrinfo() call, it will call a function getifaddrs() who retrieves
all interfaces and addresses from kernel via netlink, returning an array
of interfaces and addresses. It will then call a function map_newlink()
to build a mapping between the interfaces’ index into the returning array
to the interface id in kernel. Then getifaddrs() will bind the
relationship between interface and the address using the mapping from
previous step.
The interfaces and addresses are retrieved from two separate netlink
requests. It retrieves interface lists then followed by address list.
Between two requests, kernel may make change to interfaces and addresses.
If a new interface and address is added between the requests, the
newly-added interface doesn’t present in the interface list, but the
new-added address does. So the address will point to an non-existent
interface index.
This issue is fixed by glibc and this change ports the commit from glibc
(with some minor changes).
Thanks,
Vincent Hou
libc/inet/ifaddrs.c | 53 +++++++++++++++++++++++++++++++++++----------
1 file changed, 42 insertions(+), 11 deletions(-)
diff --git a/libc/inet/ifaddrs.c b/libc/inet/ifaddrs.c
index 0c9310651..72771d35a 100644
--- a/libc/inet/ifaddrs.c
+++ b/libc/inet/ifaddrs.c
@@ -339,17 +339,19 @@ map_newlink (int idx, struct ifaddrs_storage *ifas, int *map, int max)
else if (map[i] == idx)
return i;
}
- /* This should never be reached. If this will be reached, we have
- a very big problem. */
- abort ();
+
+ /* This means interfaces changed inbetween the reading of the
+ RTM_GETLINK and RTM_GETADDR information. We have to repeat
+ everything. */
+ return -1;
}
/* Create a linked list of `struct ifaddrs' structures, one for each
network interface on the host machine. If successful, store the
list in *IFAP and return 0. On errors, return -1 and set `errno'. */
-int
-getifaddrs (struct ifaddrs **ifap)
+static int
+getifaddrs_internal (struct ifaddrs **ifap)
{
struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
struct netlink_res *nlp;
@@ -496,6 +498,13 @@ getifaddrs (struct ifaddrs **ifap)
kernel. */
ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
map_newlink_data, newlink);
+ if (__builtin_expect (ifa_index == -1, 0))
+ {
+ try_again:
+ result = -EAGAIN;
+ free (ifas);
+ goto exit_free;
+ }
ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
while (RTA_OK (rta, rtasize))
@@ -580,9 +589,11 @@ getifaddrs (struct ifaddrs **ifap)
that we have holes in the interface part of the list,
but we always have already the interface for this address. */
ifa_index = newlink + newaddr_idx;
- ifas[ifa_index].ifa.ifa_flags
- = ifas[map_newlink (ifam->ifa_index - 1, ifas,
- map_newlink_data, newlink)].ifa.ifa_flags;
+ int idx = map_newlink (ifam->ifa_index - 1, ifas,
+ map_newlink_data, newlink);
+ if (__builtin_expect (idx == -1, 0))
+ goto try_again;
+ ifas[ifa_index].ifa.ifa_flags = ifas[idx].ifa.ifa_flags;
if (ifa_index > 0)
ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
++newaddr_idx;
@@ -768,9 +779,13 @@ getifaddrs (struct ifaddrs **ifap)
/* If we didn't get the interface name with the
address, use the name from the interface entry. */
if (ifas[ifa_index].ifa.ifa_name == NULL)
- ifas[ifa_index].ifa.ifa_name
- = ifas[map_newlink (ifam->ifa_index - 1, ifas,
- map_newlink_data, newlink)].ifa.ifa_name;
+ {
+ int idx = map_newlink (ifam->ifa_index - 1, ifas,
+ map_newlink_data, newlink);
+ if (__builtin_expect (idx == -1, 0))
+ goto try_again;
+ ifas[ifa_index].ifa.ifa_name = ifas[idx].ifa.ifa_name;
+ }
/* Calculate the netmask. */
if (ifas[ifa_index].ifa.ifa_addr
@@ -850,6 +865,22 @@ getifaddrs (struct ifaddrs **ifap)
return result;
}
+
+
+/* Create a linked list of `struct ifaddrs' structures, one for each
+ network interface on the host machine. If successful, store the
+ list in *IFAP and return 0. On errors, return -1 and set `errno'. */
+int
+getifaddrs (struct ifaddrs **ifap)
+{
+ int res;
+
+ do
+ res = getifaddrs_internal (ifap);
+ while (res == -EAGAIN);
+
+ return res;
+}
libc_hidden_def(getifaddrs)
void
--
2.18.0
From: Yann Sionneau <ysionneau(a)kalray.eu>
Avoid calling select with empty sets which hangs the process
This makes uClibc-ng act like glibc and musl
Without this fix the test_poll of python3 testsuite hangs forever
Scenario of the issue:
If you call poll with only invalid file descriptors, like in python3
testsuite
(https://github.com/python/cpython/blob/master/Lib/test/test_poll.py#L83)
You will go through uClibc poll emulation code, which is based on
select syscall.
Your first call to select will fail, it will return -1 and errno will be
set to EBADF: https://github.com/wbx-github/uclibc-ng/blob/master/libc/sysdeps/linux/comm…
Then you will go through the for loop which tests individually each file descriptor by calling
select on each one: https://github.com/wbx-github/uclibc-ng/blob/master/libc/sysdeps/linux/comm…
each call will also return -1 with errno being equal to EBADF.
Therefore all pollfd will have the POLLNVAL flag in their respective revents field.
And, the most important, rset/wset/xset will stay empty.
Then the for loop ends, the "continue" makes the while loop run again.
The following select() is run again: https://github.com/wbx-github/uclibc-ng/blob/master/libc/sysdeps/linux/comm…
But this time the sets are empty.
If the poll was called with timeout set to -1, this select will hang forever because there is no timeout
and the sets are empty so no event will ever wake it up.
test program:
int main(void)
{
struct pollfd pfd;
int ret;
int pipe_fds[2];
pipe(pipe_fds);
close(pipe_fds[0]);
close(pipe_fds[1]);
pfd.fd = pipe_fds[0];
pfd.events = POLLIN | POLLOUT | POLLPRI;
pfd.revents = 0;
ret = poll(&pfd, 1, -1);
printf("ret: %d\n", ret);
if (ret < 0)
printf("error: %s", strerror(errno));
else {
puts("revents: ");
if (pfd.revents & POLLERR)
printf(" POLLERR");
if (pfd.revents & POLLHUP)
printf(" POLLHUP");
if (pfd.revents & POLLNVAL)
printf(" POLLNVAL");
puts("");
}
return 0;
}
This hangs on uClibc-ng aarch64 and Kalray's arch (kv3) but does the following on musl and glibc:
"
ret: 1
revents:
POLLNVAL
"
strace output of this program with uClibc *without* the patch applied:
pselect6(4, [3], [3], [3], NULL, NULL) = -1 EBADF (Bad file descriptor)
pselect6(4, [3], [3], [3], {tv_sec=0, tv_nsec=0}, NULL) = -1 EBADF (Bad file descriptor)
pselect6(0, 0x7ffffffb80, 0x7ffffffb68, 0x7ffffffb50, NULL, NULL
(never finishes)
strace output of this program with uClibc *with* the patch applied:
pselect6(4, [3], [3], [3], NULL, NULL) = -1 EBADF (Bad file descriptor)
pselect6(4, [3], [3], [3], {tv_sec=0, tv_nsec=0}, NULL) = -1 EBADF (Bad file descriptor)
write(1, "ret: 1\n", 7ret: 1
) = 7
write(1, "revents: \n", 10revents:
) = 10
write(1, " POLLNVAL\n", 10 POLLNVAL
) = 10
exit_group(0) = ?
+++ exited with 0 +++
---
libc/sysdeps/linux/common/poll.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/libc/sysdeps/linux/common/poll.c b/libc/sysdeps/linux/common/poll.c
index d1f1f17..3d46d5b 100644
--- a/libc/sysdeps/linux/common/poll.c
+++ b/libc/sysdeps/linux/common/poll.c
@@ -53,6 +53,7 @@ int __NC(poll)(struct pollfd *fds, nfds_t nfds, int timeout)
fd_set *rset, *wset, *xset;
struct pollfd *f;
int ready;
+ int error_num;
int maxfd = 0;
int bytes;
@@ -142,6 +143,7 @@ int __NC(poll)(struct pollfd *fds, nfds_t nfds, int timeout)
/* Reset the return value. */
ready = 0;
+ error_num = 0;
for (f = fds; f < &fds[nfds]; ++f)
if (f->fd != -1 && (f->events & (POLLIN|POLLOUT|POLLPRI))
@@ -178,8 +180,13 @@ int __NC(poll)(struct pollfd *fds, nfds_t nfds, int timeout)
++ready;
}
else if (errno == EBADF)
+ {
f->revents |= POLLNVAL;
+ error_num++;
+ }
}
+ if (ready == 0)
+ return error_num;
/* Try again. */
continue;
}
--
1.8.3.1
Hi,
I've been trying to cleanup uClibc test-suite failures on ARC and when debugging
test-double ran into a totally unrelated issue where it fails as
| testing double (without inline functions)
| Failure: finite (0): errno set to 11, expected 0 (unchanged)
Turns out the test harness uses asprintf() which seems to be fudging errno causing
test harness to erroneously declare failure:
Here's a simple test case which shows the problem:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
void main(void)
{
const char *this_func = "finite";
char *test_name;
errno = 0;
if (asprintf (&test_name, "%s (%s)", this_func, "my-str") == -1)
abort ();
printf("%d\n", errno); // <-- prints 11
}
The errno unconditionally being set to EAGAIN seems to have been introduced in
commit 568ceebf6adfc58c64a95133311268db6 ("Fix infinite loop when fopencookie
custom write returns 0 on error") bakc in 2016.
+#define __STDIO_STREAM_CUSTOM_WRITE_FUNC(S, ARGS...) \
+ if (__STDIO_STREAM_IS_CUSTOM((S))) { \
+ _IO_cookie_file_t *cfile = (_IO_cookie_file_t *) (S); \
+ if (cfile->__gcs.write == NULL) { \
+ __set_errno(EINVAL); \
+ return -1; \
+ } \
+ __set_errno(EAGAIN); \
+ ssize_t w = cfile->__gcs.write(cfile->__cookie, ##ARGS); \
+ return (w == 0 ? -1 : w); \
+ }
I don't understand all the logic but shouldn't it be set after __gcs.write() call ?
Thx,
-Vineet
Signed-off-by: Yann Sionneau <ysionneau(a)kalray.eu>
---
libpthread/nptl/sysdeps/riscv64/libc-tls.c | 2 +-
libpthread/nptl/sysdeps/riscv64/tls.h | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/libpthread/nptl/sysdeps/riscv64/libc-tls.c b/libpthread/nptl/sysdeps/riscv64/libc-tls.c
index 500de1d..67c3a60 100644
--- a/libpthread/nptl/sysdeps/riscv64/libc-tls.c
+++ b/libpthread/nptl/sysdeps/riscv64/libc-tls.c
@@ -17,7 +17,7 @@
#include <sysdeps/generic/libc-tls.c>
#include <dl-tls.h>
-/* On OpenRISC, linker optimizations are not required, so __tls_get_addr
+/* On RISC-V 64, linker optimizations are not required, so __tls_get_addr
can be called even in statically linked binaries. In this case module
must be always 1 and PT_TLS segment exist in the binary, otherwise it
would not link. */
diff --git a/libpthread/nptl/sysdeps/riscv64/tls.h b/libpthread/nptl/sysdeps/riscv64/tls.h
index 33a3781..8295c71 100644
--- a/libpthread/nptl/sysdeps/riscv64/tls.h
+++ b/libpthread/nptl/sysdeps/riscv64/tls.h
@@ -1,4 +1,4 @@
-/* Definition for thread-local data handling. NPTL/OR1K version.
+/* Definition for thread-local data handling. NPTL/RISCV64 version.
Copyright (C) 2005, 2007, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -70,7 +70,7 @@ register tcbhead_t *__thread_self __asm__("tp");
* ------------------------------------
* | PRE | TCB | TLS MEMORY .. |
* ------------------------------------
- * ^ r10 / TP
+ * ^ x4 / TP
*
* PRE is the struct pthread described below
* TCB is tcbhead_t
--
1.8.3.1
Hello,
About
https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/commit/?id=858ffad2170762…
I'm not sure why exactly sizeof(int)*3 in the following line:
char buf[sizeof "/proc/self/fd/" + sizeof (int) * 3];
IIUC, this is supposed to give room for the ascii decimal representation
of the file descriptor number.
Maybe we could read the max file descriptor number configured in the
kernel from "/proc/sys/fs/file-max" (or "/proc/sys/file-max" for old
systems?).
So:
1/ fopen("/proc/sys/fs/file-max", "r");
2/ fscanf(fp, "%d", &fdmax);
3/ fdmax_length = log10(fdmax);
Then use fdmax_length
Or, much simpler: take for granted that fd is always an int, and thus
max 32 bits, and hard code that max "string length" of a file descriptor
is 10 chars.
But in any case maybe add a comment on top of the line to explain the
"magic number".
Cheers!
--
Yann
Hi,
This diff fixes a typo in the PTRACE_EVENT_SECCOMP event code.
The typo itself was introduced in 2012 when syncing with glibc header
files and was itself fixed in 2013 in the glibc headers.
diff --git a/libc/sysdeps/linux/common/sys/ptrace.h b/libc/sysdeps/linux/common/sys/ptrace.h
index 6b3c7b574..ebafe4e27 100644
--- a/libc/sysdeps/linux/common/sys/ptrace.h
+++ b/libc/sysdeps/linux/common/sys/ptrace.h
@@ -171,7 +171,7 @@ enum __ptrace_eventcodes
PTRACE_EVENT_EXEC = 4,
PTRACE_EVENT_VFORK_DONE = 5,
PTRACE_EVENT_EXIT = 6,
- PTRAVE_EVENT_SECCOMP = 7
+ PTRACE_EVENT_SECCOMP = 7
};
/* Perform process tracing functions. REQUEST is one of the values
.joris
Hi,
The getenv() library call can trap under certain conditions. It compares the passed in environment variable name (var) with the name=variables (*ep) in the environment area and returns a pointer to the value in the environment if it exists. To accomplish this, it does a memcmp() using the length of the passed in name (len) for each environment variable (*ep) against the passed in name (var). So memcmp will attempt to scan both strings for len bytes. However, if for some reason, len is equal to or greater than 16 and longer than the length of the *ep in the environment and the *ep resides near the end of a page boundary while the next page is not present or mapped, the memcmp could trap with a sigsegv error while continuing the scan with the optimization read-ahead. However, if strncmp is used instead, there is no problem since both source and destination scanning will stop when either reaches a terminating NULL
Test case: We are using gcc 4.8.5 and uclibc 1.0.31. With a small environment area, attempt to do a getenv() using a variable name such as "1234567890123456". Example: file run.c contains:
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *n;
n = getenv("1234567890123456");
printf("Return val: \"%s\"\n", n);
return 0;
}
Then
<sh> cc run.c -o run
<sh> env -i 123=123 ./run.
Segmentation fault
Proposed fix:
--- uclibc/libc/stdlib/getenv.c 2019-11-13 17:22:26.260187664 -0500
+++ uclibc/libc/stdlib/getenv.c 2019-11-13 17:22:39.376111771 -0500
@@ -20,7 +20,7 @@
return NULL;
len = strlen(var);
while(*ep) {
- if (memcmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
+ if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
return *ep + len + 1;
}
ep++;
Then
<sh> env -i 123=123 ./run.
<sh>
Can we get this patch upstream?
Thanks,
----
John Ata, CISSP
Senior Principal Software Engineer
Electronics Systems
STOP Operating System<http://www.baesystems.com/en-us/product/stop> Software Development
T 703-563-8115 | F 703-668-4359 | john.ata(a)baesystems.com<mailto:john.ata@baesystems.com>
http://www.baesystems.com/csp
[cid:image001.png@01D138BC.8E54E330][cid:image003.png@01D138BC.8E54E330]<http://www.twitter.com/baesystemsinc>[cid:image004.png@01D138BC.8E54E330]<http://www.youtube.com/baesystemsinc>[cid:image006.png@01D138BC.8E54E330]<http://www.flickr.com/photos/baesystemsinc/>