This is an archive of the discontinued LLVM Phabricator instance.

Add NetBSD LSan support
ClosedPublic

Authored by krytarowski on Jul 1 2019, 7:21 PM.

Details

Summary

Combine few relatively small changes into one:

  • implement internal_ptrace() and internal_clone() for NetBSD
  • add support for stoptheworld based on the ptrace(2) API
  • define COMPILER_RT_HAS_LSAN for NetBSD
  • enable tests for NetBSD/amd64

Inspired by the original implementation by Christos Zoulas in netbsd/src for GCC.

The implementation is in theory CPU independent through well defined macros
across all NetBSD ports, however only the x86_64 version was tested.

Diff Detail

Repository
rL LLVM

Event Timeline

krytarowski created this revision.Jul 1 2019, 7:21 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 1 2019, 7:21 PM
  • Fixup style.

This code in general works.. however the tests are not compatible with NetBSD.

Please see:

$ env LSAN_OPTIONS=report_objects=1:use_stacks=1:use_registers=1 /public/llvm-build/projects/compiler-rt/test/lsan/X86_64LsanConfig/TestCases/Output/use_unaligned.cc.tmp
Test alloc: 0x61a000000000 

=================================================================
==6705==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1337 byte(s) in 1 object(s) allocated from:
    #0 0x4048f5 in malloc /public/llvm/projects/compiler-rt/lib/lsan/lsan_interceptors.cc:54:3
    #1 0x41e308 in main /public/compiler-rt/test/lsan/TestCases/use_unaligned.cc:15:13
    #2 0x4032bc in ___start (/public/llvm-build/projects/compiler-rt/test/lsan/X86_64LsanConfig/TestCases/Output/use_unaligned.cc.tmp+0x4032bc)

Objects leaked above:
0x61a000000000 (1337 bytes)

SUMMARY: LeakSanitizer: 1337 byte(s) leaked in 1 allocation(s).
$ env LSAN_OPTIONS=report_objects=1:use_stacks=0:use_registers=1 /public/llvm-build/projects/compiler-rt/test/lsan/X86_64LsanConfig/TestCases/Output/use_unaligned.cc.tmp
Test alloc: 0x61a000000000 

=================================================================
==6026==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1337 byte(s) in 1 object(s) allocated from:
    #0 0x4048f5 in malloc /public/llvm/projects/compiler-rt/lib/lsan/lsan_interceptors.cc:54:3
    #1 0x41e308 in main /public/compiler-rt/test/lsan/TestCases/use_unaligned.cc:15:13
    #2 0x4032bc in ___start (/public/llvm-build/projects/compiler-rt/test/lsan/X86_64LsanConfig/TestCases/Output/use_unaligned.cc.tmp+0x4032bc)

Objects leaked above:
0x61a000000000 (1337 bytes)

Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x4048f5 in malloc /public/llvm/projects/compiler-rt/lib/lsan/lsan_interceptors.cc:54:3
    #1 0x7f7ff6160e67 in atexit_handler_alloc /usr/src/lib/libc/stdlib/atexit.c:112
    #2 0x7f7ff6160e67 in __cxa_atexit_internal /usr/src/lib/libc/stdlib/atexit.c:158

Objects leaked above:
0x602000000000 (32 bytes)

Indirect leak of 128 byte(s) in 4 object(s) allocated from:
    #0 0x4048f5 in malloc /public/llvm/projects/compiler-rt/lib/lsan/lsan_interceptors.cc:54:3
    #1 0x7f7ff6160e67 in atexit_handler_alloc /usr/src/lib/libc/stdlib/atexit.c:112
    #2 0x7f7ff6160e67 in __cxa_atexit_internal /usr/src/lib/libc/stdlib/atexit.c:158

Objects leaked above:
0x602000000020 (32 bytes)
0x602000000040 (32 bytes)
0x602000000060 (32 bytes)
0x602000000080 (32 bytes)

SUMMARY: LeakSanitizer: 1497 byte(s) leaked in 6 allocation(s).

This causes breakage in all LSan tests. What should we do with this? Is there need to fix something in LSan? Tune the tests?

Testing notification e-mails from phabricator.

Ping? There is planned LLVM branching soon and I would like to see this in LLVM 9.0.

Actually after a longer thought I would like to enable LSan for all NetBSD CPUs, but keep the tests for amd64 for now.

vitalybuka added inline comments.Jul 8 2019, 11:28 AM
lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
614 ↗(On Diff #207467)

can you put this and other forked function into sanitizer_linux.cc/sanitizer_netbst.cc/sanitizer_linux_libcdep.cc ?

krytarowski marked an inline comment as done.Jul 8 2019, 11:49 PM
krytarowski added inline comments.
lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
614 ↗(On Diff #207467)

Do you mean to split sanitizer_stoptheworld_linux_libcdep.cc into ptrace-generic and linux and NetBSD?

I think it is not a good idea:

  • this cannot work on other ptrace(2) fueled systems (at least NetBSD is the only one having enough batteries to do it in a similar way to Linux)
  • duplicating or splitting stoptheworld implementation that is a hack is not a good idea, better to keep it in a single file - I don't want to see it spread to multiple files
  • the amount of ifdefs is not that large and they are only for essential operation
  • I plan to write an alternative implementation with a dedicated syscall for StopTheWorld(), but that would happen not sooner than in NetBSD 10.0 and we want to keep this ptrace(2) version here for the time being
vitalybuka added inline comments.Jul 9 2019, 3:04 PM
lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
423 ↗(On Diff #207467)

now it will silently compile if we remove include <sys/prctl.h>

it should be internal_set_dumpable with noop on NETBSD
or better two StopTheWorldScope for Linux and NETBSD

512 ↗(On Diff #207467)

internal_set_ptracer

585 ↗(On Diff #207467)

SuspendedThreadsListLinux is also can be forked

614 ↗(On Diff #207467)

Sanitizers are full of hack.
Also it looks like you just need to fork completely entire classes like: SuspendedThreadsListLinux, StopTheWorldScope, ThreadSuspender...

krytarowski retitled this revision from Add NetBSD/amd64 LSan support to Add NetBSD LSan support.
  • switch the protype of internal_ptrace() to the one matching NetBSD
  • move the stop-the-world implementation for NetBSD into a separate file
  • minor changes
vitalybuka accepted this revision.Jul 10 2019, 1:28 PM

LGTM, Thank you!

lib/sanitizer_common/sanitizer_netbsd.cc
325 ↗(On Diff #208896)

Looks like you completely forked sanitizer_stoptheworld_netbsd_libcdep
in this case you don't new internal_
up to you if you like to keep them

This revision is now accepted and ready to land.Jul 10 2019, 1:28 PM
This revision was automatically updated to reflect the committed changes.

I've landed this version as it is good enough to land LLVM-9.

Unfortunately many tests fail as they seem to be tuned for Linux/Darwin.

Please see:

https://reviews.llvm.org/D64057#1565937

@vitalybuka how to address these problems?

I've landed this version as it is good enough to land LLVM-9.

Unfortunately many tests fail as they seem to be tuned for Linux/Darwin.

Please see:

https://reviews.llvm.org/D64057#1565937

@vitalybuka how to address these problems?

Can you show how the tests *fail*>
I.e. what is the diff between expected and actual output?

I've landed this version as it is good enough to land LLVM-9.

Unfortunately many tests fail as they seem to be tuned for Linux/Darwin.

Please see:

https://reviews.llvm.org/D64057#1565937

@vitalybuka how to address these problems?

Can you show how the tests *fail*>
I.e. what is the diff between expected and actual output?

For start most of the problems come from this:

  1. LSan registers check in AtExit(). There are other callbacks registered out there.
  2. In __cxa_finalize() we first call the callbacks and at the end of the procedure we free() the memory

https://nxr.netbsd.org/xref/src/lib/libc/stdlib/atexit.c#191

247 
248 	/*
249 	 * Now free any dead handlers.  Do this even if we're about to
250 	 * exit, in case a leak-detecting malloc is being used.
251 	 */
252 	while ((ah = dead_handlers) != NULL) {
253 		dead_handlers = ah->ah_next;
254 		free(ah);
255 	}
256 }
  1. In the tests there is enforced option use_stacks=0. This leads to false positives that struct atexit_handler *ah; is leaked. This is not true as its reference is still kept and it will be released soon after finishing execution of the callbacks.