From patchwork Thu Mar 13 08:33:33 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: max X-Patchwork-Id: 329804 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D3A4B2C008F for ; Thu, 13 Mar 2014 19:33:51 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=mYnz/zcmj02vsO1ZzIU0/4bizd4dQfBJlBDgzG8Bw+P CC3g2ERb3MpkyNhDakWCO5mydwDYCyoBF4PVS1NKr0QOTmIuAHfBYV6BlsjdD5NL DxxB5sXS7cUCIG/UqVpa+957Kb97zyW+EbowVW9pO/b+6qho5c6Uvt50pk4c0n+4 = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=m0rlwgWWLAUsmo+IPI4kAm9czNo=; b=u/vd29h+Dc36oVJsR bePFvj5cT7KfM9gZD9igdK50bEhJ7sZwa9FDonIRSoL4x0CBthK0AdYTqZZfDRbZ wZxXLtvSIK9bkk7OqSNGYlse1sfEmpHacozbW2k9LLY40mlZCEbr6JR+YKj4Ip1t sqyHhcFHhF+8P4gO80rI84ym4M= Received: (qmail 20280 invoked by alias); 13 Mar 2014 08:33:43 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 20270 invoked by uid 89); 13 Mar 2014 08:33:42 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, T_MANY_HDRS_LCASE, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mailout2.w1.samsung.com Received: from mailout2.w1.samsung.com (HELO mailout2.w1.samsung.com) (210.118.77.12) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (DES-CBC3-SHA encrypted) ESMTPS; Thu, 13 Mar 2014 08:33:39 +0000 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout2.w1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0N2D009P593S6V10@mailout2.w1.samsung.com> for gcc-patches@gcc.gnu.org; Thu, 13 Mar 2014 08:33:28 +0000 (GMT) Received: from eusync4.samsung.com ( [203.254.199.214]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id EB.51.18565.E5D61235; Thu, 13 Mar 2014 08:33:34 +0000 (GMT) Received: from [106.109.128.212] by eusync4.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0N2D00MGM93XYN60@eusync4.samsung.com>; Thu, 13 Mar 2014 08:33:34 +0000 (GMT) Message-id: <53216D5D.4000403@partner.samsung.com> Date: Thu, 13 Mar 2014 12:33:33 +0400 From: Maxim Ostapenko User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.1.0 MIME-version: 1.0 To: GCC Patches Cc: Yury Gribov , Slava Garbuzov Subject: RFC LeakSanitizer tests. Content-type: multipart/mixed; boundary=------------060303060203070407050506 X-IsSubscribed: yes Hi, This patch adds initial set of tests and dg infrastructure for LeakSanitizer runtime. Tested on x86_64. Ok to commit? -Maxim 2014-03-13 Max Ostapenko * c-c++-common/lsan/fork.c: New test. * c-c++-common/lsan/ignore_object.c: New test. * c-c++-common/lsan/ignore_object_errors.c: New test. * c-c++-common/lsan/large_allocation_leak.c: New test. * c-c++-common/lsan/leak_check_at_exit-1.c: New test. * c-c++-common/lsan/leak_check_at_exit-2.c: New test. * c-c++-common/lsan/link_turned_off.c: New test. * c-c++-common/lsan/pointer_to_self.c: New test. * c-c++-common/lsan/suppressions_default.c: New test. * c-c++-common/lsan/swapcontext-1.c: New test. * c-c++-common/lsan/swapcontext-2.c: New test. * c-c++-common/lsan/use_after_return.c: New test. * c-c++-common/lsan/use_globals_initialized.c: New test. * c-c++-common/lsan/use_globals_uninitialized.c: New test. * c-c++-common/lsan/use_stacks.c: New test. * c-c++-common/lsan/use_tls_static.c: New test. * c-c++-common/lsan/use_unaligned.c: New test. * g++.dg/lsan/lsan.exp: New file. * gcc.dg/lsan/lsan.exp: New file. * lib/lsan-dg.exp: New file. diff --git a/gcc/testsuite/c-c++-common/lsan/fork.c b/gcc/testsuite/c-c++-common/lsan/fork.c new file mode 100644 index 0000000..4dc9d4b --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/fork.c @@ -0,0 +1,23 @@ +// Test that thread local data is handled correctly after forking without exec(). +/* { dg-do run } */ + +#include +#include +#include +#include +#include + +__thread void *thread_local_var; + +int main() { + int status = 0; + thread_local_var = malloc(1337); + pid_t pid = fork(); + assert(pid >= 0); + if (pid > 0) { + waitpid(pid, &status, 0); + assert(WIFEXITED(status)); + return WEXITSTATUS(status); + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/lsan/ignore_object.c b/gcc/testsuite/c-c++-common/lsan/ignore_object.c new file mode 100644 index 0000000..d73f08b --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/ignore_object.c @@ -0,0 +1,31 @@ +// Test for __lsan_ignore_object(). + +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=3" } */ +/* { dg-set-target-env-var ASAN_OPTIONS "verbosity=3" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +#ifdef __cplusplus +extern "C" +#endif +void __lsan_ignore_object(void **p); + +int main() { + // Explicitly ignored object. + void **p = (void **) malloc(sizeof(void **)); + // Transitively ignored object. + *p = malloc(666); + // Non-ignored object. + volatile void *q = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + fprintf(stderr, "Test alloc_2: %p.\n", q); + __lsan_ignore_object(p); + return 0; +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "ignoring heap object at .*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer: 1337 byte\\(s\\) leaked in 1 allocation\\(s\\).*" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/ignore_object_errors.c b/gcc/testsuite/c-c++-common/lsan/ignore_object_errors.c new file mode 100644 index 0000000..47a1cd1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/ignore_object_errors.c @@ -0,0 +1,25 @@ +// Test for incorrect use of __lsan_ignore_object(). +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "verbosity=2" } */ + +#include +#include + +#ifdef __cplusplus +extern "C" +#endif +void __lsan_ignore_object(const void *p); + +int main() { + void *p = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + __lsan_ignore_object(p); + __lsan_ignore_object(p); + free(p); + __lsan_ignore_object(p); + return 0; +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "heap object at .* is already being ignored.*" } */ +/* { dg-output "no heap object found at .*" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/large_allocation_leak.c b/gcc/testsuite/c-c++-common/lsan/large_allocation_leak.c new file mode 100644 index 0000000..36511d3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/large_allocation_leak.c @@ -0,0 +1,19 @@ +// Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure. +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +int main() { + // maxsize in primary allocator is always less than this (1 << 25). + void *large_alloc = malloc(33554432); + fprintf(stderr, "Test alloc: %p.\n", large_alloc); + return 0; +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "Directly leaked 33554432 byte object at .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/leak_check_at_exit-1.c b/gcc/testsuite/c-c++-common/lsan/leak_check_at_exit-1.c new file mode 100644 index 0000000..443a2b1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/leak_check_at_exit-1.c @@ -0,0 +1,24 @@ +// Test for the leak_check_at_exit flag. + +/* { dg-do run } */ +/* { dg-options "-fno-builtin" } */ +/* { dg-set-target-env-var LSAN_OPTIONS "verbosity=1:leak_check_at_exit=0" } */ +/* { dg-set-target-env-var ASAN_OPTIONS "leak_check_at_exit=0" } */ + +#ifdef __cplusplus +extern "C" +#endif +void __lsan_do_leak_check(); + +#ifdef __cplusplus +extern "C" +#endif +int printf (const char *format, ...); + +int main(int argc, char *argv[]) { + printf("printf to break optimization\n"); + __lsan_do_leak_check(); + return 0; +} + +/* { dg-output "(Leak|Address)Sanitizer: .*" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/leak_check_at_exit-2.c b/gcc/testsuite/c-c++-common/lsan/leak_check_at_exit-2.c new file mode 100644 index 0000000..8ae955a --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/leak_check_at_exit-2.c @@ -0,0 +1,18 @@ +// Test for the leak_check_at_exit flag. + +/* { dg-do run } */ +/* { dg-options "-fno-builtin" } */ +/* { dg-set-target-env-var LSAN_OPTIONS "verbosity=1:leak_check_at_exit=0" } */ +/* { dg-set-target-env-var ASAN_OPTIONS "leak_check_at_exit=0" } */ + +#ifdef __cplusplus +extern "C" +#endif +int printf (const char *format, ...); + +int main(int argc, char *argv[]) { + printf("printf to break optimization\n"); + return 0; +} + +/* { dg-prune-output "(Leak|Address)Sanitizer: .*" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/link_turned_off.c b/gcc/testsuite/c-c++-common/lsan/link_turned_off.c new file mode 100644 index 0000000..9e7e428 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/link_turned_off.c @@ -0,0 +1,21 @@ +// Test for disabling LSan at link-time. + +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "use_stacks=0:use_registers=0" } */ + +#include + +#ifdef __cplusplus +extern "C" +#endif +int __lsan_is_turned_off() { + return 1; +} + +int main(int argc, char *argv[]) { + volatile int *x = (volatile int *) malloc(sizeof(int)); + *x = 42; + return 0; +} + +/* { dg-prune-output "SUMMARY: (Leak|Address)Sanitizer: 4 byte\\(s\\) leaked in 1 allocation\\(s\\)" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/pointer_to_self.c b/gcc/testsuite/c-c++-common/lsan/pointer_to_self.c new file mode 100644 index 0000000..5cfa5a4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/pointer_to_self.c @@ -0,0 +1,18 @@ +// Regression test: pointers to self should not confuse LSan into thinking the +// object is indirectly leaked. Only external pointers count. +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +int main() { + void *p = malloc(1337); + *((void **) p) = p; + fprintf(stderr, "Test alloc: %p.\n", p); +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/suppressions_default.c b/gcc/testsuite/c-c++-common/lsan/suppressions_default.c new file mode 100644 index 0000000..8d41e75 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/suppressions_default.c @@ -0,0 +1,29 @@ +// Test for ScopedDisabler. +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "use_stacks=0:use_registers=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +#ifdef __cplusplus +extern "C" +#endif +const char *__lsan_default_suppressions() { + return "leak:*LSanTestLeakingFunc*"; +} + +void LSanTestLeakingFunc() { + void *p = malloc(666); + fprintf(stderr, "Test alloc: %p.\n", p); +} + +int main() { + LSanTestLeakingFunc(); + void *q = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", q); + return 0; +} +/* { dg-output "Suppressions used:.*" } */ +/* { dg-output "1.*666 \\*LSanTestLeakingFunc\\*.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer: 1337 byte\\(s\\) leaked in 1 allocation\\(s\\).*" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/swapcontext-1.c b/gcc/testsuite/c-c++-common/lsan/swapcontext-1.c new file mode 100644 index 0000000..e16ef15 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/swapcontext-1.c @@ -0,0 +1,41 @@ +// We can't unwind stack if we're running coroutines on heap-allocated +// memory. Make sure we don't report these leaks. + +/* { dg-do run } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include +#include +#include + +const int kStackSize = 1 << 20; + +void Child() { + int child_stack; + printf("Child: %p\n", &child_stack); + volatile int *leaked = (volatile int *) malloc(666 * sizeof(int)); + leaked[0] = 1; + printf("leaked[0] = %d\n", leaked[0]); +} + +int main(int argc, char *argv[]) { + char stack_memory[kStackSize + 1]; + char *child_stack = stack_memory; + + printf("Child stack: %p\n", child_stack); + ucontext_t orig_context; + ucontext_t child_context; + getcontext(&child_context); + child_context.uc_stack.ss_sp = child_stack; + child_context.uc_stack.ss_size = kStackSize / 2; + child_context.uc_link = &orig_context; + makecontext(&child_context, Child, 0); + if (swapcontext(&orig_context, &child_context) < 0) { + perror("swapcontext"); + return 1; + } + return 0; +} + +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer: 2664 byte\\(s\\) leaked in 1 allocation\\(s\\)" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/swapcontext-2.c b/gcc/testsuite/c-c++-common/lsan/swapcontext-2.c new file mode 100644 index 0000000..9b9bcd6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/swapcontext-2.c @@ -0,0 +1,39 @@ +// We can't unwind stack if we're running coroutines on heap-allocated +// memory. Make sure we don't report these leaks. + +/* { dg-do run } */ + +#include +#include +#include +#include + +const int kStackSize = 1 << 20; + +void Child() { + int child_stack; + printf("Child: %p\n", &child_stack); + int *leaked = (int *) malloc(666 * sizeof(int)); +} + +int main(int argc, char *argv[]) { + char *heap_memory = (char *) malloc(kStackSize + 1); + char *child_stack = heap_memory; + + printf("Child stack: %p\n", child_stack); + ucontext_t orig_context; + ucontext_t child_context; + getcontext(&child_context); + child_context.uc_stack.ss_sp = child_stack; + child_context.uc_stack.ss_size = kStackSize / 2; + child_context.uc_link = &orig_context; + makecontext(&child_context, Child, 0); + if (swapcontext(&orig_context, &child_context) < 0) { + perror("swapcontext"); + return 1; + } + free(heap_memory); + return 0; +} + +/* { dg-prune-output "SUMMARY: (Leak|Address)Sanitizer: 2664 byte\\(s\\) leaked in 1 allocation\\(s\\)" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/use_after_return.c b/gcc/testsuite/c-c++-common/lsan/use_after_return.c new file mode 100644 index 0000000..9373e48 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/use_after_return.c @@ -0,0 +1,22 @@ +// Test that fake stack (introduced by ASan's use-after-return mode) is included +// in the root set. +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0" } */ +/* { dg-set-target-env-var ASAN_OPTIONS "detect_stack_use_after_return=1" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +int main() { + void *stack_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", stack_var); + // Take pointer to variable, to ensure it's not optimized into a register. + fprintf(stderr, "Stack var at: %p.\n", &stack_var); + // Do not return from main to prevent the pointer from going out of scope. + exit(0); +} +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "Directly leaked 1337 byte object at .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/use_globals_initialized.c b/gcc/testsuite/c-c++-common/lsan/use_globals_initialized.c new file mode 100644 index 0000000..f6647c8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/use_globals_initialized.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0:use_globals=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +void *data_var = (void *) 1; + +int main() { + data_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", data_var); + return 0; +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "Directly leaked 1337 byte object at .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/use_globals_uninitialized.c b/gcc/testsuite/c-c++-common/lsan/use_globals_uninitialized.c new file mode 100644 index 0000000..538c546 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/use_globals_uninitialized.c @@ -0,0 +1,19 @@ +// Test that uninitialized globals are included in the root set. +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0:use_globals=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +void *bss_var; + +int main() { + bss_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", bss_var); + return 0; +} +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "Directly leaked 1337 byte object at .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/use_stacks.c b/gcc/testsuite/c-c++-common/lsan/use_stacks.c new file mode 100644 index 0000000..abf0aee --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/use_stacks.c @@ -0,0 +1,19 @@ +// Test that stack of main thread is included in the root set. +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +int main() { + void *stack_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", stack_var); + // Do not return from main to prevent the pointer from going out of scope. + exit(0); +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "Directly leaked 1337 byte object at .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/use_tls_static.c b/gcc/testsuite/c-c++-common/lsan/use_tls_static.c new file mode 100644 index 0000000..dd27883 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/use_tls_static.c @@ -0,0 +1,20 @@ +// Test that statically allocated TLS space is included in the root set. +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0:use_tls=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include + +__thread void *tls_var; + +int main() { + tls_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", tls_var); + return 0; +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "Directly leaked 1337 byte object at .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/c-c++-common/lsan/use_unaligned.c b/gcc/testsuite/c-c++-common/lsan/use_unaligned.c new file mode 100644 index 0000000..1aff6a9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/lsan/use_unaligned.c @@ -0,0 +1,24 @@ +// Test that unaligned pointers are detected correctly. + +/* { dg-do run } */ +/* { dg-set-target-env-var LSAN_OPTIONS "report_objects=1:use_stacks=0:use_registers=0:use_unaligned=0" } */ +/* { dg-shouldfail "lsan" } */ + +#include +#include +#include + +void *arr[2]; + +int main() { + void *p = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + char *char_arr = (char *)arr; + memcpy(char_arr + 1, &p, sizeof(p)); + return 0; +} + +/* { dg-output "Test alloc: .*" } */ +/* { dg-output "Directly leaked 1337 byte object at .*" } */ +/* { dg-output "LeakSanitizer: detected memory leaks.*" } */ +/* { dg-output "SUMMARY: (Leak|Address)Sanitizer" } */ diff --git a/gcc/testsuite/g++.dg/lsan/lsan.exp b/gcc/testsuite/g++.dg/lsan/lsan.exp new file mode 100644 index 0000000..f531a44 --- /dev/null +++ b/gcc/testsuite/g++.dg/lsan/lsan.exp @@ -0,0 +1,38 @@ +# Copyright (C) 2012-2014 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Load support procs. +load_lib g++-dg.exp +load_lib lsan-dg.exp + +if ![check_effective_target_fleak_sanitizer] { + return +} + +# Initialize `dg'. +dg-init +if [lsan_init] { + +# Main loop. +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/lsan/*.c]] "" + +} + +# All done. +lsan_finish +dg-finish diff --git a/gcc/testsuite/gcc.dg/lsan/lsan.exp b/gcc/testsuite/gcc.dg/lsan/lsan.exp new file mode 100644 index 0000000..d5f5749 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lsan/lsan.exp @@ -0,0 +1,40 @@ +# Copyright (C) 2012-2014 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp +load_lib lsan-dg.exp + +if ![check_effective_target_fleak_sanitizer] { + return +} + +# Initialize `dg'. +dg-init +if [lsan_init] { + +# Main loop. +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/lsan/*.c]] "" + +} + +# All done. +lsan_finish +dg-finish diff --git a/gcc/testsuite/lib/lsan-dg.exp b/gcc/testsuite/lib/lsan-dg.exp new file mode 100644 index 0000000..143b71c --- /dev/null +++ b/gcc/testsuite/lib/lsan-dg.exp @@ -0,0 +1,113 @@ +# Copyright (C) 2012-2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Return 1 if compilation with -fsanitize=leak is error-free for trivial +# code, 0 otherwise. + +proc check_effective_target_fleak_sanitizer {} { + return [check_no_compiler_messages fleak_sanitizer object { + void foo (void) { } + } "-fsanitize=leak"] +} + +# +# lsan_link_flags -- compute library path and flags to find liblsan. +# (originally from g++.exp) +# + +proc lsan_link_flags { paths } { + global srcdir + global ld_library_path + global shlib_ext + + set gccpath ${paths} + set flags "" + + set shlib_ext [get_shlib_extension] + + if { $gccpath != "" } { + if { [file exists "${gccpath}/libsanitizer/lsan/.libs/liblsan.a"] + || [file exists "${gccpath}/libsanitizer/lsan/.libs/liblsan.${shlib_ext}"] } { + append flags " -B${gccpath}/libsanitizer/ " + append flags " -B${gccpath}/libsanitizer/lsan/ " + append flags " -L${gccpath}/libsanitizer/lsan/.libs " + append ld_library_path ":${gccpath}/libsanitizer/lsan/.libs" + } + } else { + global tool_root_dir + + set liblsan [lookfor_file ${tool_root_dir} liblsan] + if { $liblsan != "" } { + append flags "-L${liblsan} " + append ld_library_path ":${liblsan}" + } + } + set_ld_library_path_env_vars + return "$flags" +} + +# +# lsan_init -- called at the start of each subdir of tests +# + +proc lsan_init { args } { + global TEST_ALWAYS_FLAGS + global ALWAYS_CXXFLAGS + global TOOL_OPTIONS + global lsan_saved_TEST_ALWAYS_FLAGS + set link_flags "" + if ![is_remote host] { + if [info exists TOOL_OPTIONS] { + set link_flags "[lsan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + } else { + set link_flags "[lsan_link_flags [get_multilibs]]" + } + } + + if [info exists TEST_ALWAYS_FLAGS] { + set lsan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS + } + if [info exists ALWAYS_CXXFLAGS] { + set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS] + set ALWAYS_CXXFLAGS [concat "{additional_flags=-fsanitize=leak -g}" $ALWAYS_CXXFLAGS] + } else { + if [info exists TEST_ALWAYS_FLAGS] { + set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=leak -g $TEST_ALWAYS_FLAGS" + } else { + set TEST_ALWAYS_FLAGS "$link_flags -fsanitize=leak -g" + } + } + if { $link_flags != "" } { + return 1 + } + return 0 +} + +# +# lsan_finish -- called at the start of each subdir of tests +# + +proc lsan_finish { args } { + global TEST_ALWAYS_FLAGS + global lsan_saved_TEST_ALWAYS_FLAGS + + if [info exists lsan_saved_TEST_ALWAYS_FLAGS] { + set TEST_ALWAYS_FLAGS $lsan_saved_TEST_ALWAYS_FLAGS + } else { + unset TEST_ALWAYS_FLAGS + } +} +