Bug 100114 - libasan built against latest glibc doesn't work
Summary: libasan built against latest glibc doesn't work
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: sanitizer (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: 8.5
Assignee: Jakub Jelinek
URL:
Keywords:
Depends on: 101749
Blocks:
  Show dependency treegraph
 
Reported: 2021-04-16 12:45 UTC by Jakub Jelinek
Modified: 2023-02-07 05:54 UTC (History)
9 users (show)

See Also:
Host:
Target:
Build:
Known to work: 11.0
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2021-04-16 12:45:55 UTC
If libsanitizer is built against glibc trunk, nothing really works:
./a
==91==ERROR: AddressSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
==91==Process memory map follows:

I think this is caused by
// TODO(glider): different tools may require different altstack size.
static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.

void SetAlternateSignalStack() {
  stack_t altstack, oldstack;
  CHECK_EQ(0, sigaltstack(nullptr, &oldstack));
  // If the alternate stack is already in place, do nothing.
  // Android always sets an alternate stack, but it's too small for us.
  if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
  // TODO(glider): the mapped stack should have the MAP_STACK flag in the
  // future. It is not required by man 2 sigaltstack now (they're using
  // malloc()).
  void* base = MmapOrDie(kAltStackSize, __func__);
  altstack.ss_sp = (char*) base;
  altstack.ss_flags = 0;
  altstack.ss_size = kAltStackSize;
  CHECK_EQ(0, sigaltstack(&altstack, nullptr));
}

called from
#0  0x00007ffff7644650 in sigaltstack () from ./libasan.so.6
#1  0x00007ffff76bca92 in __sanitizer::SetAlternateSignalStack() () from ./libasan.so.6
#2  0x00007ffff76bcc65 in __sanitizer::InstallDeadlySignalHandlers(void (*)(int, void*, void*)) () from ./libasan.so.6
#3  0x00007ffff76ab60c in __asan::AsanInitInternal() [clone .part.0] () from ./libasan.so.6
#4  0x00007ffff7fdb6ee in _dl_init () from /lib64/ld-linux-x86-64.so.2
#5  0x00007ffff7fcc0ca in _dl_start_user () from /lib64/ld-linux-x86-64.so.2

and __asan_init which tail calls AsanInitInternal is registered in .preinit_array.

As in newer glibcs SIGSTKSZ is no longer a constant - since
https://sourceware.org/git/?p=glibc.git;a=commit;h=6c57d320484988e87e446e2e60ce42816bf51d53
- I think the above is invalid C++, because the function is called before the
kAltStackSize variable is constructed (which is why we end up with calling MmapOrDie(0, __func__);
and that fails miserably.
Comment 1 Jakub Jelinek 2021-04-16 12:49:20 UTC
As a quick hack, we could do something like:
#ifdef _SC_SIGSTKSZ
#define kAltStackSize (SIGSTKSZ * 4)
#else
static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
#endif
but the disadvantage is that sysconf will be called in that case on each use of kAltStackSize.
Comment 2 Richard Biener 2021-04-16 12:52:12 UTC
Confirmed by code inspection, but it's for sure sth not new (but would be nice to fix before GCC 11.1).

I suggtest to simply move the initialization inside SetAlternateSignalStack.
Sth like

diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
index d29438cf9db..803712e268e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -165,7 +165,7 @@ bool SupportsColoredOutput(fd_t fd) {
 
 #if !SANITIZER_GO
 // TODO(glider): different tools may require different altstack size.
-static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
+static const uptr kAltStackSize;
 
 void SetAlternateSignalStack() {
   stack_t altstack, oldstack;
@@ -176,6 +176,7 @@ void SetAlternateSignalStack() {
   // TODO(glider): the mapped stack should have the MAP_STACK flag in the
   // future. It is not required by man 2 sigaltstack now (they're using
   // malloc()).
+  kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
   void* base = MmapOrDie(kAltStackSize, __func__);
   altstack.ss_sp = (char*) base;
   altstack.ss_flags = 0;
Comment 3 H.J. Lu 2021-04-16 13:20:29 UTC
(In reply to Richard Biener from comment #2)
> Confirmed by code inspection, but it's for sure sth not new (but would be
> nice to fix before GCC 11.1).
> 
> I suggtest to simply move the initialization inside SetAlternateSignalStack.
> Sth like
> 
> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> index d29438cf9db..803712e268e 100644
> --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> @@ -165,7 +165,7 @@ bool SupportsColoredOutput(fd_t fd) {
>  
>  #if !SANITIZER_GO
>  // TODO(glider): different tools may require different altstack size.
> -static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
> +static const uptr kAltStackSize;
>  
>  void SetAlternateSignalStack() {
>    stack_t altstack, oldstack;
> @@ -176,6 +176,7 @@ void SetAlternateSignalStack() {
>    // TODO(glider): the mapped stack should have the MAP_STACK flag in the
>    // future. It is not required by man 2 sigaltstack now (they're using
>    // malloc()).
> +  kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
>    void* base = MmapOrDie(kAltStackSize, __func__);
>    altstack.ss_sp = (char*) base;
>    altstack.ss_flags = 0;

We can initialize it with a constructor or .init_array.
Comment 4 Jakub Jelinek 2021-04-16 13:22:20 UTC
const vars in C++ can't be uninitialized nor modified.
And initializing those in constructor or .init_array is too late, the problem is
that the function is called from .preinit_array handler, so before anything is constructed.

I'd suggest
--- libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp.jj	2020-11-13 19:00:46.909618582 +0100
+++ libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp	2021-04-16 15:19:56.211942944 +0200
@@ -165,7 +165,13 @@ bool SupportsColoredOutput(fd_t fd) {
 
 #if !SANITIZER_GO
 // TODO(glider): different tools may require different altstack size.
+#if SANITIZER_LINUX && defined(_SC_SIGSTKSZ)
+// In glibc 2.34 and later SIGSTKSZ is no longer a compile time constant,
+// but sysconf (_SC_SIGSTKSZ) call.
+static uptr kAltStackSize;
+#else
 static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
+#endif
 
 void SetAlternateSignalStack() {
   stack_t altstack, oldstack;
@@ -173,6 +179,9 @@ void SetAlternateSignalStack() {
   // If the alternate stack is already in place, do nothing.
   // Android always sets an alternate stack, but it's too small for us.
   if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;
+#if SANITIZER_LINUX && defined(_SC_SIGSTKSZ)
+  if (!kAltStackSize) kAltStackSize = SIGSTKSZ * 4;
+#endif
   // TODO(glider): the mapped stack should have the MAP_STACK flag in the
   // future. It is not required by man 2 sigaltstack now (they're using
   // malloc()).
Comment 5 GCC Commits 2021-04-17 09:30:53 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:d9f462fb372fb02da032cefd6b091d7582c425ae

commit r11-8230-gd9f462fb372fb02da032cefd6b091d7582c425ae
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Sat Apr 17 11:27:14 2021 +0200

    sanitizer: Fix asan against glibc 2.34 [PR100114]
    
    As mentioned in the PR, SIGSTKSZ is no longer a compile time constant in
    glibc 2.34 and later, so
    static const uptr kAltStackSize = SIGSTKSZ * 4;
    needs dynamic initialization, but is used by a function called indirectly
    from .preinit_array and therefore before the variable is constructed.
    This results in using 0 size instead and all asan instrumented programs
    die with:
    ==91==ERROR: AddressSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
    
    Here is a cherry-pick from upstream to fix this.
    
    2021-04-17  Jakub Jelinek  <jakub@redhat.com>
    
            PR sanitizer/100114
            * sanitizer_common/sanitizer_posix_libcdep.cpp: Cherry-pick
            llvm-project revisions 82150606fb11d28813ae6da1101f5bda638165fe
            and b93629dd335ffee2fc4b9b619bf86c3f9e6b0023.
Comment 6 Jakub Jelinek 2021-04-17 19:25:14 UTC
Fixed on the trunk so far, guess some backporting will be useful.
Comment 7 Richard Biener 2021-04-19 06:57:26 UTC
Yeah, backporting everywhere is needed.
Comment 8 GCC Commits 2021-04-20 09:46:40 UTC
The releases/gcc-10 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:950bac27d63c1c2ac3a6ed867692d6a13f21feb3

commit r10-9732-g950bac27d63c1c2ac3a6ed867692d6a13f21feb3
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Sat Apr 17 11:27:14 2021 +0200

    sanitizer: Fix asan against glibc 2.34 [PR100114]
    
    As mentioned in the PR, SIGSTKSZ is no longer a compile time constant in
    glibc 2.34 and later, so
    static const uptr kAltStackSize = SIGSTKSZ * 4;
    needs dynamic initialization, but is used by a function called indirectly
    from .preinit_array and therefore before the variable is constructed.
    This results in using 0 size instead and all asan instrumented programs
    die with:
    ==91==ERROR: AddressSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
    
    Here is a cherry-pick from upstream to fix this.
    
    2021-04-17  Jakub Jelinek  <jakub@redhat.com>
    
            PR sanitizer/100114
            * sanitizer_common/sanitizer_posix_libcdep.cpp: Cherry-pick
            llvm-project revisions 82150606fb11d28813ae6da1101f5bda638165fe
            and b93629dd335ffee2fc4b9b619bf86c3f9e6b0023.
    
    (cherry picked from commit d9f462fb372fb02da032cefd6b091d7582c425ae)
Comment 9 GCC Commits 2021-04-20 23:35:04 UTC
The releases/gcc-9 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:3d0135bf3be416bbe2531dc763d19b749eb2b856

commit r9-9450-g3d0135bf3be416bbe2531dc763d19b749eb2b856
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Sat Apr 17 11:27:14 2021 +0200

    sanitizer: Fix asan against glibc 2.34 [PR100114]
    
    As mentioned in the PR, SIGSTKSZ is no longer a compile time constant in
    glibc 2.34 and later, so
    static const uptr kAltStackSize = SIGSTKSZ * 4;
    needs dynamic initialization, but is used by a function called indirectly
    from .preinit_array and therefore before the variable is constructed.
    This results in using 0 size instead and all asan instrumented programs
    die with:
    ==91==ERROR: AddressSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
    
    Here is a cherry-pick from upstream to fix this.
    
    2021-04-17  Jakub Jelinek  <jakub@redhat.com>
    
            PR sanitizer/100114
            * sanitizer_common/sanitizer_posix_libcdep.cc: Cherry-pick
            llvm-project revisions 82150606fb11d28813ae6da1101f5bda638165fe
            and b93629dd335ffee2fc4b9b619bf86c3f9e6b0023.
    
    (cherry picked from commit 950bac27d63c1c2ac3a6ed867692d6a13f21feb3)
Comment 10 GCC Commits 2021-04-22 16:53:13 UTC
The releases/gcc-8 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:ef195a39d0d3b929cc676302d074b42c25460601

commit r8-10912-gef195a39d0d3b929cc676302d074b42c25460601
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Sat Apr 17 11:27:14 2021 +0200

    sanitizer: Fix asan against glibc 2.34 [PR100114]
    
    As mentioned in the PR, SIGSTKSZ is no longer a compile time constant in
    glibc 2.34 and later, so
    static const uptr kAltStackSize = SIGSTKSZ * 4;
    needs dynamic initialization, but is used by a function called indirectly
    from .preinit_array and therefore before the variable is constructed.
    This results in using 0 size instead and all asan instrumented programs
    die with:
    ==91==ERROR: AddressSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
    
    Here is a cherry-pick from upstream to fix this.
    
    2021-04-17  Jakub Jelinek  <jakub@redhat.com>
    
            PR sanitizer/100114
            * sanitizer_common/sanitizer_posix_libcdep.cc: Cherry-pick
            llvm-project revisions 82150606fb11d28813ae6da1101f5bda638165fe
            and b93629dd335ffee2fc4b9b619bf86c3f9e6b0023.
    
    (cherry picked from commit 950bac27d63c1c2ac3a6ed867692d6a13f21feb3)
Comment 11 Jakub Jelinek 2021-04-22 17:10:44 UTC
Fixed.
Comment 12 Alexander Enaldiev 2023-02-07 05:36:14 UTC
I just've seen it by compiling carbon-lang:
https://github.com/carbon-language/carbon-lang

(it could be reproduced when one downloads LLVM15 via homebrew as listed at carbon-lang README.md -- LLVM14 doesn't reproduce)

More: https://github.com/carbon-language/carbon-lang/issues/2236

But here I see status 'RESOLVED FIXED'. Do you presume, my today's issue isn't connected?
Comment 13 Florian Weimer 2023-02-07 05:54:13 UTC
(In reply to Alexander Enaldiev from comment #12)
> But here I see status 'RESOLVED FIXED'. Do you presume, my today's issue
> isn't connected?

It could still be the same bug. It's supposed to be fixed in LLVM 13 and later, but maybe your program links against system libasan.a, which may not have been fixed yet by your distribution.