[Bug 261713] ThreadSanitizer detects race in __catopen_l (via strerror_r)

From: <bugzilla-noreply_at_freebsd.org>
Date: Fri, 04 Feb 2022 15:21:20 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=261713

            Bug ID: 261713
           Summary: ThreadSanitizer detects race in __catopen_l (via
                    strerror_r)
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: threads
          Assignee: threads@FreeBSD.org
          Reporter: dim@FreeBSD.org

Test case:

======================================================================
#include <err.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define NUM_THREADS 2

static void *thread_func(void *arg __attribute__((__unused__)))
{
  char buf[256];
  int error;

  usleep(1);

  error = strerror_r(ETIMEDOUT, buf, sizeof buf);
  if (error)
    errx(1, "strerror_r failed with error %d", error);

  return NULL;
}

int main(void)
{
  pthread_t threads[NUM_THREADS];
  int i, error;
  void *result;

  for (i = 0; i < NUM_THREADS; ++i) {
    error = pthread_create(&threads[i], NULL, thread_func, NULL);
    if (error)
      errx(1, "pthread_create failed with error %d", error);
  }

  for (i = 0; i < NUM_THREADS; ++i) {
    error = pthread_join(threads[i], &result);
    if (error)
      errx(1, "pthread_join failed with error %d", error);
  }

  return 0;
}
======================================================================

% uname -v
FreeBSD 14.0-CURRENT #2 main-n252774-fdf278410104: Sun Jan 30 21:44:57 CET 2022
    dim@vdim-fbsdhead-amd64:/usr/obj/usr/src/amd64.amd64/sys/GENERIC

% cc -g fsanitize=thread race-strerror.c -o race-strerror -lpthread

% ./race-strerror
==================
WARNING: ThreadSanitizer: data race (pid=3438)
  Read of size 1 at 0x7b0400000000 by thread T2:
    #0 strcmp
/usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc:457:3
(race-strerror+0x25fdcf)
    #1 __catopen_l /usr/src/lib/libc/nls/msgcat.c:163:8 (libc.so.7+0xfb2ad)
    #2 thread_func /share/dim/bugs/race-strerror/race-strerror.c:17:11
(race-strerror+0x2bac75)

  Previous write of size 1 at 0x7b0400000000 by thread T1:
    #0 memcpy
/usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc:827:5
(race-strerror+0x261b9b)
    #1 strdup /usr/src/lib/libc/string/strdup.c:51:2 (libc.so.7+0x1d39b6)
    #2 __catopen_l /usr/src/lib/libc/nls/msgcat.c:273:2 (libc.so.7+0xfb6a4)
    #3 thread_func /share/dim/bugs/race-strerror/race-strerror.c:17:11
(race-strerror+0x2bac75)

  As if synchronized via sleep:
    #0 usleep
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:356:3
(race-strerror+0x257476)
    #1 thread_func /share/dim/bugs/race-strerror/race-strerror.c:15:3
(race-strerror+0x2bac5f)

  Location is heap block of size 5 at 0x7b0400000000 allocated by thread T1:
    #0 malloc
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:655:5
(race-strerror+0x2586fa)
    #1 strdup /usr/src/lib/libc/string/strdup.c:49:14 (libc.so.7+0x1d39a0)
    #2 __catopen_l /usr/src/lib/libc/nls/msgcat.c:273:2 (libc.so.7+0xfb6a4)
    #3 thread_func /share/dim/bugs/race-strerror/race-strerror.c:17:11
(race-strerror+0x2bac75)

  Thread T2 (tid=100539, running) created by main thread at:
    #0 pthread_create
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:977:3
(race-strerror+0x259c15)
    #1 main /share/dim/bugs/race-strerror/race-strerror.c:31:13
(race-strerror+0x2bab8d)

  Thread T1 (tid=100538, finished) created by main thread at:
    #0 pthread_create
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:977:3
(race-strerror+0x259c15)
    #1 main /share/dim/bugs/race-strerror/race-strerror.c:31:13
(race-strerror+0x2bab8d)

SUMMARY: ThreadSanitizer: data race /usr/src/lib/libc/nls/msgcat.c:163:8 in
__catopen_l
==================
==================
WARNING: ThreadSanitizer: data race (pid=3438)
  Read of size 1 at 0x7b0400000010 by thread T2:
    #0 strcmp
/usr/src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc:457:3
(race-strerror+0x25fdcf)
    #1 __catopen_l /usr/src/lib/libc/nls/msgcat.c:165:7 (libc.so.7+0xfb2ca)
    #2 thread_func /share/dim/bugs/race-strerror/race-strerror.c:17:11
(race-strerror+0x2bac75)

  Previous write of size 8 at 0x7b0400000010 by thread T1:
    #0 malloc
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:655:5
(race-strerror+0x2586fa)
    #1 strdup /usr/src/lib/libc/string/strdup.c:49:14 (libc.so.7+0x1d39a0)
    #2 __catopen_l /usr/src/lib/libc/nls/msgcat.c:273:2 (libc.so.7+0xfb6c4)
    #3 thread_func /share/dim/bugs/race-strerror/race-strerror.c:17:11
(race-strerror+0x2bac75)

  As if synchronized via sleep:
    #0 usleep
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:356:3
(race-strerror+0x257476)
    #1 thread_func /share/dim/bugs/race-strerror/race-strerror.c:15:3
(race-strerror+0x2bac5f)

  Location is heap block of size 2 at 0x7b0400000010 allocated by thread T1:
    #0 malloc
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:655:5
(race-strerror+0x2586fa)
    #1 strdup /usr/src/lib/libc/string/strdup.c:49:14 (libc.so.7+0x1d39a0)
    #2 __catopen_l /usr/src/lib/libc/nls/msgcat.c:273:2 (libc.so.7+0xfb6c4)
    #3 thread_func /share/dim/bugs/race-strerror/race-strerror.c:17:11
(race-strerror+0x2bac75)

  Thread T2 (tid=100539, running) created by main thread at:
    #0 pthread_create
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:977:3
(race-strerror+0x259c15)
    #1 main /share/dim/bugs/race-strerror/race-strerror.c:31:13
(race-strerror+0x2bab8d)

  Thread T1 (tid=100538, finished) created by main thread at:
    #0 pthread_create
/usr/src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:977:3
(race-strerror+0x259c15)
    #1 main /share/dim/bugs/race-strerror/race-strerror.c:31:13
(race-strerror+0x2bab8d)

SUMMARY: ThreadSanitizer: data race /usr/src/lib/libc/nls/msgcat.c:165:7 in
__catopen_l
==================
ThreadSanitizer: reported 2 warnings

E.g. thread T2 is looping over the cache in lib/libc/nls/msgcat.c, line 163: 

   160          /* Try to get it from the cache first */
   161          RLOCK(NLERR);
   162          SLIST_FOREACH(np, &cache, list) {
-> 163                  if ((strcmp(np->name, name) == 0) &&
   164                      ((lang != NULL && np->lang != NULL &&
   165                      strcmp(np->lang, lang) == 0) || (np->lang ==
lang))) {

while thread T1 is still allocating memory in the SAVEFAIL macro, line 273:

   271          free(plang);
   272          free(base);
-> 273          SAVEFAIL(name, lang, ENOENT);
   274          NLRETERR(ENOENT);
   275  }

But it's tricky to see what happens exactly, since SAVEFAIL does quite a lot of
things. :)

-- 
You are receiving this mail because:
You are the assignee for the bug.