Bug 59188 - [4.9 Regression] lib64/libtsan.so: undefined reference to `sigsetjmp'
Summary: [4.9 Regression] lib64/libtsan.so: undefined reference to `sigsetjmp'
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: sanitizer (show other bugs)
Version: 4.9.0
: P1 normal
Target Milestone: 4.9.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-11-19 14:26 UTC by Joost VandeVondele
Modified: 2013-12-06 11:23 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-11-21 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joost VandeVondele 2013-11-19 14:26:25 UTC
looks like it is not possible to use -fsanitize=thread with current trunk.

> cat test.c
int main()
{
 return 0;
}

> gcc  -fsanitize=thread -pie -fPIC test.c 
/data/vjoost/gnu/gcc_trunk/install/lib/gcc/x86_64-unknown-linux-gnu/4.9.0/../../../../lib64/libtsan.so: undefined reference to `sigsetjmp'
collect2: error: ld returned 1 exit status
Comment 1 Kostya Serebryany 2013-11-19 14:44:54 UTC
Interesting. tsan in clang works, so we either have problems in the 
gcc build system or we have some differences in the code that affect the 
sigsetjmp interceptor. 

one other problem would be that we have zero tests for tsan in gcc :(
Comment 2 Jakub Jelinek 2013-11-19 14:53:06 UTC
glibc (at least the 2.17 I have around) doesn't have sigsetjmp function at all,
it only conditionally has sigsetjmp as a macro:
#ifdef  __USE_POSIX
...
/* Store the calling environment in ENV, also saving the
   signal mask if SAVEMASK is nonzero.  Return 0.  */
# define sigsetjmp(env, savemask)       __sigsetjmp (env, savemask)
...
#endif

so
extern "C" int setjmp(void *env);
extern "C" int _setjmp(void *env);
extern "C" int sigsetjmp(void *env);
extern "C" int __sigsetjmp(void *env);
DEFINE_REAL(int, setjmp, void *env)
DEFINE_REAL(int, _setjmp, void *env)
DEFINE_REAL(int, sigsetjmp, void *env)
DEFINE_REAL(int, __sigsetjmp, void *env)

is just asking for trouble.  Not to mention that the arguments are wrong even for __sigsetjmp, which has two arguments rather than just one.  So, if it works with clang, must be purely by accident, perhaps the difference is that __USE_POSIX is defined in one case and not in the other one, or something, but still, it can't really work in either case.
Comment 3 Dmitry Vyukov 2013-11-19 15:13:08 UTC
Hi,

Can you please try the following patch?
If it does not work, please check what else references sigsetjmp.


--- rtl/tsan_interceptors.cc	(revision 194823)
+++ rtl/tsan_interceptors.cc	(working copy)
@@ -2034,6 +2034,9 @@
   Die();
 }
 
+extern "C" uptr dlsym(uptr, const char*);
+const uptr RTLD_NEXT = -1;
+
 void InitializeInterceptors() {
   CHECK_GT(cur_thread()->in_rtl, 0);
 
@@ -2048,10 +2051,11 @@
 
   SANITIZER_COMMON_INTERCEPTORS_INIT;
 
-  TSAN_INTERCEPT(setjmp);
-  TSAN_INTERCEPT(_setjmp);
-  TSAN_INTERCEPT(sigsetjmp);
-  TSAN_INTERCEPT(__sigsetjmp);
+  *(uptr*)&REAL(setjmp) = dlsym(RTLD_NEXT, "setjmp");
+  *(uptr*)&REAL(_setjmp) = dlsym(RTLD_NEXT, "_setjmp");
+  *(uptr*)&REAL(sigsetjmp) = dlsym(RTLD_NEXT, "sigsetjmp");
+  *(uptr*)&REAL(__sigsetjmp) = dlsym(RTLD_NEXT, "__sigsetjmp");
+
   TSAN_INTERCEPT(longjmp);
   TSAN_INTERCEPT(siglongjmp);
Comment 4 Dmitry Vyukov 2013-11-19 15:16:09 UTC
> glibc (at least the 2.17 I have around) doesn't have sigsetjmp function at all

this must be fine, we do not call it if it's not used

> Not to mention that the arguments are wrong even for __sigsetjmp

setjmp interception is a bit tricky (because one can't wrap libc setjmp into another function, otherwise the saved context will be broken)
so it's actually called from tsan_rtl_amd64.S by a tail call here:

  // tail jump to libc sigsetjmp
  movl $0, %eax
  movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx
  jmp *(%rdx)
  .cfi_endproc
.size __sigsetjmp, .-__sigsetjmp
Comment 5 Joost VandeVondele 2013-11-19 15:23:04 UTC
(In reply to Dmitry Vyukov from comment #3)
> Can you please try the following patch

compiles with warnings:

../../../../gcc/libsanitizer/tsan/tsan_interceptors.cc:2022:12: note: in expansion of macro ‘REAL’
   *(uptr*)&REAL(_setjmp) = dlsym(RTLD_NEXT, "_setjmp");
            ^
../../../../gcc/libsanitizer/interception/interception.h:145:25: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]


However, it fixes the issue mentioned.
Comment 6 Dmitry Vyukov 2013-11-19 15:34:44 UTC
Great, thanks!
I will prepare a real patch.
Comment 7 Dmitry Vyukov 2013-11-21 11:55:17 UTC
I've committed the fix into llvm:
http://llvm.org/viewvc/llvm-project?view=revision&revision=195345
Comment 8 Jonathan Wakely 2013-11-21 15:02:25 UTC
(In reply to Kostya Serebryany from comment #1)
> one other problem would be that we have zero tests for tsan in gcc :(

It would be great if someone could do something about that, even just a single test would have shown this problem, which I think has been there for at least a week.
Comment 9 Richard Biener 2013-11-21 15:05:04 UTC
Fixed (works for me now).
Comment 10 Joost VandeVondele 2013-11-21 15:11:11 UTC
(In reply to Richard Biener from comment #9)
> Fixed
unlikely, the fix only went to the llvm repo so far.
>  (works for me now).
depends on your libc
Comment 11 Kostya Serebryany 2013-11-22 11:11:04 UTC
planing next merge from llvm to gcc in ~1 week.
Comment 12 Joost VandeVondele 2013-12-06 11:23:13 UTC
(In reply to Kostya Serebryany from comment #11)
> planing next merge from llvm to gcc in ~1 week.

Fixed in current trunk. Thanks!