[PATCH] LT.old: Make errno_location thread safe

Vineet Gupta Vineet.Gupta1 at synopsys.com
Wed Mar 12 14:05:33 UTC 2014


[summary: Get rid of libc alias __GI___errno_location]

It seems with Linuxthreads.old (yet to confirm NPTL) errno is not thread
safe.

A simple pthread linked test program (at the bottom) which makes a
failing syscall e.g. open("/not-exist") fails to observe the right errno
in the thread (main is OK)

Conceptually uClibc defines weak __errno_location() while libpthread
defines astrong variant. This arrangement shd work when using -pthread
links. The spoil sport is __GI___errno_location, intended to bypass PLT
for intra-libc callers. It gets called even in case of LT.old links
given the syscall wrappers in  libpthread (LT.old). e.g.

open [ in libpthread ]
  pthreadsetcanceltype()
   __libc_open()
      __GI__open()
           ...
-           __GI___errno_location    [ existing ]
+           __errno_location         [ intended ]
   ....
  pthreadsetcanceltype()

So the solution is to get rid of GI alias for errno_location
altogether.

I tested this on master for ARC as well as an ARMv7 buildroot LT.old
build (daily snapshot of uClibc) and fix works on both.

-------- before ------->8----------

[Main thread] Initial errno = 99
errno @b6f6c338 = 2 (OK)

[Child Thread] Initial errno = 0
errno @be1ffee8 = 0 (BROKEN)
Errno in main after child 4

------- after ----->8------------------

[Main thread] Initial errno = 99
errno @b6f9a338 = 2 (OK)

[Child Thread] Initial errno = 0
errno @be1ffee8 = 2 (OK)
Errno in main after child 4

============Test case ===================
/* $CROSS-gcc -o errno-arc -lpthread */

void *th(void *str)
{
	int fd;
	printf("\n[%s] Initial errno = %d\n", (char *)str, errno);

	fd = open("/nothing", O_RDONLY);
	if (fd >= 0) {
		close(fd);
		//printf("success\n");
	} else
		printf("errno @%x = %d (%s)\n", &errno, errno, errno ?  "OK" : "BROKEN");

	errno = 66;

	return NULL;
}

int main(void)
{
	pthread_t t;
	void *r;
	int err;

	errno = 99;
	th("Main thread");

	err = pthread_create(&t, NULL, th, "Child Thread");
	if (err) {
		fprintf(stderr, "could not spawn thread: %s\n", strerror(err));
		return 1;
	}
	pthread_join(t, &r);

	printf("Errno in main after child %d\n", errno);
	return 0;
}

Cc: Christian Ruppert <christian.ruppert at abilis.com>
CC: Francois Bedard <Francois.Bedard at synopsys.com>
Cc: Joern Rennecke  <joern.rennecke at embecosm.com>
Cc: Jeremy Bennett <jeremy.bennett at embecosm.com>
Signed-off-by: Vineet Gupta <vgupta at synopsys.com>
---
 libc/misc/internals/__errno_location.c | 1 -
 libc/sysdeps/linux/common/bits/errno.h | 3 ---
 2 files changed, 4 deletions(-)

diff --git a/libc/misc/internals/__errno_location.c b/libc/misc/internals/__errno_location.c
index be7a9093efa3..9bbc2d779653 100644
--- a/libc/misc/internals/__errno_location.c
+++ b/libc/misc/internals/__errno_location.c
@@ -16,4 +16,3 @@ int *__errno_location(void)
 {
     return &errno;
 }
-libc_hidden_weak(__errno_location)
diff --git a/libc/sysdeps/linux/common/bits/errno.h b/libc/sysdeps/linux/common/bits/errno.h
index 777338fb1e0a..611b8359001a 100644
--- a/libc/sysdeps/linux/common/bits/errno.h
+++ b/libc/sysdeps/linux/common/bits/errno.h
@@ -43,11 +43,8 @@
 /* Function to get address of global `errno' variable.  */
 extern int *__errno_location (void) __THROW __attribute__ ((__const__));
 #  ifdef _LIBC
-#   if !defined(__UCLIBC_HAS_TLS__) && !defined(__UCLIBC_HAS_THREADS__)
 extern int weak_const_function *__errno_location(void);
-#   endif
 #  endif
-libc_hidden_proto(__errno_location)
 
 #  ifdef __UCLIBC_HAS_THREADS__
 /* When using threads, errno is a per-thread value.  */
-- 
1.8.3.2



More information about the uClibc mailing list