From patchwork Thu Dec 5 10:19:35 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: max X-Patchwork-Id: 296765 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)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 0E6E92C007B for ; Thu, 5 Dec 2013 21:19:56 +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:references :in-reply-to:content-type; q=dns; s=default; b=PNthH8Ui8c3eX2pon tCgJdgje9g9tpDgQsbKaawoEMgLAF3uNHIvHbtt0G/lxcJNlPp2zqf/yKeVxoDOd JOakvL0t+1r4b+gEL68X7Eb8hComDMsIRI6Zjek0+hsEXu0sKNZM4ADjZWVgswyD 8mCJRyfRWtsSFald3lVETrnCtY= 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:references :in-reply-to:content-type; s=default; bh=Pm9CHmmPpnnUL5VrAK+ZTW7 PJ+c=; b=WbHG1aj2w2UNDLr4FdjDUMzs6G4YdMlKF6JPZh3AzutP5a8hlxBEXEo zgs+LdZmZYRcozZzNDs8oPA0wHcpNilWDt80AIBeFfTUmW3cond4AoKia8flK5A9 G9qe3W2vUTcgMNsf7wobEeFAHU9/J3UL3obMvkVaYgp+YeUboTC4= Received: (qmail 31796 invoked by alias); 5 Dec 2013 10:19:50 -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 31780 invoked by uid 89); 5 Dec 2013 10:19:49 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS autolearn=ham version=3.3.2 X-HELO: mailout1.w1.samsung.com Received: from Unknown (HELO mailout1.w1.samsung.com) (210.118.77.11) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (DES-CBC3-SHA encrypted) ESMTPS; Thu, 05 Dec 2013 10:19:47 +0000 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout1.w1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MXB00D6MWOP8DA0@mailout1.w1.samsung.com> for gcc-patches@gcc.gnu.org; Thu, 05 Dec 2013 10:19:37 +0000 (GMT) Received: from eusync1.samsung.com ( [203.254.199.211]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id 9A.C5.00985.83350A25; Thu, 05 Dec 2013 10:19:36 +0000 (GMT) Received: from [106.109.128.86] by eusync1.samsung.com (Oracle Communications Messaging Server 7u4-23.01(7.0.4.23.0) 64bit (built Aug 10 2011)) with ESMTPA id <0MXB0063KWOO7T30@eusync1.samsung.com>; Thu, 05 Dec 2013 10:19:36 +0000 (GMT) Message-id: <52A05337.3060200@partner.samsung.com> Date: Thu, 05 Dec 2013 14:19:35 +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@gcc.gnu.org Cc: Yury Gribov , Slava Garbuzov Subject: Re: RFC ThreadSanitizer tests References: <52A01954.60901@partner.samsung.com> In-reply-to: <52A01954.60901@partner.samsung.com> Content-type: multipart/mixed; boundary=------------000003020500080901050702 X-IsSubscribed: yes > Instead of mentioning the directory in the ChangeLog, > mention the individual test files. > ... > * g++.dg/dg.exp: Prune tsan subdirectory. Thanks, I fixed the ChangeLog file. > how long does it take to run make check-gcc check-g++ RUNTESTFLAGS=tsan.exp ? > How much memory does it need? I've run `make check-gcc RUNTESTFLAGS=tsan.exp' (this also includes c++ tests) under `/usr/bin/time -v' and got: -Elapsed (wall clock) time (h:mm:ss or m:ss): 3:17.04 -Maximum resident set size (kbytes): 199872 kbytes The same numbers for asan are (/usr/bin/time -v make check-gcc RUNTESTFLAGS=asan.exp): -Elapsed (wall clock) time (h:mm:ss or m:ss): 3:56.38 -Maximum resident set size (kbytes): 3155264 kbytes -Maxim 2013-12-05 Max Ostapenko < m.ostapenko@partner.samsung.com > * c-c++-common/tsan/atomic_stack.c: New test. * c-c++-common/tsan/fd_pipe_race.c: New test. * c-c++-common/tsan/free_race.c: New test. * c-c++-common/tsan/mutexset1.c: New test. * c-c++-common/tsan/race_on_barrier.c: New test. * c-c++-common/tsan/sleep_sync.c: New test. * c-c++-common/tsan/thread_leak.c: New test. * c-c++-common/tsan/thread_leak1.c: New test. * c-c++-common/tsan/thread_leak2.c: New test. * c-c++-common/tsan/tiny_race.c: New test. * c-c++-common/tsan/tls_race.c: New test. * c-c++-common/tsan/write_in_reader_lock.c: New test. * lib/tsan-dg.exp: New file. * gcc.dg/tsan/tsan.exp: New file. * g++.dg/tsan/tsan.exp: New file. * g++.dg/dg.exp: Prune tsan subdirectory. diff --git a/gcc/testsuite/c-c++-common/tsan/atomic_stack.c b/gcc/testsuite/c-c++-common/tsan/atomic_stack.c new file mode 100644 index 0000000..eac71b8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/atomic_stack.c @@ -0,0 +1,32 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include + +int Global; + +void *Thread1(void *x) { + sleep(1); + __atomic_fetch_add(&Global, 1, __ATOMIC_RELAXED); + return NULL; +} + +void *Thread2(void *x) { + Global++; + return NULL; +} + +int main() { + pthread_t t[2]; + pthread_create(&t[0], NULL, Thread1, NULL); + pthread_create(&t[1], NULL, Thread2, NULL); + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ +/* { dg-output " Atomic write of size 4.*" } */ +/* { dg-output " #0 __tsan_atomic32_fetch_add.*" } */ +/* { dg-output " #1 Thread1.*" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/fd_pipe_race.c b/gcc/testsuite/c-c++-common/tsan/fd_pipe_race.c new file mode 100644 index 0000000..fc76cbf --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/fd_pipe_race.c @@ -0,0 +1,37 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include +#include + +int fds[2]; + +void *Thread1(void *x) { + write(fds[1], "a", 1); + return NULL; +} + +void *Thread2(void *x) { + sleep(1); + close(fds[0]); + close(fds[1]); + return NULL; +} + +int main() { + pipe(fds); + pthread_t t[2]; + pthread_create(&t[0], NULL, Thread1, NULL); + pthread_create(&t[1], NULL, Thread2, NULL); + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*\n" } */ +/* { dg-output " Write of size 8.*\n" } */ +/* { dg-output " #0 close.*\n" } */ +/* { dg-output " #1 Thread2.*\n" } */ +/* { dg-output " Previous read of size 8.*\n" } */ +/* { dg-output " #0 write.*\n" } */ +/* { dg-output " #1 Thread1.*\n" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/free_race.c b/gcc/testsuite/c-c++-common/tsan/free_race.c new file mode 100644 index 0000000..362c92b --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/free_race.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include + +void __attribute__((noinline)) foo(int *mem) { + free(mem); +} + +void __attribute__((noinline)) bar(int *mem) { + mem[0] = 42; +} + +int main() { + int *mem =(int*)malloc (100); + foo(mem); + bar(mem); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: heap-use-after-free.*(\n|\r\n|\r)" } */ +/* { dg-output " Write of size 4 at.* by main thread:(\n|\r\n|\r)" } */ +/* { dg-output " #0 bar.*(\n|\r\n|\r)" } */ +/* { dg-output " #1 main.*(\n|\r\n|\r)" } */ +/* { dg-output " Previous write of size 8 at.* by main thread:(\n|\r\n|\r)" } */ +/* { dg-output " #0 free.*(\n|\r\n|\r)" } */ +/* { dg-output " #\(1|2\) foo.*(\n|\r\n|\r)" } */ +/* { dg-output " #\(2|3\) main.*(\n|\r\n|\r)" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/mutexset1.c b/gcc/testsuite/c-c++-common/tsan/mutexset1.c new file mode 100644 index 0000000..783f262 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/mutexset1.c @@ -0,0 +1,41 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include +#include + +int Global; +pthread_mutex_t mtx; + +void *Thread1(void *x) { + sleep(1); + pthread_mutex_lock(&mtx); + Global++; + pthread_mutex_unlock(&mtx); + return NULL; +} + +void *Thread2(void *x) { + Global--; + return NULL;/* { dg-output ".*" } */ + +} + +int main() { + pthread_mutex_init(&mtx, 0); + pthread_t t[2]; + pthread_create(&t[0], NULL, Thread1, NULL); + pthread_create(&t[1], NULL, Thread2, NULL); + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); + pthread_mutex_destroy(&mtx); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ +/* { dg-output " Read of size 4 at 0x\[0-9a-f\]+ by thread T1 \\(mutexes: write M\[0-9\]\\):.*" } */ +/* { dg-output " Previous write of size 4 at 0x\[0-9a-f\]+ by thread T2:.*" } */ +/* { dg-output " Mutex M\[0-9\] created at:.*" } */ +/* { dg-output " #0 pthread_mutex_init.*" } */ +/* { dg-output " #1 main (.*mutexset1.c|\\?{2}):\[0-9]+.*" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/race_on_barrier.c b/gcc/testsuite/c-c++-common/tsan/race_on_barrier.c new file mode 100644 index 0000000..407c712 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/race_on_barrier.c @@ -0,0 +1,33 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include +#include +#include + +pthread_barrier_t B; +int Global; + +void *Thread1(void *x) { + pthread_barrier_init(&B, 0, 2); + pthread_barrier_wait(&B); + return NULL; +} + +void *Thread2(void *x) { + sleep(1); + pthread_barrier_wait(&B); + return NULL; +} + +int main() { + pthread_t t; + pthread_create(&t, NULL, Thread1, NULL); + Thread2(0); + pthread_join(t, NULL); + pthread_barrier_destroy(&B); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/sleep_sync.c b/gcc/testsuite/c-c++-common/tsan/sleep_sync.c new file mode 100644 index 0000000..8203d54 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/sleep_sync.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include + +int X = 0; + +void MySleep() { + sleep(1); +} + +void *Thread(void *p) { + MySleep(); // Assume the main thread has done the write. + X = 42; + return 0; +} + +int main() { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + X = 43; + pthread_join(t, 0); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r).*} */ +/* { dg-output " As if synchronized via sleep:(\n|\r\n|\r)} */ +/* { dg-output " #0 sleep.*"*} */ +/* { dg-output " #1 MySleep.*"*} */ +/* { dg-output " #2 Thread.*"*} */ diff --git a/gcc/testsuite/c-c++-common/tsan/thread_leak.c b/gcc/testsuite/c-c++-common/tsan/thread_leak.c new file mode 100644 index 0000000..416ef77 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/thread_leak.c @@ -0,0 +1,18 @@ +/* { dg-do run } */ + +#include +#include + +void *Thread(void *x) { + return 0; +} + +int main() { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + pthread_join(t, 0); + printf("PASS\n"); + return 0; +} + +/* { dg-prune-output "WARNING: ThreadSanitizer: thread leak.*" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/thread_leak1.c b/gcc/testsuite/c-c++-common/tsan/thread_leak1.c new file mode 100644 index 0000000..18bcf2a --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/thread_leak1.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include + +void *Thread(void *x) { + return 0; +} + +int main() { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + sleep(1); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: thread leak.*(\n|\r\n|\r)" } */ +/* { dg-output "SUMMARY: ThreadSanitizer: thread leak.*main.*(\n|\r\n|\r)" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/thread_leak2.c b/gcc/testsuite/c-c++-common/tsan/thread_leak2.c new file mode 100644 index 0000000..12ac734 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/thread_leak2.c @@ -0,0 +1,23 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ +/* { dg-skip-if "" { *-*-* } { "-O3 -funroll-loops" "-O3 -funroll-all-loops" } { "" } } */ + +#include +#include + +void *Thread(void *x) { + return 0; +} + +int main() { + int i; + for (i = 0; i < 5; i++) { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + } + sleep(1); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: thread leak.*(\n|\r\n|\r)" } */ +/* { dg-output " And 4 more similar thread leaks.*" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/tiny_race.c b/gcc/testsuite/c-c++-common/tsan/tiny_race.c new file mode 100644 index 0000000..0356183 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/tiny_race.c @@ -0,0 +1,23 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include + +int Global; + +void *Thread1(void *x) { + sleep(1); + Global = 42; + return x; +} + +int main() { + pthread_t t; + pthread_create(&t, 0, Thread1, 0); + Global = 43; + pthread_join(t, 0); + return Global; +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/tls_race.c b/gcc/testsuite/c-c++-common/tsan/tls_race.c new file mode 100644 index 0000000..041e9af --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/tls_race.c @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include + +void *Thread(void *a) { + *(int*)a = 43; + return 0; +} + +int main() { + static __thread int Var = 42; + pthread_t t; + pthread_create(&t, 0, Thread, &Var); + Var = 43; + pthread_join(t, 0); +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r).*" } */ +/* { dg-output " Location is TLS of main thread.(\n|\r\n|\r).*" } */ diff --git a/gcc/testsuite/c-c++-common/tsan/write_in_reader_lock.c b/gcc/testsuite/c-c++-common/tsan/write_in_reader_lock.c new file mode 100644 index 0000000..c6a0bee --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/write_in_reader_lock.c @@ -0,0 +1,37 @@ +/* { dg-do run } */ +/* { dg-shouldfail "tsan" } */ + +#include +#include + +pthread_rwlock_t rwlock; +int GLOB; + +void *Thread1(void *p) { + (void)p; + pthread_rwlock_rdlock(&rwlock); + // Write under reader lock. + sleep(1); + GLOB++; + pthread_rwlock_unlock(&rwlock); + return 0; +} + +int main(int argc, char *argv[]) { + pthread_rwlock_init(&rwlock, NULL); + pthread_rwlock_rdlock(&rwlock); + pthread_t t; + pthread_create(&t, 0, Thread1, 0); + volatile int x = GLOB; + (void)x; + pthread_rwlock_unlock(&rwlock); + pthread_join(t, 0); + pthread_rwlock_destroy(&rwlock); + return 0; +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ +/* { dg-output " Write of size 4 at 0x\[0-9a-f\]+ by thread T1.*:(\n|\r\n|\r).*" } */ +/* { dg-output " #0 Thread1.*\(write_in_reader_lock.c|\\?{2}\):\[0-9\]+ .*" } */ +/* { dg-output " Previous read of size 4 at.* by main thread.*:(\n|\r\n|\r).*" } */ +/* { dg-output " #0 main.*\(write_in_reader_lock.c|\\?{2}\):\[0-9\]+.*" } */ diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index d107dfe..c90a7e6 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -54,6 +54,7 @@ set tests [prune $tests $srcdir/$subdir/guality/*] set tests [prune $tests $srcdir/$subdir/simulate-thread/*] set tests [prune $tests $srcdir/$subdir/asan/*] set tests [prune $tests $srcdir/$subdir/ubsan/*] +set tests [prune $tests $srcdir/$subdir/tsan/*] # Main loop. g++-dg-runtest $tests $DEFAULT_CXXFLAGS diff --git a/gcc/testsuite/g++.dg/tsan/tsan.exp b/gcc/testsuite/g++.dg/tsan/tsan.exp new file mode 100644 index 0000000..164a92e --- /dev/null +++ b/gcc/testsuite/g++.dg/tsan/tsan.exp @@ -0,0 +1,40 @@ +# Copyright (C) 2013 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 g++-dg.exp +load_lib tsan-dg.exp + +if ![check_effective_target_fthread_sanitizer] { + return +} + +# Initialize `dg'. +dg-init +if [tsan_init] { + +# Main loop. +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/tsan/*.c]] "" + +} + +# All done. +tsan_finish +dg-finish diff --git a/gcc/testsuite/gcc.dg/tsan/tsan.exp b/gcc/testsuite/gcc.dg/tsan/tsan.exp new file mode 100644 index 0000000..248cfb1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tsan/tsan.exp @@ -0,0 +1,40 @@ +# Copyright (C) 2013 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 tsan-dg.exp + +if ![check_effective_target_fthread_sanitizer] { + return +} + +# Initialize `dg'. +dg-init +if [tsan_init] { + +# Main loop. +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/tsan/*.c]] "" + +} + +# All done. +tsan_finish +dg-finish diff --git a/gcc/testsuite/lib/tsan-dg.exp b/gcc/testsuite/lib/tsan-dg.exp new file mode 100644 index 0000000..f39d8b5 --- /dev/null +++ b/gcc/testsuite/lib/tsan-dg.exp @@ -0,0 +1,114 @@ +# Copyright (C) 2013 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=thread is error-free for trivial +# code, 0 otherwise. + +proc check_effective_target_fthread_sanitizer {} { + return [check_no_compiler_messages faddress_sanitizer object { + void foo (void) { } + } "-fPIE -pie -fsanitize=thread"] +} + +# +# tsan_link_flags -- compute library path and flags to find libtsan. +# (originally from g++.exp) +# + +proc tsan_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/tsan/.libs/libtsan.a"] + || [file exists "${gccpath}/libsanitizer/tsan/.libs/libtsan.${shlib_ext}"] } { + append flags " -B${gccpath}/libsanitizer/tsan/ " + append flags " -L${gccpath}/libsanitizer/tsan/.libs " + append ld_library_path ":${gccpath}/libsanitizer/tsan/.libs" + } + } else { + global tool_root_dir + + set libtsan [lookfor_file ${tool_root_dir} libtsan] + if { $libtsan != "" } { + append flags "-L${libtsan} " + append ld_library_path ":${libtsan}" + } + } + + set_ld_library_path_env_vars + + return "$flags" +} + +# +# tsan_init -- called at the start of each subdir of tests +# + +proc tsan_init { args } { + global TEST_ALWAYS_FLAGS + global ALWAYS_CXXFLAGS + global TOOL_OPTIONS + global tsan_saved_TEST_ALWAYS_FLAGS + + set link_flags "" + if ![is_remote host] { + if [info exists TOOL_OPTIONS] { + set link_flags "[tsan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + } else { + set link_flags "[tsan_link_flags [get_multilibs]]" + } + } + + if [info exists TEST_ALWAYS_FLAGS] { + set tsan_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=-fPIE -pie -fsanitize=thread -g}" $ALWAYS_CXXFLAGS] + } else { + if [info exists TEST_ALWAYS_FLAGS] { + set TEST_ALWAYS_FLAGS "$link_flags -fPIE -pie -fsanitize=thread -g $TEST_ALWAYS_FLAGS" + } else { + set TEST_ALWAYS_FLAGS "$link_flags -fPIE -pie -fsanitize=thread -g" + } + } + if { $link_flags != "" } { + return 1 + } + return 0 +} + +# +# tsan_finish -- called at the start of each subdir of tests +# + +proc tsan_finish { args } { + global TEST_ALWAYS_FLAGS + global tsan_saved_TEST_ALWAYS_FLAGS + + if [info exists tsan_saved_TEST_ALWAYS_FLAGS] { + set TEST_ALWAYS_FLAGS $tsan_saved_TEST_ALWAYS_FLAGS + } else { + unset TEST_ALWAYS_FLAGS + } +}