errno is not thread-safe in uClibc-0.9.30?

Pan ruochen panruochen at gmail.com
Tue Jul 20 09:05:17 UTC 2010


Hi All,

I am developing with uClibc-0.9.30. I came accoss very strange problems
relating to `errno'.

----------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define NUM_THREADS 6

void *thread(void *threadid)
{
       int i;
       struct stat stat_buf;

       for(i=0; i<100; i++) {
               int ret = stat("/lib/The_DIR_NOT_EXIST", &stat_buf);
               if(ret < 0) {
                       fprintf(stderr, "inv errno %d, ret=%d\n", errno, ret);
                       abort();
               }
               sleep(1);
       }
       return (void *)NULL;
}
int main (int argc, char *argv[])
{
       pthread_t threads[NUM_THREADS];
       int rc, i;
       srand(time(NULL));
       for(i=0; i<NUM_THREADS; i++){
               rc = pthread_create(&threads[i], NULL, thread, (void *)i);
               if (rc) {
                       printf("pthread_create() failed: %d\n", rc);
               }
       }
       for(i=0; i<100; i++) {
               opendir("/The_DIR_NOT_EXIST");
               usleep(1);
       }
       sleep(5);
       for(i=0; i<NUM_THREADS; i++){
               pthread_join(threads[i], NULL);
       }
       return 0;
}
----------------------------------------------------------------------------

The application will fail on `stat' function while the errno is equal to zero!!
The results don't conform to the descriptions about `stat' function.
The same thing happens to any other ANSI C library functions instead of `stat'.

Then I read the unassembly code of uClibc-0.9.30.so
and find the following:
----------------------------------------------------------------------------
0000ebe0 <stat>:
   ebe0:       3c1c0006        lui     gp,0x6
   ebe4:       279cb810        addiu   gp,gp,-18416
   ebe8:       0399e021        addu    gp,gp,t9
   ebec:       27bdff48        addiu   sp,sp,-184
   ebf0:       afbf00b4        sw      ra,180(sp)
   ebf4:       afb100b0        sw      s1,176(sp)
   ebf8:       afb000ac        sw      s0,172(sp)
   ebfc:       afbc0010        sw      gp,16(sp)
   ec00:       27a60018        addiu   a2,sp,24
   ec04:       00a08821        move    s1,a1
   ec08:       00c02821        move    a1,a2
   ec0c:       2402100a        li      v0,4106
   ec10:       0000000c        syscall
   ec14:       10e00008        beqz    a3,ec38 <stat+0x58>
   ec18:       00408021        move    s0,v0
   ec1c:       8f99801c        lw      t9,-32740(gp) /*PRC:__errno_location*/
   ec20:       0320f809        jalr    t9 <__errno_location>
   ec24:       00000000        nop
   ec28:       8fbc0010        lw      gp,16(sp)
   ec2c:       ac500000        sw      s0,0(v0)
   ...
00013910 <__errno_location>:
  13910:       3c1c0005        lui     gp,0x5
  13914:       279c6ae0        addiu   gp,gp,27360
  13918:       0399e021        addu    gp,gp,t9
  1391c:       03e00008        jr      ra
  13920:       8f828180        lw      v0,-32384(gp)
----------------------------------------------------------------------------

Here errno is implemented as a global variable and not thread-safe.
There is another implementation of `__errno_location' in libpthread.so.

----------------------------------------------------------------------------
00004584 <__errno_location>:
   4584:       3c1c0002        lui     gp,0x2
   4588:       279c3e4c        addiu   gp,gp,15948
   458c:       0399e021        addu    gp,gp,t9
   4590:       27bdffe0        addiu   sp,sp,-32
   4594:       afbf001c        sw      ra,28(sp)
   4598:       afbc0010        sw      gp,16(sp)
   459c:       8f9980c0        lw      t9,-32576(gp) /*PRC:thread_self*/
   45a0:       0320f809        jalr    t9 <thread_self>
   45a4:       00000000        nop
   45a8:       8fbf001c        lw      ra,28(sp)
   45ac:       8fbc0010        lw      gp,16(sp)
   45b0:       8c420044        lw      v0,68(v0)
   45b4:       03e00008        jr      ra
   45b8:       27bd0020        addiu   sp,sp,32
   45bc:       00000000        nop
----------------------------------------------------------------------------

There is stll chance that `errno' is thread-safe if the ELF loader is
smart enough
to fix the location -32740(gp) insied libuClibc.so when the shared
library libpthread.so is loaded.

I don't know whether the loader can do this. If it can, how should I
configure kernel or uClibc options?
Or has this bug been fix in the later version?


Best Regards,
PRC
Jul 20,2010


More information about the uClibc mailing list