NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: port-sparc/53277 (Many ubsan tests fail on sparc)



Synopsis: Many ubsan tests fail on sparc

State-Changed-From-To: open->analyzed
State-Changed-By: riastradh%NetBSD.org@localhost
State-Changed-When: Fri, 18 Apr 2025 22:37:27 +0000
State-Changed-Why:
I tried compiling and running the t_ubsan_int_add_overflow program on
sparc under anita:

$ cat >test.c
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int help(int);
#ifndef PIC_MAIN
int help(int count) {volatile int l = INT_MAX; l+= count; return l;}
#endif
#ifndef PIC_FOO
int main(int argc, char **argv) {volatile int l = INT_MAX; l+=argc; return l;}
#endif
$ cc -fsanitize=undefined -o test test.c
$ ./test

It didn't seem to react, but ^T showed the same instruction address
repeatedly:

[ 5401.0213825] load: 0.65  cmd: test 1508 [0xed9c9454] 4.06u 46.48s 90% 2956k
[ 5403.7323765] load: 0.65  cmd: test 1508 [0xed9c9454] 4.22u 48.94s 91% 2956k
[ 5404.3214200] load: 0.65  cmd: test 1508 [0xed9c9454] 4.27u 49.45s 91% 2956k
[ 5404.4614085] load: 0.65  cmd: test 1508 [0xed9c9454] 4.30u 49.55s 91% 2956k

So I hit ^\ and it dumped core.  Here's what gdb said about the core:

Core was generated by `test'.
Program terminated with signal SIGQUIT, Quit.
#0  0xed9c9454 in __sanitizer::StaticSpinMutex::LockSlow (
    this=0xede968b8 <__sanitizer::report_file_mu>)
    at /usr/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_mutex.cpp:24

warning: 24     /usr/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_mutex.cpp: No such file or directory
(gdb) bt
#0  0xed9c9454 in __sanitizer::StaticSpinMutex::LockSlow (
    this=0xede968b8 <__sanitizer::report_file_mu>)
    at /usr/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_mutex.cpp:24
#1  0xed9c72dc in __sanitizer::StaticSpinMutex::Lock (
    this=0xede968b8 <__sanitizer::report_file_mu>)
    at /usr/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_mutex.h:32
#2  __sanitizer::GenericScopedLock<__sanitizer::StaticSpinMutex>::GenericScopedLock (mu=0xede968b8 <__sanitizer::report_file_mu>, this=<synthetic pointer>)
    at /usr/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_mutex.h:367
    this=0xed9f4260 <__sanitizer::report_file>,
    buffer=0xefffedd8 "UndefinedBehaviorSanitizer: CHECK failed: sanitizer_mutex.h:42 \"((atomic_load(&state_, memory_order_relaxed))) == ((1))\" (0xff, 0x1) (tid=928)\n", length=143)
    at /usr/src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_posix.cpp:271

This bespoke spin lock built out of bespoke atomic operations in terms
of __sync_* compiler builtins has an internal state of 0xff instead of
1.  It turns out this sanitizer logic is simply misusing the
__sync_lock_test_and_set API to implement a C11-style atomic_exchange:
when you do __sync_lock_test_and_set(&lock, 1), it is not guaranteed to
set lock to 1; it is only guaranteed to set it to something nonzero.
On sparc, this value is 0xff, because that's what ou get from the
LDSTUB instruction.

Fortunately, I think we can just change this assertion:

  void CheckLocked() const CHECK_LOCKED() {
    CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1);
  }

to:

  void CheckLocked() const CHECK_LOCKED() {
    CHECK_NE(atomic_load(&state_, memory_order_relaxed), 0);
  }





Home | Main Index | Thread Index | Old Index