From 4d3de70f0e1370df07aa85ff6a86bf82ed9f3b69 Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Fri, 24 Jun 2011 16:03:32 +0000 Subject: [PATCH] Add tests for displaying of locks held by threads in races. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11827 --- helgrind/tests/Makefile.am | 15 ++++ helgrind/tests/locked_vs_unlocked1.c | 50 +++++++++++++ .../tests/locked_vs_unlocked1_fwd.stderr.exp | 34 +++++++++ .../tests/locked_vs_unlocked1_fwd.stdout.exp | 0 helgrind/tests/locked_vs_unlocked1_fwd.vgtest | 2 + .../tests/locked_vs_unlocked1_rev.stderr.exp | 34 +++++++++ .../tests/locked_vs_unlocked1_rev.stdout.exp | 0 helgrind/tests/locked_vs_unlocked1_rev.vgtest | 3 + helgrind/tests/locked_vs_unlocked2.c | 73 +++++++++++++++++++ helgrind/tests/locked_vs_unlocked2.stderr.exp | 40 ++++++++++ helgrind/tests/locked_vs_unlocked2.stdout.exp | 0 helgrind/tests/locked_vs_unlocked2.vgtest | 2 + helgrind/tests/locked_vs_unlocked3.c | 62 ++++++++++++++++ helgrind/tests/locked_vs_unlocked3.stderr.exp | 32 ++++++++ helgrind/tests/locked_vs_unlocked3.stdout.exp | 0 helgrind/tests/locked_vs_unlocked3.vgtest | 2 + 16 files changed, 349 insertions(+) create mode 100644 helgrind/tests/locked_vs_unlocked1.c create mode 100644 helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp create mode 100644 helgrind/tests/locked_vs_unlocked1_fwd.stdout.exp create mode 100644 helgrind/tests/locked_vs_unlocked1_fwd.vgtest create mode 100644 helgrind/tests/locked_vs_unlocked1_rev.stderr.exp create mode 100644 helgrind/tests/locked_vs_unlocked1_rev.stdout.exp create mode 100644 helgrind/tests/locked_vs_unlocked1_rev.vgtest create mode 100644 helgrind/tests/locked_vs_unlocked2.c create mode 100644 helgrind/tests/locked_vs_unlocked2.stderr.exp create mode 100644 helgrind/tests/locked_vs_unlocked2.stdout.exp create mode 100644 helgrind/tests/locked_vs_unlocked2.vgtest create mode 100644 helgrind/tests/locked_vs_unlocked3.c create mode 100644 helgrind/tests/locked_vs_unlocked3.stderr.exp create mode 100644 helgrind/tests/locked_vs_unlocked3.stdout.exp create mode 100644 helgrind/tests/locked_vs_unlocked3.vgtest diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am index f06fd26740..76691b3594 100644 --- a/helgrind/tests/Makefile.am +++ b/helgrind/tests/Makefile.am @@ -21,6 +21,18 @@ EXTRA_DIST = \ hg05_race2.vgtest hg05_race2.stdout.exp hg05_race2.stderr.exp \ hg06_readshared.vgtest hg06_readshared.stdout.exp \ hg06_readshared.stderr.exp \ + locked_vs_unlocked1_fwd.vgtest \ + locked_vs_unlocked1_fwd.stderr.exp \ + locked_vs_unlocked1_fwd.stdout.exp \ + locked_vs_unlocked1_rev.vgtest \ + locked_vs_unlocked1_rev.stderr.exp \ + locked_vs_unlocked1_rev.stdout.exp \ + locked_vs_unlocked2.vgtest \ + locked_vs_unlocked2.stderr.exp \ + locked_vs_unlocked2.stdout.exp \ + locked_vs_unlocked3.vgtest \ + locked_vs_unlocked3.stderr.exp \ + locked_vs_unlocked3.stdout.exp \ pth_barrier1.vgtest pth_barrier1.stdout.exp pth_barrier1.stderr.exp \ pth_barrier2.vgtest pth_barrier2.stdout.exp pth_barrier2.stderr.exp \ pth_barrier3.vgtest pth_barrier3.stdout.exp pth_barrier3.stderr.exp \ @@ -84,6 +96,9 @@ check_PROGRAMS = \ hg04_race \ hg05_race2 \ hg06_readshared \ + locked_vs_unlocked1 \ + locked_vs_unlocked2 \ + locked_vs_unlocked3 \ tc01_simple_race \ tc02_simple_tls \ tc03_re_excl \ diff --git a/helgrind/tests/locked_vs_unlocked1.c b/helgrind/tests/locked_vs_unlocked1.c new file mode 100644 index 0000000000..96dc425480 --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked1.c @@ -0,0 +1,50 @@ + +#include +#include +#include +#include + +/* Test of the mechanism for showing all locks held by a thread -- one + thread has a lock, the other doesn't. Running w/ command line args + switches the has/has-not thread around, so as to test lockset + retention in both the history mechanism and the primary errors. */ + +pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; + +int x = 0; + +void* child_fn ( void* arg ) +{ + if (arg) pthread_mutex_lock(&mx); + x = 1; + if (arg) pthread_mutex_unlock(&mx); + return NULL; +} + +int main ( int argc, char** argv ) +{ + int sw = argc > 1; + pthread_t child1, child2; + + if (pthread_create(&child1, NULL, child_fn, (void*)(long)(sw ? 0 : 1))) { + perror("pthread_create1"); + exit(1); + } + sleep(1); /* ensure repeatable results */ + if (pthread_create(&child2, NULL, child_fn, (void*)(long)(sw ? 1 : 0))) { + perror("pthread_create1"); + exit(1); + } + + if (pthread_join(child1, NULL)) { + perror("pthread join1"); + exit(1); + } + + if (pthread_join(child2, NULL)) { + perror("pthread join2"); + exit(1); + } + + return 0; +} diff --git a/helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp b/helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp new file mode 100644 index 0000000000..a3677cacc6 --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp @@ -0,0 +1,34 @@ +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---------------------------------------------------------------- + +Lock at 0x........ was first observed + at 0x........: pthread_mutex_lock (hg_intercepts.c:...) + by 0x........: child_fn (locked_vs_unlocked1.c:18) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: none + at 0x........: child_fn (locked_vs_unlocked1.c:19) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous write of size 4 by thread #x +Locks held: 1, at address 0x........ + at 0x........: child_fn (locked_vs_unlocked1.c:19) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + diff --git a/helgrind/tests/locked_vs_unlocked1_fwd.stdout.exp b/helgrind/tests/locked_vs_unlocked1_fwd.stdout.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/helgrind/tests/locked_vs_unlocked1_fwd.vgtest b/helgrind/tests/locked_vs_unlocked1_fwd.vgtest new file mode 100644 index 0000000000..eced0bf16c --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked1_fwd.vgtest @@ -0,0 +1,2 @@ +prog: locked_vs_unlocked1 +vgopts: -q --num-callers=3 diff --git a/helgrind/tests/locked_vs_unlocked1_rev.stderr.exp b/helgrind/tests/locked_vs_unlocked1_rev.stderr.exp new file mode 100644 index 0000000000..caf7189bff --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked1_rev.stderr.exp @@ -0,0 +1,34 @@ +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---------------------------------------------------------------- + +Lock at 0x........ was first observed + at 0x........: pthread_mutex_lock (hg_intercepts.c:...) + by 0x........: child_fn (locked_vs_unlocked1.c:18) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: 1, at address 0x........ + at 0x........: child_fn (locked_vs_unlocked1.c:19) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous write of size 4 by thread #x +Locks held: none + at 0x........: child_fn (locked_vs_unlocked1.c:19) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + diff --git a/helgrind/tests/locked_vs_unlocked1_rev.stdout.exp b/helgrind/tests/locked_vs_unlocked1_rev.stdout.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/helgrind/tests/locked_vs_unlocked1_rev.vgtest b/helgrind/tests/locked_vs_unlocked1_rev.vgtest new file mode 100644 index 0000000000..1e32c8a40b --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked1_rev.vgtest @@ -0,0 +1,3 @@ +prog: locked_vs_unlocked1 +args: x +vgopts: -q --num-callers=3 diff --git a/helgrind/tests/locked_vs_unlocked2.c b/helgrind/tests/locked_vs_unlocked2.c new file mode 100644 index 0000000000..f95e5559bc --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked2.c @@ -0,0 +1,73 @@ + +#include +#include +#include +#include +#include + +/* Test of the mechanism for showing all locks held by a thread. Test + the case where the earlier thread held, at the time of the access, + some locks, at least one of which is deleted by the time the second + access (the race) happens. This causes problems for Helgrind's + error reporting mechanism in that it can no longer show the deleted + lock in the error message.x */ + +pthread_mutex_t mx1a; +pthread_mutex_t mx1b; +pthread_mutex_t mx2a; +pthread_mutex_t mx2b; + +int x = 0; + +void* child_fn1 ( void* arg ) +{ + int r; + // We are the first-accessing thread. Take and release two locks + // and then destroy one of them. + r= pthread_mutex_lock(&mx1a); assert(!r); + r= pthread_mutex_lock(&mx1b); assert(!r); + x = 1; + r= pthread_mutex_unlock(&mx1b); assert(!r); + r= pthread_mutex_unlock(&mx1a); assert(!r); + r= pthread_mutex_destroy(&mx1a); assert(!r); + sleep(1); + return NULL; +} + +void* child_fn2 ( void* arg ) +{ + int r; + // We are the second-accessing thread. Take and release + // our two locks, but don't otherwise mess with them. + sleep(1); + r= pthread_mutex_lock(&mx2a); assert(!r); + r= pthread_mutex_lock(&mx2b); assert(!r); + x = 1; + r= pthread_mutex_unlock(&mx2b); assert(!r); + r= pthread_mutex_unlock(&mx2a); assert(!r); + return NULL; +} + +int main ( int argc, char** argv ) +{ + pthread_t child1, child2; + int r; + + r= pthread_mutex_init(&mx1a, NULL); assert(!r); + r= pthread_mutex_init(&mx1b, NULL); assert(!r); + r= pthread_mutex_init(&mx2a, NULL); assert(!r); + r= pthread_mutex_init(&mx2b, NULL); assert(!r); + + r= pthread_create(&child2, NULL, child_fn2, NULL); assert(!r); + r= pthread_create(&child1, NULL, child_fn1, NULL); assert(!r); + + r= pthread_join(child1, NULL); assert(!r); + r= pthread_join(child2, NULL); assert(!r); + + // don't destroy mx1a; it's already destroyed. + r= pthread_mutex_destroy(&mx1b); assert(!r); + r= pthread_mutex_destroy(&mx2a); assert(!r); + r= pthread_mutex_destroy(&mx2b); assert(!r); + + return 0; +} diff --git a/helgrind/tests/locked_vs_unlocked2.stderr.exp b/helgrind/tests/locked_vs_unlocked2.stderr.exp new file mode 100644 index 0000000000..591f90ed44 --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked2.stderr.exp @@ -0,0 +1,40 @@ +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---------------------------------------------------------------- + +Lock at 0x........ was first observed + at 0x........: pthread_mutex_init (hg_intercepts.c:...) + by 0x........: main (locked_vs_unlocked2.c:58) + +Lock at 0x........ was first observed + at 0x........: pthread_mutex_init (hg_intercepts.c:...) + by 0x........: main (locked_vs_unlocked2.c:59) + +Lock at 0x........ was first observed + at 0x........: pthread_mutex_init (hg_intercepts.c:...) + by 0x........: main (locked_vs_unlocked2.c:57) + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: 2, at addresses 0x........ 0x........ + at 0x........: child_fn2 (locked_vs_unlocked2.c:45) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous write of size 4 by thread #x +Locks held: 2, at address 0x........ (and 1 that can't be shown) + at 0x........: child_fn1 (locked_vs_unlocked2.c:29) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + diff --git a/helgrind/tests/locked_vs_unlocked2.stdout.exp b/helgrind/tests/locked_vs_unlocked2.stdout.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/helgrind/tests/locked_vs_unlocked2.vgtest b/helgrind/tests/locked_vs_unlocked2.vgtest new file mode 100644 index 0000000000..3244156e5a --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked2.vgtest @@ -0,0 +1,2 @@ +prog: locked_vs_unlocked2 +vgopts: -q --num-callers=3 diff --git a/helgrind/tests/locked_vs_unlocked3.c b/helgrind/tests/locked_vs_unlocked3.c new file mode 100644 index 0000000000..77a0fe8e8b --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked3.c @@ -0,0 +1,62 @@ + +/* Needed for older glibcs (2.3 and older, at least) who don't + otherwise "know" about pthread_rwlock_anything or about + PTHREAD_MUTEX_RECURSIVE (amongst things). */ +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include + +/* Test of the mechanism for showing all locks held by a thread. This + is like locked_vs_unlocked.c, except that it uses a recursively + lockable lock, and one thread holds the lock more than once. Point + is to check that the lock showing mechanism shows the + lock-number-of-times-held count. */ + +pthread_mutex_t mx; + +int x = 0; + +void* child_fn1 ( void* arg ) +{ + int r; + r= pthread_mutex_lock(&mx); assert(!r); + r= pthread_mutex_lock(&mx); assert(!r); + x = 1; + r= pthread_mutex_unlock(&mx); assert(!r); + r= pthread_mutex_unlock(&mx); assert(!r); + sleep(1); + return NULL; +} + +void* child_fn2 ( void* arg ) +{ + sleep(1); + x = 1; + return NULL; +} + +int main ( int argc, char** argv ) +{ + int r; + pthread_t child1, child2; + pthread_mutexattr_t attr; + r = pthread_mutexattr_init( &attr ); + assert(!r); + r = pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); + assert(!r); + r= pthread_mutex_init(&mx, &attr); assert(!r); + + r= pthread_create(&child2, NULL, child_fn2, NULL); assert(!r); + r= pthread_create(&child1, NULL, child_fn1, NULL); assert(!r); + + r= pthread_join(child1, NULL); assert(!r); + r= pthread_join(child2, NULL); assert(!r); + + r= pthread_mutex_destroy(&mx); assert(!r); + + return 0; +} diff --git a/helgrind/tests/locked_vs_unlocked3.stderr.exp b/helgrind/tests/locked_vs_unlocked3.stderr.exp new file mode 100644 index 0000000000..d3fce52bcf --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked3.stderr.exp @@ -0,0 +1,32 @@ +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---Thread-Announcement------------------------------------------ + +Thread #x was created + at 0x........: clone (in /...libc...) + by 0x........: pthread_create@@GLIBC_2.2.5 (in /...libpthread...) + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + +---------------------------------------------------------------- + +Lock at 0x........ was first observed + at 0x........: pthread_mutex_init (hg_intercepts.c:...) + by 0x........: main (locked_vs_unlocked3.c:51) + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: none + at 0x........: child_fn2 (locked_vs_unlocked3.c:38) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous write of size 4 by thread #x +Locks held: 1, at address 0x........ + at 0x........: child_fn1 (locked_vs_unlocked3.c:28) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + diff --git a/helgrind/tests/locked_vs_unlocked3.stdout.exp b/helgrind/tests/locked_vs_unlocked3.stdout.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/helgrind/tests/locked_vs_unlocked3.vgtest b/helgrind/tests/locked_vs_unlocked3.vgtest new file mode 100644 index 0000000000..d97a197764 --- /dev/null +++ b/helgrind/tests/locked_vs_unlocked3.vgtest @@ -0,0 +1,2 @@ +prog: locked_vs_unlocked3 +vgopts: -q --num-callers=3 -- 2.47.2