1
0
mirror of https://github.com/ioacademy-jikim/debugging synced 2026-08-30 09:19:28 +00:00

first commit

This commit is contained in:
jikim
2015-12-13 22:34:58 +09:00
commit 0b589c7986
9455 changed files with 4350134 additions and 0 deletions
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
@@ -0,0 +1 @@
# dummy
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,221 @@
include $(top_srcdir)/Makefile.tool-tests.am
dist_noinst_SCRIPTS = filter_stderr \
filter_stderr_solaris \
filter_helgrind \
filter_xml
EXTRA_DIST = \
annotate_hbefore.vgtest annotate_hbefore.stdout.exp \
annotate_hbefore.stderr.exp \
annotate_rwlock.vgtest annotate_rwlock.stdout.exp \
annotate_rwlock.stderr.exp \
annotate_smart_pointer.vgtest annotate_smart_pointer.stdout.exp \
annotate_smart_pointer.stderr.exp \
cond_init_destroy.vgtest cond_init_destroy.stderr.exp \
cond_timedwait_invalid.vgtest cond_timedwait_invalid.stdout.exp \
cond_timedwait_invalid.stderr.exp \
cond_timedwait_test.vgtest cond_timedwait_test.stdout.exp \
cond_timedwait_test.stderr.exp \
bar_bad.vgtest bar_bad.stdout.exp bar_bad.stderr.exp \
bar_trivial.vgtest bar_trivial.stdout.exp bar_trivial.stderr.exp \
free_is_write.vgtest free_is_write.stdout.exp \
free_is_write.stderr.exp \
hg01_all_ok.vgtest hg01_all_ok.stdout.exp hg01_all_ok.stderr.exp \
hg02_deadlock.vgtest hg02_deadlock.stdout.exp hg02_deadlock.stderr.exp \
hg03_inherit.vgtest hg03_inherit.stdout.exp hg03_inherit.stderr.exp \
hg04_race.vgtest hg04_race.stdout.exp hg04_race.stderr.exp \
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 \
pth_destroy_cond.vgtest \
pth_destroy_cond.stdout.exp pth_destroy_cond.stderr.exp \
pth_cond_destroy_busy.vgtest pth_cond_destroy_busy.stderr.exp \
pth_cond_destroy_busy.stderr.exp-ppc64 \
pth_cond_destroy_busy.stderr.exp-solaris \
pth_spinlock.vgtest pth_spinlock.stdout.exp pth_spinlock.stderr.exp \
rwlock_race.vgtest rwlock_race.stdout.exp rwlock_race.stderr.exp \
rwlock_test.vgtest rwlock_test.stdout.exp rwlock_test.stderr.exp \
shmem_abits.vgtest shmem_abits.stdout.exp shmem_abits.stderr.exp \
stackteardown.vgtest stackteardown.stdout.exp stackteardown.stderr.exp \
t2t_laog.vgtest t2t_laog.stdout.exp t2t_laog.stderr.exp \
tc01_simple_race.vgtest tc01_simple_race.stdout.exp \
tc01_simple_race.stderr.exp \
tc02_simple_tls.vgtest tc02_simple_tls.stdout.exp \
tc02_simple_tls.stderr.exp \
tc03_re_excl.vgtest tc03_re_excl.stdout.exp \
tc03_re_excl.stderr.exp \
tc04_free_lock.vgtest tc04_free_lock.stdout.exp \
tc04_free_lock.stderr.exp \
tc05_simple_race.vgtest tc05_simple_race.stdout.exp \
tc05_simple_race.stderr.exp \
tc06_two_races.vgtest tc06_two_races.stdout.exp \
tc06_two_races.stderr.exp \
tc06_two_races_xml.vgtest tc06_two_races_xml.stdout.exp \
tc06_two_races_xml.stderr.exp \
tc07_hbl1.vgtest tc07_hbl1.stdout.exp tc07_hbl1.stderr.exp \
tc08_hbl2.vgtest tc08_hbl2.stdout.exp tc08_hbl2.stderr.exp \
tc09_bad_unlock.vgtest tc09_bad_unlock.stdout.exp \
tc09_bad_unlock.stderr.exp tc09_bad_unlock.stderr.exp-solaris \
tc10_rec_lock.vgtest tc10_rec_lock.stdout.exp tc10_rec_lock.stderr.exp \
tc11_XCHG.vgtest tc11_XCHG.stdout.exp tc11_XCHG.stderr.exp \
tc12_rwl_trivial.vgtest tc12_rwl_trivial.stdout.exp \
tc12_rwl_trivial.stderr.exp \
tc12_rwl_trivial.stderr.exp-darwin970 \
tc12_rwl_trivial.stderr.exp-solaris \
tc13_laog1.vgtest tc13_laog1.stdout.exp tc13_laog1.stderr.exp \
tc14_laog_dinphils.vgtest tc14_laog_dinphils.stdout.exp \
tc14_laog_dinphils.stderr.exp \
tc15_laog_lockdel.vgtest tc15_laog_lockdel.stdout.exp \
tc15_laog_lockdel.stderr.exp \
tc16_byterace.vgtest tc16_byterace.stdout.exp \
tc16_byterace.stderr.exp \
tc17_sembar.vgtest tc17_sembar.stdout.exp \
tc17_sembar.stderr.exp \
tc18_semabuse.vgtest tc18_semabuse.stdout.exp \
tc18_semabuse.stderr.exp \
tc18_semabuse.stderr.exp-linux-mips32 \
tc18_semabuse.stderr.exp-linux-mips32-b \
tc18_semabuse.stderr.exp-solaris \
tc19_shadowmem.vgtest tc19_shadowmem.stdout.exp \
tc19_shadowmem.stderr.exp tc19_shadowmem.stderr.exp-mips32 \
tc20_verifywrap.vgtest tc20_verifywrap.stdout.exp \
tc20_verifywrap.stderr.exp \
tc20_verifywrap.stderr.exp-glibc-2.18 \
tc20_verifywrap.stderr.exp-glibc-2.21 \
tc20_verifywrap.stderr.exp-mips32 \
tc20_verifywrap.stderr.exp-mips32-b \
tc20_verifywrap.stderr.exp-s390x \
tc20_verifywrap.stderr.exp-solaris \
tc21_pthonce.vgtest tc21_pthonce.stdout.exp tc21_pthonce.stderr.exp \
tc22_exit_w_lock.vgtest tc22_exit_w_lock.stdout.exp \
tc22_exit_w_lock.stderr.exp \
tc22_exit_w_lock.stderr.exp-kfail-x86 \
tc22_exit_w_lock.stderr.exp-solaris \
tc23_bogus_condwait.vgtest tc23_bogus_condwait.stdout.exp \
tc23_bogus_condwait.stderr.exp \
tc23_bogus_condwait.stderr.exp-mips32 \
tc24_nonzero_sem.vgtest tc24_nonzero_sem.stdout.exp \
tc24_nonzero_sem.stderr.exp \
tls_threads.vgtest tls_threads.stdout.exp \
tls_threads.stderr.exp
# Wrapper headers used by some check programs.
noinst_HEADERS = safe-pthread.h safe-semaphore.h
# XXX: tc18_semabuse uses operations that are unsupported on Darwin. It
# should be conditionally compiled like tc20_verifywrap is.
check_PROGRAMS = \
annotate_hbefore \
cond_init_destroy \
cond_timedwait_invalid \
cond_timedwait_test \
free_is_write \
hg01_all_ok \
hg02_deadlock \
hg03_inherit \
hg04_race \
hg05_race2 \
hg06_readshared \
locked_vs_unlocked1 \
locked_vs_unlocked2 \
locked_vs_unlocked3 \
pth_destroy_cond \
shmem_abits \
stackteardown \
t2t \
tc01_simple_race \
tc02_simple_tls \
tc03_re_excl \
tc04_free_lock \
tc05_simple_race \
tc06_two_races \
tc07_hbl1 \
tc08_hbl2 \
tc09_bad_unlock \
tc10_rec_lock \
tc11_XCHG \
tc12_rwl_trivial \
tc13_laog1 \
tc14_laog_dinphils \
tc15_laog_lockdel \
tc16_byterace \
tc17_sembar \
tc18_semabuse \
tc19_shadowmem \
tc21_pthonce \
tc23_bogus_condwait \
tc24_nonzero_sem \
tls_threads
# DDD: it seg faults, and then the Valgrind exit path hangs
# JRS 29 July 09: it craps out in the stack unwinder, in
#==13480== at 0xF00B81FF: ??? f00b8180 VG_(get_StackTrace_wrk)
#==13480== by 0xF00B83F8: ??? f00b8340 VG_(get_StackTrace)
#==13480== by 0xF009FE19: ??? f009fd70 record_ExeContext_wrk
#==13480== by 0xF009D92E: ??? f009d8c0 construct_error
#==13480== by 0xF009F001: ??? f009eef0 VG_(maybe_record_error)
#==13480== by 0xF0081F80: ??? f0081f00 HG_(record_error_misc)
#==13480== by 0xF0089C00: ??? f0089b80 evh__pre_thread_ll_exit
#==13480== by 0xF01111D1: ??? f0111070 run_a_thread_NORETURN
#==13480== by 0xF0111512: ??? f0111500 start_thread_NORETURN
# when the thread being unwound is at __bsdthread_terminate+0
#
# Like Tom says, the stack unwinder protection is bollocks.
# We should junk all previous schemes and simply get the
# stack unwinder to consult aspacem at each frame (cache-accelerated,
# of course) to check each page it visits is accessible.
#
if ! VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
check_PROGRAMS += \
tc22_exit_w_lock
endif
if VGCONF_PLATFORMS_INCLUDE_ARM_LINUX
annotate_hbefore_CFLAGS = $(AM_CFLAGS) -mcpu=cortex-a8
tc07_hbl1_CFLAGS = $(AM_CFLAGS) -mcpu=cortex-a8
tc08_hbl2_CFLAGS = $(AM_CFLAGS) -mcpu=cortex-a8
else
annotate_hbefore_CFLAGS = $(AM_CFLAGS)
tc07_hbl1_CFLAGS = $(AM_CFLAGS)
tc08_hbl2_CFLAGS = $(AM_CFLAGS)
endif
if HAVE_PTHREAD_BARRIER
check_PROGRAMS += bar_bad bar_trivial
endif
if HAVE_PTHREAD_MUTEX_TIMEDLOCK
check_PROGRAMS += tc20_verifywrap
endif
if HAVE_BUILTIN_ATOMIC
check_PROGRAMS += annotate_rwlock
endif
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
LDADD = -lpthread
if VGCONF_OS_IS_DARWIN
annotate_hbefore_CFLAGS = $(AM_CFLAGS) -mdynamic-no-pic
else
annotate_hbefore_CFLAGS = $(AM_CFLAGS)
endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,416 @@
/* Program which uses a happens-before edge to coordinate an access to
variable 'shared_var' between two threads. The h-b edge is created
by a custom (kludgesome!) mechanism and hence we need to use
ANNOTATES_HAPPEN_{BEFORE,AFTER} to explain to Helgrind what's going
on (else it reports a race). */
#include <pthread.h>
#include <stdio.h>
#include <assert.h>
#include "../../helgrind/helgrind.h"
/* Todo: move all this do_acasW guff into a support library. It's
useful for multiple tests, not just this one.
XXX: all the do_acasW routines assume the supplied address
is UWord (naturally) aligned. */
typedef unsigned long int UWord;
#if defined(VGA_ppc64be) || defined(VGA_ppc64le)
// ppc64
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord old, success;
/* Fetch the old value, and set the reservation */
__asm__ __volatile__ (
"ldarx %0, 0,%1" "\n" // rD,rA,rB
: /*out*/ "=b"(old)
: /*in*/ "b"(addr)
: /*trash*/ "memory","cc"
);
/* If the old value isn't as expected, we've had it */
if (old != expected) return 0;
/* otherwise try to stuff the new value in */
__asm__ __volatile__(
"stdcx. %2, 0,%1" "\n" // rS,rA,rB
"mfcr %0" "\n\t"
"srdi %0,%0,29" "\n\t"
"andi. %0,%0,1" "\n"
: /*out*/ "=b"(success)
: /*in*/ "b"(addr), "b"(nyu)
);
assert(success == 0 || success == 1);
return success;
}
#elif defined(VGA_ppc32)
// ppc32
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord old, success;
/* Fetch the old value, and set the reservation */
__asm__ __volatile__ (
"lwarx %0, 0,%1" "\n" // rD,rA,rB
: /*out*/ "=b"(old)
: /*in*/ "b"(addr)
: /*trash*/ "memory","cc"
);
/* If the old value isn't as expected, we've had it */
if (old != expected) return 0;
/* otherwise try to stuff the new value in */
__asm__ __volatile__(
"stwcx. %2, 0,%1" "\n" // rS,rA,rB
"mfcr %0" "\n\t"
"srwi %0,%0,29" "\n\t"
"andi. %0,%0,1" "\n"
: /*out*/ "=b"(success)
: /*in*/ "b"(addr), "b"(nyu)
);
assert(success == 0 || success == 1);
return success;
}
#elif defined(VGA_amd64)
// amd64
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord block[4] = { (UWord)addr, expected, nyu, 2 };
__asm__ __volatile__(
"movq 0(%%rsi), %%rdi" "\n\t" // addr
"movq 8(%%rsi), %%rax" "\n\t" // expected
"movq 16(%%rsi), %%rbx" "\n\t" // nyu
"xorq %%rcx,%%rcx" "\n\t"
"lock; cmpxchgq %%rbx,(%%rdi)" "\n\t"
"setz %%cl" "\n\t"
"movq %%rcx, 24(%%rsi)" "\n"
: /*out*/
: /*in*/ "S"(&block[0])
: /*trash*/"memory","cc","rdi","rax","rbx","rcx"
);
assert(block[3] == 0 || block[3] == 1);
return block[3] & 1;
}
#elif defined(VGA_x86)
// x86
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord block[4] = { (UWord)addr, expected, nyu, 2 };
__asm__ __volatile__(
"pushl %%ebx" "\n\t"
"movl 0(%%esi), %%edi" "\n\t" // addr
"movl 4(%%esi), %%eax" "\n\t" // expected
"movl 8(%%esi), %%ebx" "\n\t" // nyu
"xorl %%ecx,%%ecx" "\n\t"
"lock; cmpxchgl %%ebx,(%%edi)" "\n\t"
"setz %%cl" "\n\t"
"movl %%ecx, 12(%%esi)" "\n\t"
"popl %%ebx" "\n"
: /*out*/
: /*in*/ "S"(&block[0])
: /*trash*/"memory","cc","edi","eax","ecx"
);
assert(block[3] == 0 || block[3] == 1);
return block[3] & 1;
}
#elif defined(VGA_arm)
// arm
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord old, success;
UWord block[2] = { (UWord)addr, nyu };
/* Fetch the old value, and set the reservation */
__asm__ __volatile__ (
"ldrex %0, [%1]" "\n"
: /*out*/ "=r"(old)
: /*in*/ "r"(addr)
);
/* If the old value isn't as expected, we've had it */
if (old != expected) return 0;
/* otherwise try to stuff the new value in */
__asm__ __volatile__(
"ldr r4, [%1, #0]" "\n\t"
"ldr r5, [%1, #4]" "\n\t"
"strex r6, r5, [r4, #0]" "\n\t"
"eor %0, r6, #1" "\n\t"
: /*out*/ "=r"(success)
: /*in*/ "r"(&block[0])
: /*trash*/ "r4","r5","r6","memory"
);
assert(success == 0 || success == 1);
return success;
}
#elif defined(VGA_arm64)
// arm64
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord old, success;
UWord block[2] = { (UWord)addr, nyu };
/* Fetch the old value, and set the reservation */
__asm__ __volatile__ (
"ldxr %0, [%1]" "\n"
: /*out*/ "=r"(old)
: /*in*/ "r"(addr)
);
/* If the old value isn't as expected, we've had it */
if (old != expected) return 0;
/* otherwise try to stuff the new value in */
__asm__ __volatile__(
"ldr x4, [%1, #0]" "\n\t"
"ldr x5, [%1, #8]" "\n\t"
"stxr w6, x5, [x4, #0]" "\n\t"
"eor %0, x6, #1" "\n\t"
: /*out*/ "=r"(success)
: /*in*/ "r"(&block[0])
: /*trash*/ "x4","x5","x6","memory"
);
assert(success == 0 || success == 1);
return success;
}
#elif defined(VGA_s390x)
// s390x
/* return 1 if success, 0 if failure */
UWord do_acasW(UWord* addr, UWord expected, UWord nyu )
{
int cc;
__asm__ __volatile__ (
"csg %2,%3,%1\n\t"
"ipm %0\n\t"
"srl %0,28\n\t"
: /* out */ "=r" (cc)
: /* in */ "Q" (*addr), "d" (expected), "d" (nyu)
: "memory", "cc"
);
return cc == 0;
}
#elif defined(VGA_mips32)
// mips32
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord success;
UWord block[3] = { (UWord)addr, nyu, expected};
__asm__ __volatile__(
".set noreorder" "\n\t"
"lw $t0, 0(%1)" "\n\t"
"lw $t2, 8(%1)" "\n\t"
"lw $t3, 4(%1)" "\n\t"
"ll $t1, 0($t0)" "\n\t"
"bne $t1, $t2, exit_0" "\n\t"
"nop" "\n\t"
"sc $t3, 0($t0)" "\n\t"
"move %0, $t3" "\n\t"
"b exit" "\n\t"
"nop" "\n\t"
"exit_0:" "\n\t"
"move %0, $zero" "\n\t"
"exit:" "\n\t"
: /*out*/ "=r"(success)
: /*in*/ "r"(&block[0])
: /*trash*/ "t0", "t1", "t2", "t3", "memory"
);
assert(success == 0 || success == 1);
return success;
}
#elif defined(VGA_mips64)
// mips64
/* return 1 if success, 0 if failure */
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
{
UWord success;
UWord block[3] = { (UWord)addr, nyu, expected};
__asm__ __volatile__(
".set noreorder" "\n\t"
"ld $t0, 0(%1)" "\n\t"
"ld $t2, 16(%1)" "\n\t"
"ld $t3, 8(%1)" "\n\t"
"ll $t1, 0($t0)" "\n\t"
"bne $t1, $t2, exit_0" "\n\t"
"nop" "\n\t"
"sc $t3, 0($t0)" "\n\t"
"move %0, $t3" "\n\t"
"b exit" "\n\t"
"nop" "\n\t"
"exit_0:" "\n\t"
"move %0, $zero" "\n\t"
"exit:" "\n\t"
: /*out*/ "=r"(success)
: /*in*/ "r"(&block[0])
: /*trash*/ "t0", "t1", "t2", "t3", "memory"
);
assert(success == 0 || success == 1);
return success;
}
#elif defined(VGA_tilegx)
/* return 1 if success, 0 if failure */
UWord do_acasW(UWord* addr, UWord expected, UWord nyu )
{
/* Load the compare value into special register 0x2780 */
__insn_mtspr(0x2780, expected);
return __insn_cmpexch(addr, nyu);
}
#endif
void atomic_incW ( UWord* w )
{
while (1) {
UWord old = *w;
UWord nyu = old + 1;
UWord ok = do_acasW( w, old, nyu );
if (ok) break;
};
}
#if 0
#define NNN 1000000
void* thread_fn ( void* arg )
{
UWord* w = (UWord*)arg;
int i;
for (i = 0; i < NNN; i++)
atomic_incW( w );
return NULL;
}
int main ( void )
{
int r;
//ANNOTATE_HAPPENS_BEFORE(0);
//return 0;
UWord w = 0;
pthread_t t1, t2;
r= pthread_create( &t1, NULL, &thread_fn, (void*)&w ); assert(!r);
r= pthread_create( &t2, NULL, &thread_fn, (void*)&w ); assert(!r);
r= pthread_join( t1, NULL ); assert(!r);
r= pthread_join( t2, NULL ); assert(!r);
printf("result = %lu\n", w );
return 0;
}
#endif
int shared_var = 0; // is not raced upon
void delayXms ( int i )
{
struct timespec ts = { 0, 1 * 1000 * 1000 };
// We do the sleep in small pieces to have scheduling
// events ensuring a fair switch between threads, even
// without --fair-sched=yes. This is a.o. needed for
// running this test under an outer helgrind or an outer
// sgcheck.
while (i > 0) {
nanosleep(&ts, NULL);
i--;
}
}
void do_wait ( UWord* w )
{
UWord w0 = *w;
UWord volatile * wV = w;
while (*wV == w0)
delayXms(1); // small sleeps, ensuring context switches
ANNOTATE_HAPPENS_AFTER(w);
}
void do_signal ( UWord* w )
{
ANNOTATE_HAPPENS_BEFORE(w);
atomic_incW(w);
}
void* thread_fn1 ( void* arg )
{
UWord* w = (UWord*)arg;
delayXms(500); // ensure t2 gets to its wait first
shared_var = 1; // first access
do_signal(w); // cause h-b edge to second thread
delayXms(500);
return NULL;
}
void* thread_fn2 ( void* arg )
{
UWord* w = (UWord*)arg;
do_wait(w); // wait for h-b edge from first thread
shared_var = 2; // second access
delayXms(500);
return NULL;
}
int main ( void )
{
int r;
UWord w = 0;
pthread_t t1, t2;
r= pthread_create( &t1, NULL, &thread_fn1, (void*)&w ); assert(!r);
r= pthread_create( &t2, NULL, &thread_fn2, (void*)&w ); assert(!r);
r= pthread_join( t1, NULL ); assert(!r);
r= pthread_join( t2, NULL ); assert(!r);
return 0;
}
@@ -0,0 +1,2 @@
vgopts: -q --fair-sched=try
prog: annotate_hbefore
@@ -0,0 +1,176 @@
/* This program is a marginally modified copy of
drd/tests/annotate_rwlock.c,
which was originally written by Bart van Assche.
Unfortunately due to the need to #include helgrind.h instead of
drd.h, it can't be an exact copy.
*/
/**
* @file annotate_rwlock.c
*
* @brief Multithreaded test program that triggers various access patterns
* without triggering any race conditions using a reader-writer lock
* implemented via busy-waiting. Annotations are used to tell DRD
* which higher-level rwlock operations are being performed.
*/
#define _GNU_SOURCE 1
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h> /* usleep() */
#include "../../config.h"
#include "../../helgrind/helgrind.h"
#ifndef HAVE_BUILTIN_ATOMIC
#error Sorry, but this test program can only be compiled by a compiler that\
has built-in functions for atomic memory access.
#endif
typedef struct {
volatile int locked;
int writer_count;
int reader_count;
} rwlock_t;
static rwlock_t s_rwlock;
static int s_counter;
static void rwlock_init(rwlock_t* p)
{
// DRD_IGNORE_VAR(*p);
p->locked = 0;
p->writer_count = 0;
p->reader_count = 0;
ANNOTATE_RWLOCK_CREATE(p);
}
static void rwlock_destroy(rwlock_t* p)
{
ANNOTATE_RWLOCK_DESTROY(p);
assert(p->locked == 0);
assert(p->writer_count == 0);
assert(p->reader_count == 0);
}
static void rwlock_rdlock(rwlock_t* p)
{
while (1)
{
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
;
if (p->writer_count == 0)
break;
#ifdef __APPLE__
/* Darwin doesn't have an implementation of pthread_yield(). */
usleep(100 * 1000);
#else
sched_yield();
#endif
(void) __sync_fetch_and_sub(&p->locked, 1);
}
p->reader_count++;
assert(p->reader_count >= 0);
assert(p->writer_count >= 0);
assert(p->reader_count == 0 || p->writer_count == 0);
(void) __sync_fetch_and_sub(&p->locked, 1);
//ANNOTATE_READERLOCK_ACQUIRED(p);
ANNOTATE_RWLOCK_ACQUIRED(p, 0);
}
static void rwlock_wrlock(rwlock_t* p)
{
while (1)
{
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
;
if (p->reader_count == 0)
break;
#ifdef __APPLE__
/* Darwin doesn't have an implementation of pthread_yield(). */
usleep(100 * 1000);
#else
sched_yield();
#endif
(void) __sync_fetch_and_sub(&p->locked, 1);
}
p->writer_count++;
assert(p->reader_count >= 0);
assert(p->writer_count >= 0);
assert(p->reader_count == 0 || p->writer_count == 0);
(void) __sync_fetch_and_sub(&p->locked, 1);
// ANNOTATE_WRITERLOCK_ACQUIRED(p);
ANNOTATE_RWLOCK_ACQUIRED(p, 1);
}
static void rwlock_unlock(rwlock_t* p)
{
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
;
if (p->reader_count > 0)
{
p->reader_count--;
//ANNOTATE_READERLOCK_RELEASED(p);
ANNOTATE_RWLOCK_RELEASED(p, 0);
}
else
{
p->writer_count--;
//ANNOTATE_WRITERLOCK_RELEASED(p);
ANNOTATE_RWLOCK_RELEASED(p, 1);
}
assert(p->reader_count >= 0);
assert(p->writer_count >= 0);
assert(p->reader_count == 0 || p->writer_count == 0);
(void) __sync_fetch_and_sub(&p->locked, 1);
}
static void* thread_func(void* arg)
{
int i;
int sum = 0;
for (i = 0; i < 1000; i++)
{
rwlock_rdlock(&s_rwlock);
sum += s_counter;
rwlock_unlock(&s_rwlock);
rwlock_wrlock(&s_rwlock);
s_counter++;
rwlock_unlock(&s_rwlock);
}
return 0;
}
int main(int argc, char** argv)
{
const int thread_count = 10;
pthread_t tid[thread_count];
int i;
rwlock_init(&s_rwlock);
for (i = 0; i < thread_count; i++)
{
pthread_create(&tid[i], 0, thread_func, 0);
}
for (i = 0; i < thread_count; i++)
{
pthread_join(tid[i], 0);
}
rwlock_destroy(&s_rwlock);
fprintf(stderr, "Finished.\n");
return 0;
}
@@ -0,0 +1,122 @@
---Thread-Announcement------------------------------------------
Thread #x was created
...
by 0x........: pthread_create@* (hg_intercepts.c:...)
by 0x........: main (annotate_rwlock.c:164)
---Thread-Announcement------------------------------------------
Thread #x was created
...
by 0x........: pthread_create@* (hg_intercepts.c:...)
by 0x........: main (annotate_rwlock.c:164)
----------------------------------------------------------------
Possible data race during read of size 4 at 0x........ by thread #x
Locks held: none
at 0x........: rwlock_rdlock (annotate_rwlock.c:71)
by 0x........: thread_func (annotate_rwlock.c:144)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous write of size 4 by thread #x
Locks held: none
at 0x........: rwlock_wrlock (annotate_rwlock.c:106)
by 0x........: thread_func (annotate_rwlock.c:147)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
----------------------------------------------------------------
Possible data race during read of size 4 at 0x........ by thread #x
Locks held: none
at 0x........: rwlock_rdlock (annotate_rwlock.c:81)
by 0x........: thread_func (annotate_rwlock.c:144)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous write of size 4 by thread #x
Locks held: none
at 0x........: rwlock_rdlock (annotate_rwlock.c:81)
by 0x........: thread_func (annotate_rwlock.c:144)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
----------------------------------------------------------------
Possible data race during write of size 4 at 0x........ by thread #x
Locks held: none
at 0x........: rwlock_rdlock (annotate_rwlock.c:81)
by 0x........: thread_func (annotate_rwlock.c:144)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous read of size 4 by thread #x
Locks held: none
at 0x........: rwlock_unlock (annotate_rwlock.c:131)
by 0x........: thread_func (annotate_rwlock.c:149)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
----------------------------------------------------------------
Possible data race during write of size 4 at 0x........ by thread #x
Locks held: none
at 0x........: rwlock_unlock (annotate_rwlock.c:121)
by 0x........: thread_func (annotate_rwlock.c:146)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous read of size 4 by thread #x
Locks held: none
at 0x........: rwlock_unlock (annotate_rwlock.c:131)
by 0x........: thread_func (annotate_rwlock.c:149)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
----------------------------------------------------------------
Possible data race during write of size 4 at 0x........ by thread #x
Locks held: none
at 0x........: rwlock_wrlock (annotate_rwlock.c:106)
by 0x........: thread_func (annotate_rwlock.c:147)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous read of size 4 by thread #x
Locks held: none
at 0x........: rwlock_unlock (annotate_rwlock.c:132)
by 0x........: thread_func (annotate_rwlock.c:149)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
----------------------------------------------------------------
Lock at 0x........ was first observed
at 0x........: rwlock_init (annotate_rwlock.c:54)
by 0x........: main (annotate_rwlock.c:161)
Address 0x........ is 0 bytes inside data symbol "s_rwlock"
Possible data race during write of size 4 at 0x........ by thread #x
Locks held: 1, at address 0x........
at 0x........: rwlock_unlock (annotate_rwlock.c:127)
by 0x........: thread_func (annotate_rwlock.c:149)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous read of size 4 by thread #x
Locks held: none
at 0x........: rwlock_unlock (annotate_rwlock.c:132)
by 0x........: thread_func (annotate_rwlock.c:149)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
Finished.
@@ -0,0 +1,3 @@
prereq: test -e annotate_rwlock
vgopts: -q
prog: annotate_rwlock
@@ -0,0 +1,4 @@
Done.
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
@@ -0,0 +1,3 @@
prereq: test -e ../../drd/tests/annotate_smart_pointer
prog: ../../drd/tests/annotate_smart_pointer
args: 50 5
@@ -0,0 +1,89 @@
/* This program checks that Helgrind reports the five degenerate
uses of the barrier functions shown. */
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
void* child1 ( void* arg )
{
pthread_barrier_wait( (pthread_barrier_t*)arg );
return NULL;
}
int main ( void )
{
pthread_barrier_t *bar1, *bar2, *bar3, *bar4, *bar5;
pthread_t thr1, thr2;
int r;
/* possibly set up a watchdog timer thread here. */
/* initialise a barrier with a zero count */
fprintf(stderr, "\ninitialise a barrier with zero count\n");
bar1 = malloc(sizeof(pthread_barrier_t));
pthread_barrier_init(bar1, NULL, 0);
/* initialise a barrier twice */
fprintf(stderr, "\ninitialise a barrier twice\n");
bar2 = malloc(sizeof(pthread_barrier_t));
pthread_barrier_init(bar2, NULL, 1);
pthread_barrier_init(bar2, NULL, 1);
/* initialise a barrier which has threads waiting on it.
This isn't too simple. */
fprintf(stderr, "\ninitialise a barrier which has threads waiting on it\n");
bar3 = malloc(sizeof(pthread_barrier_t));
pthread_barrier_init(bar3, NULL, 2);
/* create a thread, whose only purpose is to block on the barrier */
pthread_create(&thr1, NULL, child1, (void*)bar3);
/* guarantee that it gets there first */
sleep(1);
/* and now reinitialise */
pthread_barrier_init(bar3, NULL, 3);
/* destroy a barrier that has threads waiting at it */
fprintf(stderr, "\ndestroy a barrier that has waiting threads\n");
/* once again, create a thread, whose only purpose is to block. */
bar4 = malloc(sizeof(pthread_barrier_t));
pthread_barrier_init(bar4, NULL, 2);
/* create a thread, whose only purpose is to block on the barrier */
pthread_create(&thr2, NULL, child1, (void*)bar4);
/* guarantee that it gets there first */
sleep(1);
/* and now destroy */
pthread_barrier_destroy(bar4);
/* destroy a barrier that was never initialised. This is a bit
tricky, in that we have to fill the barrier with bytes which
ensure that the pthread_barrier_destroy call doesn't hang for
some reason. Zero-fill seems to work ok on amd64-linux (glibc
2.8). */
fprintf(stderr, "\ndestroy a barrier that was never initialised\n");
bar5 = malloc(sizeof(pthread_barrier_t));
assert(bar5);
memset(bar5, 0, sizeof(*bar5));
pthread_barrier_destroy(bar5);
/* now we need to clean up the mess .. */
r= pthread_cancel(thr1); assert(!r);
r= pthread_cancel(thr2); assert(!r);
free(bar1); free(bar2); free(bar3); free(bar4); free(bar5);
return 0;
}
@@ -0,0 +1,64 @@
initialise a barrier with zero count
---Thread-Announcement------------------------------------------
Thread #x is the program's root thread
----------------------------------------------------------------
Thread #x: pthread_barrier_init: 'count' argument is zero
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:39)
----------------------------------------------------------------
Thread #x's call to pthread_barrier_init failed
with error code 22 (EINVAL: Invalid argument)
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:39)
initialise a barrier twice
----------------------------------------------------------------
Thread #x: pthread_barrier_init: barrier is already initialised
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:45)
initialise a barrier which has threads waiting on it
----------------------------------------------------------------
Thread #x: pthread_barrier_init: barrier is already initialised
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:57)
----------------------------------------------------------------
Thread #x: pthread_barrier_init: threads are waiting at barrier
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:57)
destroy a barrier that has waiting threads
----------------------------------------------------------------
Thread #x: pthread_barrier_destroy: threads are waiting at barrier
at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:69)
----------------------------------------------------------------
Thread #x's call to pthread_barrier_destroy failed
with error code 16 (EBUSY: Device or resource busy)
at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:69)
destroy a barrier that was never initialised
----------------------------------------------------------------
Thread #x: pthread_barrier_destroy: barrier was never initialised
at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
by 0x........: main (bar_bad.c:80)
@@ -0,0 +1,3 @@
prereq: test -e bar_bad
prog: bar_bad
vgopts: -q
@@ -0,0 +1,57 @@
/* This is the most trivial test I could think of that involves
barriers. If H fails to notice the pthread_barrier_wait call then
it will report a race. Correct behaviour is not to report a race
(there isn't one.) */
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
int x = 0;
pthread_barrier_t bar;
void* child_fn ( void* arg )
{
long r, n = (long)arg;
if (n == 1) x++;
r = pthread_barrier_wait(&bar);
assert(r == 0 || r == PTHREAD_BARRIER_SERIAL_THREAD);
if (n == 0) x++;
sleep(1); /* ensure both threads get to this point before
either exits. */
return NULL;
}
#define NTHR 2
int main ( void )
{
long i, r;
pthread_t thr[NTHR];
r = pthread_barrier_init(&bar, NULL, NTHR);
assert(!r);
for (i = 0; i < NTHR; i++) {
r = pthread_create(&thr[i], NULL, child_fn, (void*)i);
assert(!r);
}
for (i = 0; i < NTHR; i++) {
r = pthread_join(thr[i], NULL);
assert(!r);
}
r = pthread_barrier_destroy(&bar); assert(!r);
printf("x = %d\n", x);
return 0;
}
@@ -0,0 +1 @@
x = 2
@@ -0,0 +1,3 @@
prereq: test -e bar_trivial
prog: bar_trivial
vgopts: -q
@@ -0,0 +1,8 @@
#include <pthread.h>
int main(int argc, char *argv[])
{
pthread_cond_t c;
pthread_cond_init(& c, NULL);
pthread_cond_destroy(& c);
return 0;
}
@@ -0,0 +1,3 @@
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
@@ -0,0 +1 @@
prog: cond_init_destroy
@@ -0,0 +1,26 @@
#include <time.h>
#include <pthread.h>
#include <assert.h>
#include <errno.h>
int main()
{
struct timespec abstime;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
abstime.tv_sec = time(NULL) + 2;
abstime.tv_nsec = 0;
abstime.tv_nsec += 1000000000;
assert(pthread_mutex_lock(&mutex)==0);
assert(pthread_cond_timedwait(&cond, &mutex, &abstime)==EINVAL);
assert(pthread_mutex_unlock(&mutex)==0);
return 0;
}
@@ -0,0 +1,15 @@
---Thread-Announcement------------------------------------------
Thread #x is the program's root thread
----------------------------------------------------------------
Thread #x's call to pthread_cond_timedwait failed
with error code 22 (EINVAL: Invalid argument)
at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
by 0x........: main (cond_timedwait_invalid.c:22)
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
@@ -0,0 +1,2 @@
prog: cond_timedwait_invalid
@@ -0,0 +1,20 @@
#include <pthread.h>
#include <string.h>
int main() {
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// This time has most definitely passed already. (Epoch)
struct timespec now;
memset(&now, 0, sizeof(now));
pthread_mutex_lock(&mutex);
pthread_cond_timedwait(&cond, &mutex, &now);
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
@@ -0,0 +1,3 @@
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
@@ -0,0 +1 @@
prog: cond_timedwait_test
@@ -0,0 +1,67 @@
#!/usr/bin/env perl
use warnings;
use strict;
#---------------------------------------------------------------------
# A list of files specific to the tool at hand. Line numbers in
# these files will be removed from backtrace entries matching these files.
#---------------------------------------------------------------------
my @tool_files = ( "hg_intercepts.c", "vg_replace_malloc.c" );
sub massage_backtrace_line ($$$) {
my ($line, $tool_files, $cmdlin_files) = @_;
my ($string, $qstring);
# If LINE matches any of the file names passed on the command line
# (i.e. in CMDLIN_FILES) return LINE unmodified.
foreach $string (@$cmdlin_files) {
$qstring = quotemeta($string);
return $line if ($line =~ /$qstring/);
}
# If LINE matches any of the file names in TOOL_FILES remove the line
# number and return the so modified line.
foreach $string (@$tool_files) {
$qstring = quotemeta($string);
return $line if ($line =~ s/$qstring:[0-9]+/$string:.../m);
# Special case for functions whose line numbers have been removed in
# filter_stderr_basic. FIXME: filter_stderr_basic should not do that.
return $line if ($line =~ s/$qstring:\.\.\./$string:.../m);
}
# Did not match anything
$line =~ s/[\w]+.*/.../m;
return "$line";
}
#---------------------------------------------------------------------
# Process lines. Two categories
# (a) lines from back traces
# pass through those lines that contain file names we're interested in
# (b) everything else
# pass through as is
#---------------------------------------------------------------------
my $prev_line = "";
while (<STDIN>) {
my $line = $_;
chomp($line);
if ($line =~ /^\s+(at |by )/) { # lines in a back trace
$line = massage_backtrace_line($line, \@tool_files, \@ARGV);
if ($line =~ /\s+\.\.\./) {
print "$line\n" if ($prev_line !~ /\s+\.\.\./);
} else {
print "$line\n";
}
} else {
print "$line\n"; # everything else
}
$prev_line = $line
}
exit 0;
@@ -0,0 +1,55 @@
#! /bin/sh
dir=`dirname $0`
$dir/../../tests/filter_stderr_basic |
# Anonymise addresses
$dir/../../tests/filter_addresses |
# Perform Solaris-specific filtering.
if $dir/../../tests/os_test solaris; then
perl -p $dir/filter_stderr_solaris
else
cat
fi |
# get rid of the numbers in bits of text "Thread #n", "thread #n",
# "Thread n" and "thread n", "tid n"
# as these make some tests more scheduling sensitive -- those where
# there are multiple threads which play interchangeable roles.
sed \
-e "s/tid [0-9][0-9]*/tid #x/g" \
-e "s/hread #[0-9][0-9]*/hread #x/g" \
-e "s/hread [0-9][0-9]*/hread x/g" |
# Likewise for frame numbers, which depend on compilation.
sed -e "s/frame #[0-9][0-9]*/frame #x/g" | \
# Remove the message that more than hundred errors have been detected
# (consists of two lines) and also the empty line above it.
awk 'BEGIN{begin=1} {if ($0 == "More than 100 errors detected. Subsequent errors") { getline; getline; } else { if (begin) begin = 0; else print last_line; }; last_line = $0; } END { if (! begin) print last_line; }' |
# Merge sem_wait and sem_wait@*, as either could be used. Likewise for
# sem_post.
sed \
-e "s/sem_wait@\*/sem_wait/" \
-e "s/sem_post@\*/sem_post/" |
# Remove "Helgrind, ..." line and the following copyright line;
# also the standard postamble (does such a word exist?)
# And also remove pthread_create_WRK lines, as ppc64 stacktraces
# do not contain them (at least on gcc110/fedora18).
sed \
-e "/^Helgrind, a thread error detector/ , /./ d" \
-e "/^For counts of detected and suppressed errors, rerun with: -v$/d" \
-e "/^Use --history-level=approx or =none to gain increased speed, at$/d" \
-e "/^the cost of reduced accuracy of conflicting-access information$/d" \
-e "/pthread_create_WRK (hg_intercepts.c:/d" |
# Some arches return ENOSYS instead of EINVAL for undefined futex operations.
sed -e "s/with error code 38 (ENOSYS: Function not implemented)/with error code 22 (EINVAL: Invalid argument)/" |
$dir/../../helgrind/tests/filter_helgrind "$@"
exit 0
@@ -0,0 +1,33 @@
#!/usr/bin/perl
# Replace pthread_create with pthread_create@* which is expected on Linux
s/pthread_create \(hg_intercepts.c:/pthread_create@* \(hg_intercepts.c:/g;
# We need to remove stack frames containing redundant function
# names from libc, for example
# by 0x........: pthread_mutex_init (in /...libc...)
my $check = join "|", ('pthread_mutex_init', 'pthread_cond_wait', 'pthread_cond_timedwait');
s/^\s*by 0x........: (?:$check) \(in \/...libc...\)\s*//;
# We also need to replace Solaris threading and sychronization function
# names with POSIX ones for hg_intercepts.c stack frame:
# at 0x........: mutex_lock (hg_intercepts.c:1234)
# See also comments in hg_intercepts.c.
my %regex = (
'cond_broadcast' => 'pthread_cond_broadcast@*',
'cond_destroy' => 'pthread_cond_destroy@*',
'cond_signal' => 'pthread_cond_signal@*',
'cond_wait' => 'pthread_cond_wait@*',
'cond_timedwait' => 'pthread_cond_timedwait@*',
'mutex_destroy' => 'pthread_mutex_destroy',
'mutex_init' => 'pthread_mutex_init',
'mutex_lock' => 'pthread_mutex_lock',
'mutex_trylock' => 'pthread_mutex_trylock',
'mutex_unlock' => 'pthread_mutex_unlock',
'rwlock_init' => 'pthread_rwlock_init',
'rw_unlock' => 'pthread_rwlock_unlock'
);
my $check = join "|", keys %regex;
if (! /: pthread_/ && ! /WRK/) {
s/($check)(.*hg_intercepts.c)/$regex{$1}$2/g;
}
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env perl
#---------------------------------------------------------------------
# Quick and dirty program to filter helgrind's XML output.
#
# The script works line-by-line and is generally unaware of XML structure
# and does not bother with issues of well-formedness.
#
# Consists of two parts
# (1) Global match and replace (see PATTERNS below)
# (2) Removal of stack frames
# Stack frames whose associated file name does not match any name in
# TOOL_FILES or in the list of files given on the command line
# will be discarded. For a sequence of one or more discarded frames
# a line <frame>...</frame> will be inserted.
#
#---------------------------------------------------------------------
use warnings;
use strict;
#---------------------------------------------------------------------
# A list of files specific to the tool at hand. Line numbers in
# these files will be removed from stack frames matching these files.
#---------------------------------------------------------------------
my @tool_files = ( "hg_intercepts.c", "vg_replace_malloc.c" );
# List of patterns and replacement strings.
# Each pattern must identify a substring which will be replaced.
my %patterns = (
"<pid>(.*)</pid>" => "...",
"<ppid>(.*)</ppid>" => "...",
"<time>(.*)</time>" => "...",
"<obj>(.*)</obj>" => "...",
"<dir>(.*)</dir>" => "...",
"<exe>(.*)</exe>" => "...",
"<tid>(.*)</tid>" => "...",
"<unique>(.*)</unique>" => "...",
"thread #([0-9]+)" => "x",
"0x([0-9a-zA-Z]+)" => "........",
"Using Valgrind-([^\\s]*)" => "X.Y.X",
"Copyright \\(C\\) ([0-9]{4}-[0-9]{4}).*" => "XXXX-YYYY",
'<fn>pthread_.*(@\*)</fn>' => ""
);
# List of XML sections to be ignored.
my %ignore_sections = (
"<errorcounts>" => "</errorcounts>",
"<suppcounts>" => "</suppcounts>"
);
# If FILE matches any of the FILES return 1
sub file_matches ($$) {
my ($file, $files) = @_;
my ($string, $qstring);
foreach $string (@$files) {
$qstring = quotemeta($string);
return 1 if ($file =~ /$qstring/);
}
return 0;
}
my $frame_buf = "";
my ($file, $lineno, $in_frame, $keep_frame, $num_discarded, $ignore_line);
$in_frame = $keep_frame = $num_discarded = $ignore_line = 0;
line:
while (<STDIN>) {
my $line = $_;
chomp($line);
# Check whether we're ignoring this piece of XML..
if ($ignore_line) {
foreach my $tag (keys %ignore_sections) {
if ($line =~ $ignore_sections{$tag}) {
print "$tag...$ignore_sections{$tag}\n";
$ignore_line = 0;
next line;
}
}
} else {
foreach my $tag (keys %ignore_sections) {
if ($line =~ $tag) {
$ignore_line = 1;
}
}
}
next if ($ignore_line);
# OK. This line is not to be ignored.
# Massage line by applying PATTERNS.
foreach my $key (keys %patterns) {
if ($line =~ $key) {
my $matched = quotemeta($1);
$line =~ s/$matched/$patterns{$key}/g;
}
}
# Handle frames
if ($in_frame) {
if ($line =~ /<\/frame>/) {
$frame_buf .= "$line\n";
# The end of a frame
if ($keep_frame) {
# First: If there were any preceding frames that were discarded
# print <frame>...</frame>
if ($num_discarded) {
print " <frame>...</frame>\n";
$num_discarded = 0;
}
# Secondly: Write out the frame itself
print "$frame_buf";
} else {
# We don't want to write this frame
++$num_discarded;
}
$in_frame = $keep_frame = 0;
$file = "";
} elsif ($line =~ /<file>(.*)<\/file>/) {
$frame_buf .= "$line\n";
$file = $1;
if (file_matches($file, \@tool_files) ||
file_matches($file, \@ARGV)) {
$keep_frame = 1;
}
} elsif ($line =~ /<line>(.*)<\/line>/) {
# This code assumes that <file> always precedes <line>
$lineno = $1;
if (file_matches($file, \@tool_files)) {
$line =~ s/$1/.../;
}
$frame_buf .= "$line\n";
} else {
$frame_buf .= "$line\n";
}
} else {
# not within frame
if ($line =~ /<\/stack>/) {
print " <frame>...</frame>\n" if ($num_discarded);
$num_discarded = 0;
}
if ($line =~ /<frame>/) {
$in_frame = 1;
$frame_buf = "$line\n";
} else {
print "$line\n";
}
}
}
exit 0;
@@ -0,0 +1,42 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
static char* s_mem;
/* wait a second, so as to guarantee that the parent access
the malloc'd area, then free it. */
static void* thread_func(void* arg)
{
sleep(1);
free(s_mem);
return NULL;
}
int main(int argc, char** argv)
{
pthread_t tid;
int quiet;
fprintf(stderr, "Start.\n");
quiet = argc > 1;
s_mem = malloc(10);
if (0 && !quiet)
fprintf(stderr, "Pointer to allocated memory: %p\n", s_mem);
assert(s_mem);
pthread_create(&tid, NULL, thread_func, NULL);
/* Write, which isn't coordinated with the free ==> a race
should be reported. */
char c = s_mem[5];
__asm__ __volatile__("" : : "r"((long)c) );
pthread_join(tid, NULL);
fprintf(stderr, "Done.\n");
return 0;
}
@@ -0,0 +1,30 @@
Start.
---Thread-Announcement------------------------------------------
Thread #x was created
...
by 0x........: pthread_create@* (hg_intercepts.c:...)
by 0x........: main (free_is_write.c:32)
---Thread-Announcement------------------------------------------
Thread #x is the program's root thread
----------------------------------------------------------------
Possible data race during write of size 1 at 0x........ by thread #x
Locks held: none
at 0x........: free (vg_replace_malloc.c:...)
by 0x........: thread_func (free_is_write.c:15)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous read of size 1 by thread #x
Locks held: none
at 0x........: main (free_is_write.c:36)
Address 0x........ is 5 bytes inside an unallocated block of size 16 in arena "client"
Done.
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
@@ -0,0 +1,2 @@
prog: free_is_write
vgopts: --free-is-write=yes
@@ -0,0 +1,48 @@
/* All OK */
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER;
static int shared = 0;
static char *ptr;
static void breakme(void)
{
if (shared == 1)
memset (ptr, 0x55, 1000);
}
static void *th(void *v)
{
pthread_mutex_lock(&mx);
shared++;
if (shared == 1) {
ptr = malloc (1008);
breakme();
}
if (shared == 2) {
free (ptr);
breakme();
}
pthread_mutex_unlock(&mx);
return 0;
}
int main()
{
pthread_t a, b;
pthread_mutex_lock(&mx);
pthread_mutex_unlock(&mx);
pthread_create(&a, NULL, th, NULL);
pthread_create(&b, NULL, th, NULL);
pthread_join(a, NULL);
pthread_join(b, NULL);
return 0;
}
@@ -0,0 +1,3 @@
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
@@ -0,0 +1 @@
prog: hg01_all_ok
@@ -0,0 +1,43 @@
/* Simple possible deadlock */
#include <pthread.h>
static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
static void *t1(void *v)
{
pthread_mutex_lock(&m1);
pthread_mutex_lock(&m2);
pthread_mutex_unlock(&m1);
pthread_mutex_unlock(&m2);
return 0;
}
static void *t2(void *v)
{
pthread_mutex_lock(&m2);
pthread_mutex_lock(&m1);
pthread_mutex_unlock(&m1);
pthread_mutex_unlock(&m2);
return 0;
}
int main()
{
pthread_t a, b;
/* prevent spurious messages from the dynamic linker */
pthread_mutex_lock(&m1);
pthread_mutex_unlock(&m1);
pthread_create(&a, NULL, t1, NULL);
pthread_create(&b, NULL, t2, NULL);
pthread_join(a, NULL);
pthread_join(b, NULL);
return 0;
}
@@ -0,0 +1,57 @@
---Thread-Announcement------------------------------------------
Thread #x was created
...
by 0x........: pthread_create@* (hg_intercepts.c:...)
by 0x........: main (hg02_deadlock.c:36)
----------------------------------------------------------------
Thread #x: lock order "0x........ before 0x........" violated
Observed (incorrect) order is: acquisition of lock at 0x........
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
by 0x........: t2 (hg02_deadlock.c:19)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
followed by a later acquisition of lock at 0x........
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
by 0x........: t2 (hg02_deadlock.c:20)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Required order was established by acquisition of lock at 0x........
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
by 0x........: t1 (hg02_deadlock.c:9)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
followed by a later acquisition of lock at 0x........
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
by 0x........: t1 (hg02_deadlock.c:10)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Lock at 0x........ was first observed
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
by 0x........: main (hg02_deadlock.c:32)
Address 0x........ is 0 bytes inside data symbol "m1"
Lock at 0x........ was first observed
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
by 0x........: t1 (hg02_deadlock.c:10)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
Address 0x........ is 0 bytes inside data symbol "m2"
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
@@ -0,0 +1 @@
prog: hg02_deadlock
@@ -0,0 +1,67 @@
/* I don't think this is a very good test .. all this
sleepery is highly confusing. */
/* test child thread inheriting data */
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
static volatile int shared[2];
static void *t1(void *v)
{
volatile int *ip = (int *)v;
if (0) printf("ta W\n");
*ip += 44;
*ip *= 2;
sleep(1);
return 0;
}
static void *t2(void *v)
{
volatile int *ip = (int *)v;
sleep(2);
if (0) printf("tb W\n");
*ip += 88;
*ip *= 3;
sleep(1);
return 0;
}
int main(void)
{
pthread_t a, b;
volatile int ret = 0;
sleep(0);
shared[0] = 22;
shared[1] = 77;
pthread_create(&a, NULL, t1, (void *)&shared[0]);
// a steals shared[0] from root thread, so is excl(a)
pthread_create(&b, NULL, t2, (void *)&shared[1]);
// b steals shared[1] from root thread, so is excl(b)
pthread_join(a, NULL);
// b's stuff (shared[1]) still belongs to b, so is excl(b)
// ret is excl(root), and shared[0] is re-acquired as excl(root)
// since a joined to root
if (0) printf("r R1\n");
ret += shared[0]; /* no error - a is finished */
// but shared[1] is excl(b); hence we're reading excl(b)
// without a lock and without a dependency edge
if (0) printf("r R2\n");
ret += shared[1]; /* expect error - b has not finished,
so we can't touch shared[1] yet */
pthread_join(b, NULL);
return ret;
}
@@ -0,0 +1,28 @@
---Thread-Announcement------------------------------------------
Thread #x was created
...
by 0x........: pthread_create@* (hg_intercepts.c:...)
by 0x........: main (hg03_inherit.c:46)
---Thread-Announcement------------------------------------------
Thread #x is the program's root thread
----------------------------------------------------------------
Possible data race during write of size 4 at 0x........ by thread #x
Locks held: none
at 0x........: t2 (hg03_inherit.c:28)
by 0x........: mythread_wrapper (hg_intercepts.c:...)
...
This conflicts with a previous read of size 4 by thread #x
Locks held: none
at 0x........: main (hg03_inherit.c:60)
Location 0x........ is 0 bytes inside shared[1],
a global variable declared at hg03_inherit.c:11
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
@@ -0,0 +1,2 @@
prog: hg03_inherit
vgopts: --read-var-info=yes
@@ -0,0 +1,27 @@
/* A simple race */
#include <pthread.h>
#include <unistd.h>
static int shared;
static void *th(void *v)
{
shared++;
return 0;
}
int main()
{
pthread_t a, b;
pthread_create(&a, NULL, th, NULL);
sleep(1); /* force ordering */
pthread_create(&b, NULL, th, NULL);
pthread_join(a, NULL);
pthread_join(b, NULL);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More