[compiler-rt] ASan AddrIsAlignedByGranularity(addr) != 0 errors on recent i386-freebsd11 and higher

Dimitry Andric via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 7 07:56:19 PDT 2016


Hi,

In relation to the upcoming 3.9 release, I have been running
llvm/clang/compiler-rt tests on various FreeBSD versions and
architectures. On of my findings is that on FreeBSD 11 and 12 for i386,
almost all AddressSanitizer tests started failing some time ago with
assertion failures similar to:

==46104==AddressSanitizer CHECK failed: /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/asan_poisoning.cc:36 "((AddrIsAlignedByGranularity(addr))) != (0)" (0x0, 0x0)
    #0 0x80c51b3 in __asan::AsanCheckFailed(char const*, int, char const, unsigned long long, unsigned long long) /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/asan_rtl.cc:68:3
    #1 0x80da459 in __sanitizer::CheckFailed(char const*, int, char const, unsigned long long, unsigned long long) /share/dim/src/llvm/asantest/projects/compiler-rt/lib/sanitizer_common/sanitizer_termination.cc:79:5
    #2 0x80ba4f7 in __asan::PoisonShadow(unsigned long, unsigned long, unsigned char) /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/asan_poisoning.cc:36:3
    #3 0x80c717b in __asan::AsanThread::ClearShadowForThreadStackAndTLS(void) /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/asan_thread.cc:281:5
    #4 0x80c717b in __asan::AsanThread::Init(void) /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/asan_thread.cc:226
    #5 0x80c73df in __asan::AsanThread::ThreadStart(unsigned long, __sanitizer::atomic_uintptr_t*) /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/asan_thread.cc:235:3
    #6 0x80c4d6f in __asan::AsanInitInternal(void) /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/asan_rtl.cc:549:3
    #7 0x809689f in pthread_mutex_lock /share/dim/src/llvm/asantest/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:3609:3
    #8 0x281b34e5 in std::__1::__call_once(unsigned long volatile&, void*, void(*)(unsigned long volatile&)) /usr/src/lib/libc++/../../contrib/libc++/src/mutex.cpp:250:5
    #9 0x28172daf in _ZNSt3__19call_onceINS_12_GLOBAL__N_111__fake_bindEJEEEvRNS_9once_flagEOT_DpOT0_ /usr/src/lib/libc++/../../contrib/libc++/include/mutex:550:9
    #10 0x28172daf in std::__1::locale::id::__get(void) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:642
    #11 0x28172daf in std::__1::locale::__imp::install<std::__1::collate<char> >(void, char*) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:162
    #12 0x28172daf in std::__1::locale::__imp::__imp(unsigned int) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:176
    #13 0x28178486 in std::__1::locale::__imp& std::__1::(anonymous namespace)::make<std::__1::locale::__imp, unsigned int>(unsigned int) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:68:18
    #14 0x28178486 in std::__1::locale::__imp::make_classic(void) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:463
    #15 0x28178486 in std::__1::locale::classic(void) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:470
    #16 0x28178486 in std::__1::locale::__imp::make_global(void) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:479
    #17 0x28178583 in std::__1::locale::__global(void) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:486:24
    #18 0x28178583 in std::__1::locale::locale(void) /usr/src/lib/libc++/../../contrib/libc++/src/locale.cpp:491
    #19 0x281a5efa in std::__1::basic_streambuf<char, std::__1::char_traits<char> >::basic_streambuf(void) /usr/src/lib/libc++/../../contrib/libc++/include/streambuf:163:5
    #20 0x2815e8a5 in std::__1::__stdinbuf<char>::__stdinbuf(__sFILE*, __mbstate_t*) /usr/src/lib/libc++/../../contrib/libc++/include/__std_stream:44:5
    #21 0x2815e48b in std::__1::ios_base::Init::Init(void) /usr/src/lib/libc++/../../contrib/libc++/src/iostream.cpp:49:59
    #22 0x2815e847 in __cxx_global_var_init /usr/src/lib/libc++/../../contrib/libc++/src/iostream.cpp:44:16
    #23 0x2815e847 in _GLOBAL__sub_I_iostream.cpp /usr/src/lib/libc++/../../contrib/libc++/src/iostream.cpp

The alignment checked for is 8 bytes by default, as defined in
lib/asan/asan_mapping.h, and for some reason a region to be poisoned was
no longer aligned properly.  After some bisecting, it turned out that a
recent jemalloc update in the FreeBSD base system[1] *seemed* to be
responsible for the assertion.

However, this was really a red herring.  On i386-freebsd, TLS sections
are aligned to 4 bytes by default, and until now, we have apparently
been "lucky" that the TLS section in libc.so was accidentally aligned to
8 bytes!  The recent jemalloc update added a few TLS variables, and this
caused the alignment to change again.

E.g., before the jemalloc update, libc.so.7's program headers looked
like this:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x227ca4 0x227ca4 R E 0x1000
  LOAD           0x228000 0x00228000 0x00228000 0x06bd4 0x1b778 RW  0x1000
  DYNAMIC        0x22a730 0x0022a730 0x0022a730 0x000c8 0x000c8 RW  0x4
  TLS            0x228000 0x00228000 0x00228000 0x00034 0x0004c R   0x4
  GNU_EH_FRAME   0x2276f4 0x002276f4 0x002276f4 0x0013c 0x0013c R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

And after the update, they became:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x2334bc 0x2334bc R E 0x1000
  LOAD           0x2334bc 0x002344bc 0x002344bc 0x06c3c 0x1b8c4 RW  0x1000
  DYNAMIC        0x235c34 0x00236c34 0x00236c34 0x000c8 0x000c8 RW  0x4
  TLS            0x2334bc 0x002344bc 0x002344bc 0x00040 0x00058 R   0x4
  GNU_EH_FRAME   0x232f0c 0x00232f0c 0x00232f0c 0x0013c 0x0013c R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

Specifically the TLS section is now no longer aligned to 8 bytes, but
from the FreeBSD i386 ABI point of view, this is of course still
entirely correct.

If you look at the stack trace above, this is all occurring during
AsanThread::Init(), which is run from one of ASan's interceptors.  It
calls ClearShadowForThreadStackAndTLS() to poison the stack, and there
it turns out that tls_begin_ is no longer aligned to 8 bytes.  This was
verified by adding a Printf() to show the actual values:

--- lib/asan/asan_thread.cc     (revision 277349)
+++ lib/asan/asan_thread.cc     (working copy)
@@ -275,8 +275,11 @@

 void AsanThread::ClearShadowForThreadStackAndTLS() {
   PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
-  if (tls_begin_ != tls_end_)
+  if (tls_begin_ != tls_end_) {
+    Printf("ClearShadowForThreadStackAndTLS: tls_begin_=%zx, tls_end_=%zx\n",
+      tls_begin_, tls_end_);
     PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
+  }
 }

 bool AsanThread::GetStackFrameAccessByAddr(uptr addr,

which at runtime now produces:

  ClearShadowForThreadStackAndTLS: tls_begin_=2812b2dc, tls_end_=2812b2f4

Now to finish up this long story, my question is how this can be made to
work at all?

I tried changing kDefaultShadowScale from 3 to 2, which changes
SHADOW_GRANULARITY from 8 to 4.  But that very obviously didn't work,
since almost all ASan tests started failing. :)  Reading about the
AddressSanitizer algorithm on GitHub seems to indicate that it is
specifically mapping 8 bytes of application memory into 1 byte of
shadow memory, so maybe the 8 byte granularity is essential and cannot
be changed at all?

I also don't think ripping out the CHECK() statements will work, as
these sanity checks were obviously inserted on purpose.

So what is the story?  Can AddressSanitizer work at all, with memory
segments aligned to 4 bytes?

-Dimitry

[1] https://svnweb.freebsd.org/base?view=revision&revision=299587

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 194 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160807/3a537e1b/attachment.sig>


More information about the llvm-commits mailing list