Bug 2130006

Summary: sem_timedwait hang with AddressSanitizer with 32 bit binary
Product: Red Hat Enterprise Linux 8 Reporter: Paulo Andrade <pandrade>
Component: gccAssignee: Marek Polacek <mpolacek>
gcc sub component: system-version QA Contact: qe-baseos-tools-bugs
Status: CLOSED UPSTREAM Docs Contact:
Severity: medium    
Priority: medium CC: ahajkova, fweimer, jakub, ohudlick, sipoyare
Version: 8.6   
Target Milestone: rc   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2022-09-27 16:14:36 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
sem_timedwait.tar none

Description Paulo Andrade 2022-09-26 21:07:41 UTC
Created attachment 1914471 [details]
sem_timedwait.tar

In the sample reproducer it is expected to have the output:

thread_func_one loop 1
thread_func_two loop 1
thread_func_one loop 2
thread_func_two loop 2
thread_func_one loop 3
thread_func_two loop 3
thread_func_one loop 4
thread_func_two loop 4
thread_func_one loop 5
thread_func_two loop 5
thread_func_one loop 6
thread_func_two loop 6
thread_func_one loop 7
thread_func_two loop 7
thread_func_one loop 8
thread_func_two loop 8
thread_func_one loop 9
thread_func_one done
thread_func_two loop 9
thread_func_two done
data_one.count=0 data_one.other=0
data_two.count=0 data_two.other=0

Instead, it hangs.

The problem is that libasan is binding to the wrong sem_init symbol.
It is binding to __old_sem_init instead of __new_sem_init.

The issue should be due to libasan not choosing the symbol from
libpthread.

A workaround is to play with the way __new_sem_init works, for example.
use the pseudo patch:

-sem_init(&sem_one, 0,1);
+sem_init(&sem_one, 0,2);

  This is due to glibc code:
...
__new_sem_init (sem_t *sem, int pshared, unsigned int value)
...
#if __HAVE_64B_ATOMICS
  isem->data = value;
#else
  isem->value = value << SEM_VALUE_SHIFT;
  /* pad is used as a mutex on pre-v9 sparc and ignored otherwise.  */
  isem->pad = 0;
  isem->nwaiters = 0;
#endif
...

SEM_VALUE_SHIFT is one.

Comment 1 Marek Polacek 2022-09-26 21:19:08 UTC
I see the same thing with F36 gcc (libasan-12.2.1-2.fc36.i686).  So it looks like it needs to be fixed upstream first, if it's a real bug.

Comment 2 Jakub Jelinek 2022-09-26 23:04:41 UTC
There is COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN macro that can be used instead of COMMON_INTERCEPT_FUNCTION, but it is used only for a few interceptors, I'm afraid i?86-linux needs far more than that.
readelf -Ws /lib/libc.so.6  | grep '[^@]@[^@]' | grep -v GLIBC_PRIVATE | awk '{print $NF}' | sort -u
shows a lot of symbols.
Of course not everything is intercepted etc.

Comment 3 Marek Polacek 2022-09-27 16:14:36 UTC
Reproduced with clang as well, upstream issue opened:
https://github.com/llvm/llvm-project/issues/58023

So this needs to be fixed in upstream first; closing this RHBZ thus.