drd_main.c \
drd_malloc_wrappers.c \
drd_mutex.c \
+ drd_rwlock.c \
drd_segment.c \
drd_semaphore.c \
drd_suppression.c \
drd_error.h \
drd_malloc_wrappers.h \
drd_mutex.h \
+ drd_rwlock.h \
drd_segment.h \
drd_semaphore.h \
drd_suppression.h \
all possible data races or deadlocks via source reading. This is why
tools for detecting data races and deadlocks at runtime are essential.
-The de facto standard library for multithreading on Unix systems is
-the POSIX threads library, also known as pthreads. The exp-drd tool
-has been developed for multithreaded software that uses the POSIX
-threads library.
+The de facto standard library for multithreading with the C and C++
+programming languages on Unix systems is the POSIX threads library,
+also known as pthreads. The exp-drd tool has been developed for
+multithreaded software that uses the POSIX threads library.
Data Races
between real-time threads is the use of preallocated fixed size
message queueus, and to lock any data needed by any real-time thread
in memory (mlock()). Avoid mutexes with priority inheritance -- see
-also [Yodaiken 2004] for more information.
+also [Yodaiken 2004] for more information. Lock-free data structures
+like circular buffers are well suited for real-time software.
+
+
+Linux and POSIX Threads
+-----------------------
+
+There exist two implementations of the POSIX threads API for
+Linux. These implementations are called LinuxThreads and
+NPTL. LinuxThreads was historically the first POSIX threads
+implementation for Linux. LinuxThreads was compliant to most but not
+all POSIX threads specifications. That is why a new threading library
+for Linux was developed, called the NPTL (Native POSIX Threads
+Library). Most Linux distributions switched from LinuxThreads to NPTL
+around 2004. DRD only supports the NPTL. See also [Shukla 2006] for
+more information.
How to use DRD
http://iacoma.cs.uiuc.edu/iacoma-papers/asid06.pdf
http://portal.acm.org/citation.cfm?id=1181309.1181315
+[Shukla 2006]
+ Vikram Shukla
+ NPTL -- A rundown of the key differences for developers who need to port
+ July 31, 2006.
+ http://www-128.ibm.com/developerworks/linux/library/l-threading.html?ca=dgr-lnxw07LinuxThreadsAndNPTL
+
[Müehlenfeld 2007]
Arndt Müehlenfeld, Franz Wotawa.
Fault Detection in Multi-threaded C++ Server Applications.
ClientCondvar = 2,
ClientSemaphore = 3,
ClientBarrier = 4,
+ ClientRwlock = 5,
} ObjType;
struct any
Addr a2;
ObjType type;
void (*cleanup)(union drd_clientobj*);
- Word count; // Participant count in a barrier wait.
- Word pre_iteration; // pthread_barrier_wait() call count modulo two.
- Word post_iteration; // pthread_barrier_wait() call count modulo two.
- Word pre_waiters_left; // number of waiters left for a complete barrier.
- Word post_waiters_left; // number of waiters left for a complete barrier.
- OSet* oset; // Thread-specific barrier information.
+ Word count; // Participant count in a barrier wait.
+ Word pre_iteration; // pthread_barrier_wait() call count modulo two.
+ Word post_iteration; // pthread_barrier_wait() call count modulo two.
+ Word pre_waiters_left; // number of waiters left for a complete barrier.
+ Word post_waiters_left; // number of waiters left for a complete barrier.
+ OSet* oset; // Thread-specific barrier information.
+};
+
+struct rwlock_info
+{
+ Addr a1;
+ Addr a2;
+ ObjType type;
+ void (*cleanup)(union drd_clientobj*);
+ OSet* thread_info;
};
typedef union drd_clientobj
struct cond_info cond;
struct semaphore_info semaphore;
struct barrier_info barrier;
+ struct rwlock_info rwlock;
} DrdClientobj;
#include "drd_suppression.h" // drd_start_suppression()
#include "drd_thread.h"
#include "drd_track.h"
+#include "drd_rwlock.h"
#include "priv_drd_clientreq.h"
#include "pub_tool_basics.h" // Bool
#include "pub_tool_libcassert.h"
break;
case VG_USERREQ__PRE_RWLOCK_INIT:
+ rwlock_pre_init(arg[1], arg[2]);
break;
case VG_USERREQ__POST_RWLOCK_DESTROY:
+ rwlock_post_destroy(arg[1]);
break;
case VG_USERREQ__PRE_RWLOCK_RDLOCK:
+ rwlock_pre_rdlock(arg[1], arg[2]);
break;
case VG_USERREQ__POST_RWLOCK_RDLOCK:
+ rwlock_post_rdlock(arg[1], arg[2]);
break;
case VG_USERREQ__PRE_RWLOCK_WRLOCK:
+ rwlock_pre_wrlock(arg[1], arg[2]);
break;
case VG_USERREQ__POST_RWLOCK_WRLOCK:
+ rwlock_post_wrlock(arg[1], arg[2]);
break;
- case VG_USERREQ__POST_RWLOCK_UNLOCK:
+ case VG_USERREQ__PRE_RWLOCK_UNLOCK:
+ rwlock_pre_unlock(arg[1]);
break;
default:
VG_USERREQ__POST_RWLOCK_WRLOCK,
/* args: Addr rwlock, Bool took_lock */
/* To notify the drd tool of a pthread_rwlock_unlock call. */
- VG_USERREQ__POST_RWLOCK_UNLOCK,
+ VG_USERREQ__PRE_RWLOCK_UNLOCK,
/* args: Addr rwlock, Bool unlocked */
};
MutexErrInfo* p = (MutexErrInfo*)(VG_(get_error_extra)(e));
tl_assert(p);
VG_(message)(Vg_UserMsg,
- "%s: address 0x%lx, recursion count %d, owner %d.",
+ "%s: mutex 0x%lx, recursion count %d, owner %d.",
VG_(get_error_string)(e),
p->mutex,
p->recursion_count,
case CondErr: {
CondErrInfo* cdei =(CondErrInfo*)(VG_(get_error_extra)(e));
VG_(message)(Vg_UserMsg,
- "cond 0x%lx: %s",
+ "%s: cond 0x%lx",
cdei->cond,
VG_(get_error_string)(e));
VG_(pp_ExeContext)(VG_(get_error_where)(e));
SemaphoreErrInfo* sei =(SemaphoreErrInfo*)(VG_(get_error_extra)(e));
tl_assert(sei);
VG_(message)(Vg_UserMsg,
- "%s 0x%lx",
+ "%s: semaphore 0x%lx",
VG_(get_error_string)(e),
sei->semaphore);
VG_(pp_ExeContext)(VG_(get_error_where)(e));
VG_(pp_ExeContext)(VG_(get_error_where)(e));
break;
}
+ case RwlockErr: {
+ RwlockErrInfo* p = (RwlockErrInfo*)(VG_(get_error_extra)(e));
+ tl_assert(p);
+ VG_(message)(Vg_UserMsg,
+ "%s: rwlock 0x%lx.",
+ VG_(get_error_string)(e),
+ p->rwlock);
+ VG_(pp_ExeContext)(VG_(get_error_where)(e));
+ break;
+ }
case GenericErr: {
//GenericErrInfo* gei =(GenericErrInfo*)(VG_(get_error_extra)(e));
VG_(message)(Vg_UserMsg, "%s", VG_(get_error_string)(e));
return sizeof(SemaphoreErrInfo);
case BarrierErr:
return sizeof(BarrierErrInfo);
+ case RwlockErr:
+ return sizeof(RwlockErrInfo);
case GenericErr:
return sizeof(GenericErrInfo);
default:
{
switch (VG_(get_error_kind)(e))
{
- case DataRaceErr: return "ConflictingAccess";
- case MutexErr: return "MutexErr";
- case CondRaceErr: return "CondRaceErr";
+ case DataRaceErr: return "DataRaceErr";
+ case MutexErr: return "MutexErr";
+ case CondErr: return "CondErr";
+ case CondRaceErr: return "CondRaceErr";
+ case CondDestrErr: return "CondDestrErr";
+ case SemaphoreErr: return "SemaphoreErr";
+ case BarrierErr: return "BarrierErr";
+ case RwlockErr: return "RwlockErr";
+ case GenericErr: return "GenericErr";
default:
tl_assert(0);
}
CondDestrErr = 5,
SemaphoreErr = 6,
BarrierErr = 7,
- GenericErr = 8,
+ RwlockErr = 8,
+ GenericErr = 9,
} DrdErrorKind;
/* The classification of a faulting address. */
Addr barrier;
} BarrierErrInfo;
+typedef struct {
+ Addr rwlock;
+} RwlockErrInfo;
+
typedef struct {
} GenericErrInfo;
if (getpid() != vg_main_thread_pid)
{
- fprintf(stderr,
- "Detected the linuxthreads threading library.\n"
- "Sorry, but DRD does not support linuxthreads.\n"
- "Please try to run DRD on a system with NPTL instead.\n"
- "Giving up.\n");
+ if (getenv("LD_ASSUME_KERNEL"))
+ {
+ fprintf(stderr,
+"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
+"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
+"after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
+ );
+ }
+ else
+ {
+ fprintf(stderr,
+"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
+"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
+"after having upgraded to a newer version of your Linux distribution.\n"
+"Giving up.\n"
+ );
+ }
abort();
}
OrigFn fn;
VALGRIND_GET_ORIG_FN(fn);
CALL_FN_W_W(ret, fn, rwlock);
- VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_UNLOCK,
+ VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
rwlock, ret == 0, 0, 0, 0);
return ret;
}
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),
- "Invalid mutex",
+ "Not a mutex",
&GEI);
return 0;
}
VG_(maybe_record_error)(VG_(get_running_tid)(),
GenericErr,
VG_(get_IP)(VG_(get_running_tid)()),
- "Invalid mutex",
+ "Not a mutex",
&GEI);
return;
}
* Note: this function must be called after pthread_mutex_lock() has been
* called, or a race condition is triggered !
*/
-int mutex_post_lock(const Addr mutex, const Bool took_lock)
+void mutex_post_lock(const Addr mutex, const Bool took_lock)
{
const DrdThreadId drd_tid = thread_get_running_tid();
struct mutex_info* p;
p ? p->owner : VG_INVALID_THREADID);
}
- if (p == 0)
- {
- return 0;
- }
-
- if (! took_lock)
- return p->recursion_count;
+ if (! p || ! took_lock)
+ return;
if (p->recursion_count == 0)
{
thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
thread_new_segment(drd_tid);
}
-
- return p->recursion_count;
}
/**
* @param tid ThreadId of the thread calling pthread_mutex_unlock().
* @param vc Pointer to the current vector clock of thread tid.
*/
-int mutex_unlock(const Addr mutex, const MutexT mutex_type)
+void mutex_unlock(const Addr mutex, const MutexT mutex_type)
{
const DrdThreadId drd_tid = thread_get_running_tid();
const ThreadId vg_tid = VG_(get_running_tid)();
const VectorClock* const vc = thread_get_vc(drd_tid);
struct mutex_info* const p = mutex_get(mutex);
- if (s_trace_mutex && p != 0)
+ if (s_trace_mutex)
{
VG_(message)(Vg_UserMsg,
"[%d/%d] mutex_unlock %s 0x%lx rc %d",
vg_tid,
drd_tid,
- mutex_get_typename(p),
+ p ? mutex_get_typename(p) : "?",
mutex,
- p->recursion_count,
- p->owner);
- }
-
- if (mutex_type == mutex_type_invalid_mutex)
- {
- GenericErrInfo GEI;
- VG_(maybe_record_error)(VG_(get_running_tid)(),
- GenericErr,
- VG_(get_IP)(VG_(get_running_tid)()),
- "Invalid mutex",
- &GEI);
- return 0;
+ p ? p->recursion_count : 0,
+ p ? p->owner : 0);
}
- if (p == 0)
+ if (p == 0 || mutex_type == mutex_type_invalid_mutex)
{
GenericErrInfo GEI;
VG_(maybe_record_error)(vg_tid,
VG_(get_IP)(vg_tid),
"Not a mutex",
&GEI);
- return 0;
+ return;
}
if (p->owner == DRD_INVALID_THREADID)
VG_(get_IP)(vg_tid),
"Mutex not locked",
&MEI);
- return 0;
+ return;
}
tl_assert(p);
tl_assert(p->mutex_type == mutex_type);
tl_assert(p->owner != DRD_INVALID_THREADID);
- if (p->owner != drd_tid)
+ if (p->owner != drd_tid || p->recursion_count <= 0)
{
MutexErrInfo MEI = { p->a1, p->recursion_count, p->owner };
VG_(maybe_record_error)(vg_tid,
MutexErr,
VG_(get_IP)(vg_tid),
- "Mutex not unlocked by owner thread",
+ "Mutex not locked by calling thread",
&MEI);
+ return;
}
+ tl_assert(p->recursion_count > 0);
p->recursion_count--;
- if (p->recursion_count < 0)
- {
- MutexErrInfo MEI
- = { p->a1, p->recursion_count, p->owner };
- VG_(maybe_record_error)(vg_tid,
- MutexErr,
- VG_(get_IP)(vg_tid),
- "Attempt to unlock a mutex that is not locked",
- &MEI);
- p->recursion_count = 0;
- }
+ tl_assert(p->recursion_count >= 0);
if (p->recursion_count == 0)
{
thread_new_segment(drd_tid);
}
- return p->recursion_count;
}
const char* mutex_get_typename(struct mutex_info* const p)
// Mutex state information: owner thread and recursion count.
-#ifndef __MUTEX_H
-#define __MUTEX_H
+#ifndef __DRD_MUTEX_H
+#define __DRD_MUTEX_H
#include "drd_clientreq.h" // MutexT
struct mutex_info* mutex_get(const Addr mutex);
void mutex_pre_lock(const Addr mutex, const SizeT size,
const MutexT mutex_type);
-int mutex_post_lock(const Addr mutex, const Bool took_lock);
-int mutex_unlock(const Addr mutex, const MutexT mutex_type);
+void mutex_post_lock(const Addr mutex, const Bool took_lock);
+void mutex_unlock(const Addr mutex, const MutexT mutex_type);
const char* mutex_get_typename(struct mutex_info* const p);
const char* mutex_type_name(const MutexT mt);
Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid);
ULong get_mutex_lock_count(void);
-#endif /* __MUTEX_H */
+#endif /* __DRD_MUTEX_H */
--- /dev/null
+/*
+ This file is part of drd, a data race detector.
+
+ Copyright (C) 2006-2008 Bart Van Assche
+ bart.vanassche@gmail.com
+
+ 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 2 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+
+#include "drd_clientobj.h"
+#include "drd_error.h"
+#include "drd_rwlock.h"
+#include "priv_drd_clientreq.h"
+#include "pub_tool_errormgr.h" // VG_(maybe_record_error)()
+#include "pub_tool_libcassert.h" // tl_assert()
+#include "pub_tool_libcprint.h" // VG_(message)()
+#include "pub_tool_machine.h" // VG_(get_IP)()
+#include "pub_tool_mallocfree.h" // VG_(malloc)(), VG_(free)()
+#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
+
+
+// Type definitions.
+
+struct rwlock_thread_info
+{
+ UWord tid; // DrdThreadId.
+ UInt reader_nesting_count;
+ UInt writer_nesting_count;
+ VectorClock vc; // Vector clock associated with last unlock by this thread.
+};
+
+
+// Local functions.
+
+static void rwlock_cleanup(struct rwlock_info* p);
+
+
+// Local variables.
+
+static Bool s_trace_rwlock;
+
+
+// Function definitions.
+
+void rwlock_set_trace(const Bool trace_rwlock)
+{
+ tl_assert(!! trace_rwlock == trace_rwlock);
+ s_trace_rwlock = trace_rwlock;
+}
+
+static Bool rwlock_is_rdlocked(struct rwlock_info* p)
+{
+ struct rwlock_thread_info* q;
+
+ VG_(OSetGen_ResetIter)(p->thread_info);
+ for ( ; (q = VG_(OSetGen_Next)(p->thread_info)); q++)
+ {
+ return q->reader_nesting_count > 0;
+ }
+ return False;
+}
+
+static Bool rwlock_is_wrlocked(struct rwlock_info* p)
+{
+ struct rwlock_thread_info* q;
+
+ VG_(OSetGen_ResetIter)(p->thread_info);
+ for ( ; (q = VG_(OSetGen_Next)(p->thread_info)); q++)
+ {
+ return q->writer_nesting_count > 0;
+ }
+ return False;
+}
+
+static Bool rwlock_is_locked(struct rwlock_info* p)
+{
+ return rwlock_is_rdlocked(p) || rwlock_is_wrlocked(p);
+}
+
+static Bool rwlock_is_rdlocked_by(struct rwlock_info* p, const DrdThreadId tid)
+{
+ const UWord uword_tid = tid;
+ struct rwlock_thread_info* q;
+
+ q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
+ return q && q->reader_nesting_count > 0;
+}
+
+static Bool rwlock_is_wrlocked_by(struct rwlock_info* p, const DrdThreadId tid)
+{
+ const UWord uword_tid = tid;
+ struct rwlock_thread_info* q;
+
+ q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
+ return q && q->writer_nesting_count > 0;
+}
+
+static Bool rwlock_is_locked_by(struct rwlock_info* p, const DrdThreadId tid)
+{
+ return rwlock_is_rdlocked_by(p, tid) || rwlock_is_wrlocked_by(p, tid);
+}
+
+static
+struct rwlock_thread_info* lookup_or_insert_node(OSet* oset, const UWord tid)
+{
+ struct rwlock_thread_info* q;
+
+ q = VG_(OSetGen_Lookup)(oset, &tid);
+ if (q == 0)
+ {
+ q = VG_(OSetGen_AllocNode)(oset, sizeof(*q));
+ q->tid = tid;
+ q->reader_nesting_count = 0;
+ q->writer_nesting_count = 0;
+ vc_init(&q->vc, 0, 0);
+ VG_(OSetGen_Insert)(oset, q);
+ }
+ tl_assert(q);
+ return q;
+}
+
+static void rwlock_combine_other_vc(struct rwlock_info* const p,
+ const DrdThreadId tid)
+{
+ struct rwlock_thread_info* q;
+
+ VG_(OSetGen_ResetIter)(p->thread_info);
+ for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
+ {
+ if (q->tid != tid)
+ {
+ thread_combine_vc2(tid, &q->vc);
+ }
+ }
+}
+
+static
+void rwlock_initialize(struct rwlock_info* const p,
+ const Addr rwlock,
+ const SizeT size)
+{
+ tl_assert(rwlock != 0);
+ tl_assert(size > 0);
+ tl_assert(p->a1 == rwlock);
+ tl_assert(p->a2 == rwlock + size);
+ tl_assert(p->type == ClientRwlock);
+
+ p->cleanup = (void(*)(DrdClientobj*))&rwlock_cleanup;
+ p->thread_info = VG_(OSetGen_Create)(0, 0, VG_(malloc), VG_(free));
+}
+
+/** Deallocate the memory that was allocated by rwlock_initialize(). */
+static void rwlock_cleanup(struct rwlock_info* p)
+{
+ struct rwlock_thread_info* q;
+
+ tl_assert(p);
+
+ if (s_trace_rwlock)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d/%d] rwlock_destroy 0x%lx",
+ VG_(get_running_tid)(),
+ thread_get_running_tid(),
+ p->a1);
+ }
+
+ if (rwlock_is_locked(p))
+ {
+ RwlockErrInfo REI = { p->a1 };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ RwlockErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Destroying locked rwlock",
+ &REI);
+ }
+
+ VG_(OSetGen_ResetIter)(p->thread_info);
+ for ( ; (q = VG_(OSetGen_Next)(p->thread_info)); q++)
+ {
+ vc_cleanup(&q->vc);
+ }
+ VG_(OSetGen_Destroy)(p->thread_info);
+}
+
+static
+struct rwlock_info*
+rwlock_get_or_allocate(const Addr rwlock, const SizeT size)
+{
+ struct rwlock_info* p;
+
+ tl_assert(offsetof(DrdClientobj, rwlock) == 0);
+ p = &clientobj_get(rwlock, ClientRwlock)->rwlock;
+ if (p)
+ {
+ tl_assert(p->a2 - p->a1 == size);
+ return p;
+ }
+
+ if (clientobj_present(rwlock, rwlock + size))
+ {
+ GenericErrInfo GEI;
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Not a reader-writer lock",
+ &GEI);
+ return 0;
+ }
+
+ p = &clientobj_add(rwlock, rwlock + size, ClientRwlock)->rwlock;
+ rwlock_initialize(p, rwlock, size);
+ return p;
+}
+
+static struct rwlock_info* rwlock_get(const Addr rwlock)
+{
+ tl_assert(offsetof(DrdClientobj, rwlock) == 0);
+ return &clientobj_get(rwlock, ClientRwlock)->rwlock;
+}
+
+/** Called before pthread_rwlock_init(). */
+struct rwlock_info*
+rwlock_pre_init(const Addr rwlock, const SizeT size)
+{
+ struct rwlock_info* p;
+
+ if (s_trace_rwlock)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d/%d] rwlock_init %s 0x%lx",
+ VG_(get_running_tid)(),
+ thread_get_running_tid(),
+ rwlock);
+ }
+
+ p = rwlock_get(rwlock);
+
+ if (p)
+ {
+ const ThreadId vg_tid = VG_(get_running_tid)();
+ RwlockErrInfo REI
+ = { p->a1 };
+ VG_(maybe_record_error)(vg_tid,
+ RwlockErr,
+ VG_(get_IP)(vg_tid),
+ "Reader-writer lock reinitialization",
+ &REI);
+ return p;
+ }
+
+ p = rwlock_get_or_allocate(rwlock, size);
+
+ return p;
+}
+
+/** Called after pthread_rwlock_destroy(). */
+void rwlock_post_destroy(const Addr rwlock)
+{
+ struct rwlock_info* p;
+
+ p = rwlock_get(rwlock);
+ if (p == 0)
+ {
+ GenericErrInfo GEI;
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ GenericErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Not a reader-writer lock",
+ &GEI);
+ return;
+ }
+
+ clientobj_remove(rwlock, ClientRwlock);
+}
+
+/** Called before pthread_rwlock_rdlock() is invoked. If a data structure for
+ * the client-side object was not yet created, do this now. Also check whether
+ * an attempt is made to lock recursively a synchronization object that must
+ * not be locked recursively.
+ */
+void rwlock_pre_rdlock(const Addr rwlock, const SizeT size)
+{
+ struct rwlock_info* p;
+
+ p = rwlock_get_or_allocate(rwlock, size);
+
+ tl_assert(p);
+
+ if (s_trace_rwlock)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d/%d] pre_rwlock_rdlock 0x%lx",
+ VG_(get_running_tid)(),
+ thread_get_running_tid(),
+ rwlock);
+ }
+
+ if (rwlock_is_wrlocked_by(p, thread_get_running_tid()))
+ {
+ VG_(message)(Vg_UserMsg,
+ "reader-writer lock 0x%lx is already locked for"
+ " writing by calling thread",
+ p->a1);
+ }
+}
+
+/**
+ * Update rwlock_info state when locking the pthread_rwlock_t mutex.
+ * Note: this function must be called after pthread_rwlock_rdlock() has been
+ * called, or a race condition is triggered !
+ */
+void rwlock_post_rdlock(const Addr rwlock, const Bool took_lock)
+{
+ const DrdThreadId drd_tid = thread_get_running_tid();
+ struct rwlock_info* p;
+ struct rwlock_thread_info* q;
+
+ p = rwlock_get(rwlock);
+
+ if (s_trace_rwlock)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d/%d] post_rwlock_rdlock 0x%lx",
+ VG_(get_running_tid)(),
+ drd_tid,
+ rwlock);
+ }
+
+ if (! p || ! took_lock)
+ return;
+
+ tl_assert(! rwlock_is_wrlocked(p));
+
+ q = lookup_or_insert_node(p->thread_info, drd_tid);
+ if (++q->reader_nesting_count == 1)
+ {
+ rwlock_combine_other_vc(p, drd_tid);
+ thread_new_segment(drd_tid);
+ }
+}
+
+/** Called before pthread_rwlock_wrlock() is invoked. If a data structure for
+ * the client-side object was not yet created, do this now. Also check whether
+ * an attempt is made to lock recursively a synchronization object that must
+ * not be locked recursively.
+ */
+void rwlock_pre_wrlock(const Addr rwlock, const SizeT size)
+{
+ struct rwlock_info* p;
+
+ p = rwlock_get(rwlock);
+
+ if (s_trace_rwlock)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d/%d] pre_rwlock_wrlock 0x%lx",
+ VG_(get_running_tid)(),
+ thread_get_running_tid(),
+ rwlock);
+ }
+
+ if (p == 0)
+ {
+ p = rwlock_get_or_allocate(rwlock, size);
+ }
+
+ tl_assert(p);
+
+ if (rwlock_is_wrlocked_by(p, thread_get_running_tid()))
+ {
+ RwlockErrInfo REI = { p->a1 };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ RwlockErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Recursive writer locking not allowed",
+ &REI);
+ }
+}
+
+/**
+ * Update rwlock_info state when locking the pthread_rwlock_t rwlock.
+ * Note: this function must be called after pthread_rwlock_wrlock() has been
+ * called, or a race condition is triggered !
+ */
+void rwlock_post_wrlock(const Addr rwlock, const Bool took_lock)
+{
+ const DrdThreadId drd_tid = thread_get_running_tid();
+ struct rwlock_info* p;
+ struct rwlock_thread_info* q;
+
+ p = rwlock_get(rwlock);
+
+ if (s_trace_rwlock)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d/%d] post_rwlock_wrlock 0x%lx",
+ VG_(get_running_tid)(),
+ drd_tid,
+ rwlock);
+ }
+
+ if (! p || ! took_lock)
+ return;
+
+ q = lookup_or_insert_node(p->thread_info, thread_get_running_tid());
+ tl_assert(q->writer_nesting_count == 0);
+ q->writer_nesting_count++;
+ tl_assert(q->writer_nesting_count == 1);
+ rwlock_combine_other_vc(p, drd_tid);
+ thread_new_segment(drd_tid);
+}
+
+/**
+ * Update rwlock_info state when unlocking the pthread_rwlock_t rwlock.
+ * Note: this function must be called before pthread_rwlock_unlock() is called,
+ * or a race condition is triggered !
+ * @return New value of the rwlock recursion count.
+ * @param rwlock Pointer to pthread_rwlock_t data structure in the client space.
+ * @param tid ThreadId of the thread calling pthread_rwlock_unlock().
+ * @param vc Pointer to the current vector clock of thread tid.
+ */
+void rwlock_pre_unlock(const Addr rwlock)
+{
+ const DrdThreadId drd_tid = thread_get_running_tid();
+ const ThreadId vg_tid = VG_(get_running_tid)();
+ const VectorClock* const vc = thread_get_vc(drd_tid);
+ struct rwlock_info* const p = rwlock_get(rwlock);
+ struct rwlock_thread_info* q;
+
+ if (s_trace_rwlock && p != 0)
+ {
+ VG_(message)(Vg_UserMsg,
+ "[%d/%d] rwlock_unlock 0x%lx",
+ vg_tid,
+ drd_tid,
+ rwlock);
+ }
+
+ if (p == 0 || ! rwlock_is_locked_by(p, drd_tid))
+ {
+ RwlockErrInfo REI = { p->a1 };
+ VG_(maybe_record_error)(vg_tid,
+ RwlockErr,
+ VG_(get_IP)(vg_tid),
+ "Reader-writer lock not locked by calling thread",
+ &REI);
+ return;
+ }
+ tl_assert(p);
+ q = lookup_or_insert_node(p->thread_info, drd_tid);
+ tl_assert(q);
+ if (q->reader_nesting_count > 0)
+ q->reader_nesting_count--;
+ else if (q->writer_nesting_count > 0)
+ q->writer_nesting_count--;
+ else
+ tl_assert(False);
+
+ if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
+ {
+ /* This pthread_rwlock_unlock() call really unlocks the rwlock. Save the */
+ /* current vector clock of the thread such that it is available when */
+ /* this rwlock is locked again. */
+ vc_assign(&q->vc, vc);
+
+ thread_new_segment(drd_tid);
+ }
+}
+
+/**
+ * Call this function when thread tid stops to exist, such that the
+ * "last owner" field can be cleared if it still refers to that thread.
+ */
+void rwlock_thread_delete(const DrdThreadId tid)
+{
+ struct rwlock_info* p;
+
+ clientobj_resetiter();
+ for ( ; (p = &clientobj_next(ClientRwlock)->rwlock) != 0; )
+ {
+ struct rwlock_thread_info* q;
+ if (rwlock_is_locked_by(p, tid))
+ {
+ RwlockErrInfo REI = { p->a1 };
+ VG_(maybe_record_error)(VG_(get_running_tid)(),
+ RwlockErr,
+ VG_(get_IP)(VG_(get_running_tid)()),
+ "Reader-writer lock still locked at thread exit",
+ &REI);
+ q = lookup_or_insert_node(p->thread_info, tid);
+ q->reader_nesting_count = 0;
+ q->writer_nesting_count = 0;
+ }
+ }
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 2
+ * End:
+ */
--- /dev/null
+/*
+ This file is part of drd, a data race detector.
+
+ Copyright (C) 2006-2008 Bart Van Assche
+ bart.vanassche@gmail.com
+
+ 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 2 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+
+// Reader-writer lock state information.
+
+
+#ifndef __DRD_RWLOCK_H
+#define __DRD_RWLOCK_H
+
+
+#include "drd_clientobj.h" // struct rwlock_info
+#include "drd_thread.h" // DrdThreadId
+#include "drd_vc.h"
+#include "pub_tool_basics.h" // Addr, SizeT
+
+
+struct rwlock_info;
+
+
+void rwlock_set_trace(const Bool trace_rwlock);
+struct rwlock_info* rwlock_pre_init(const Addr rwlock, const SizeT size);
+void rwlock_post_destroy(const Addr rwlock);
+void rwlock_pre_rdlock(const Addr rwlock, const SizeT size);
+void rwlock_post_rdlock(const Addr rwlock, const Bool took_lock);
+void rwlock_pre_wrlock(const Addr rwlock, const SizeT size);
+void rwlock_post_wrlock(const Addr rwlock, const Bool took_lock);
+void rwlock_pre_unlock(const Addr rwlock);
+void rwlock_thread_delete(const DrdThreadId tid);
+
+
+#endif /* __DRD_RWLOCK_H */
EXTRA_DIST = $(noinst_SCRIPTS) \
fp_race.vgtest \
fp_race.stdout.exp fp_race.stderr.exp \
- fp_race.stderr.exp2 \
fp_race2.vgtest \
fp_race2.stdout.exp fp_race2.stderr.exp \
hg01_all_ok.vgtest \
hg02_deadlock.stderr.exp \
hg03_inherit.vgtest \
hg03_inherit.stderr.exp \
- hg03_inherit.stderr.exp2 \
hg04_race.vgtest \
hg04_race.stderr.exp \
- hg04_race.stderr.exp2 \
hg05_race2.vgtest \
hg05_race2.stderr.exp \
hg06_readshared.vgtest \
pth_detached2.vgtest \
pth_detached2.stdout.exp pth_detached2.stderr.exp \
recursive_mutex.vgtest recursive_mutex.stderr.exp \
- sem_as_mutex.vgtest \
- sem_as_mutex.stderr.exp sem_as_mutex.stderr.exp2 \
- sem_as_mutex2.vgtest \
- sem_as_mutex2.stderr.exp \
+ sem_as_mutex.vgtest sem_as_mutex.stderr.exp \
+ sem_as_mutex2.vgtest sem_as_mutex2.stderr.exp \
tc01_simple_race.vgtest \
tc01_simple_race.stderr.exp \
- tc01_simple_race.stderr.exp2 \
tc02_simple_tls.vgtest \
tc02_simple_tls.stderr.exp \
tc03_re_excl.vgtest \
tc10_rec_lock.stderr.exp \
tc11_XCHG.vgtest \
tc11_XCHG.stderr.exp tc11_XCHG.stdout.exp \
- tc11_XCHG.stderr.exp2 \
tc12_rwl_trivial.vgtest \
tc12_rwl_trivial.stderr.exp \
tc13_laog1.vgtest \
tc15_laog_lockdel.stderr.exp \
tc16_byterace.vgtest \
tc16_byterace.stderr.exp \
- tc16_byterace.stderr.exp2 \
tc17_sembar.vgtest \
tc17_sembar.stderr.exp \
tc18_semabuse.vgtest \
tc18_semabuse.stderr.exp \
tc19_shadowmem.vgtest \
tc19_shadowmem.stderr.exp \
- tc20_verifywrap.vgtest \
- tc20_verifywrap.stderr.exp tc20_verifywrap.stderr.exp2 \
- tc20_verifywrap2.vgtest \
- tc20_verifywrap2.stderr.exp tc20_verifywrap2.stderr.exp2\
+ tc20_verifywrap.vgtest tc20_verifywrap.stderr.exp \
+ tc20_verifywrap2.vgtest tc20_verifywrap2.stderr.exp \
tc21_pthonce.vgtest \
tc21_pthonce.stderr.exp tc21_pthonce.stdout.exp \
tc22_exit_w_lock.vgtest \
sed \
-e "/^exp-drd, a data race detector\.$/d" \
-e "s/^Allocation context: stack of thread \([0-9]*\), offset -[0-9]*$/Allocation context: stack of thread \1, offset .../" \
+-e "s/^Allocation context: .*$/Allocation context: unknown/" \
-e "/^NOTE: This is an Experimental-Class Valgrind Tool.$/d" \
-e "/^Copyright (C) 2006-200., and GNU GPL'd, by Bart Van Assche.$/d" \
-e "s/\(pthread_create.c:[0-9]*\)/in libpthread-?.?.so/" \
Conflicting load by main at 0x........ size 8
at 0x........: main (fp_race.c:?)
-Allocation context: s_d3 (offset 0, size 8) in fp_race, NONE:BSS
+Allocation context: unknown
Other segment start (thread_func)
(thread finished, call stack no longer available)
Other segment end (thread_func)
Conflicting store by main at 0x........ size 8
at 0x........: main (fp_race.c:?)
-Allocation context: s_d3 (offset 0, size 8) in fp_race, NONE:BSS
+Allocation context: unknown
Other segment start (thread_func)
(thread finished, call stack no longer available)
Other segment end (thread_func)
+++ /dev/null
-
-Conflicting load by main at 0x........ size 8
- at 0x........: main (fp_race.c:?)
-Allocation context: unknown
-Other segment start (thread_func)
- (thread finished, call stack no longer available)
-Other segment end (thread_func)
- (thread finished, call stack no longer available)
-
-Conflicting store by main at 0x........ size 8
- at 0x........: main (fp_race.c:?)
-Allocation context: unknown
-Other segment start (thread_func)
- (thread finished, call stack no longer available)
-Other segment end (thread_func)
- (thread finished, call stack no longer available)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
+++ /dev/null
-
-Thread 3:
-Conflicting store by thread 3 at 0x........ size 4
- at 0x........: t2 (hg03_inherit.c:28)
- by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
- by 0x........: start_thread (in libpthread-?.?.so)
- by 0x........: clone (in /...libc...)
-Allocation context: unknown
-Other segment start (thread 1)
- at 0x........: pthread_join (drd_intercepts.c:?)
- by 0x........: main (hg03_inherit.c:49)
-Other segment end (thread 1)
- at 0x........: pthread_join (in libpthread-?.?.so)
- by 0x........: pthread_join (drd_intercepts.c:?)
- by 0x........: main (hg03_inherit.c:63)
-
-Conflicting store by thread 3 at 0x........ size 4
- at 0x........: t2 (hg03_inherit.c:29)
- by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
- by 0x........: start_thread (in libpthread-?.?.so)
- by 0x........: clone (in /...libc...)
-Allocation context: unknown
-Other segment start (thread 1)
- at 0x........: pthread_join (drd_intercepts.c:?)
- by 0x........: main (hg03_inherit.c:49)
-Other segment end (thread 1)
- at 0x........: pthread_join (in libpthread-?.?.so)
- by 0x........: pthread_join (drd_intercepts.c:?)
- by 0x........: main (hg03_inherit.c:63)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
+++ /dev/null
-
-Thread 2:
-Conflicting load by thread 2 at 0x........ size 4
- at 0x........: th (hg04_race.c:10)
- by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
- by 0x........: start_thread (in libpthread-?.?.so)
- by 0x........: clone (in /...libc...)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-Conflicting store by thread 2 at 0x........ size 4
- at 0x........: th (hg04_race.c:10)
- by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
- by 0x........: start_thread (in libpthread-?.?.so)
- by 0x........: clone (in /...libc...)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
by 0x........: start_thread (in libpthread-?.?.so)
by 0x........: clone (in /...libc...)
-Allocation context: stack of thread 1, offset ...
+Allocation context: unknown
Other segment start (thread 2)
(thread finished, call stack no longer available)
Other segment end (thread 2)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
by 0x........: start_thread (in libpthread-?.?.so)
by 0x........: clone (in /...libc...)
-Allocation context: stack of thread 1, offset ...
+Allocation context: unknown
Other segment start (thread 2)
(thread finished, call stack no longer available)
Other segment end (thread 2)
-Recursive locking not allowed: address 0x........, recursion count 1, owner 1.
+Recursive locking not allowed: mutex 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
by 0x........: lock_twice (recursive_mutex.c:?)
by 0x........: main (recursive_mutex.c:?)
-Attempt to unlock a mutex that is not locked: address 0x........, recursion count -1, owner 1.
+Mutex not locked by calling thread: mutex 0x........, recursion count 0, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: lock_twice (recursive_mutex.c:?)
by 0x........: main (recursive_mutex.c:?)
-Recursive locking not allowed: address 0x........, recursion count 1, owner 1.
+Recursive locking not allowed: mutex 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
by 0x........: lock_twice (recursive_mutex.c:?)
by 0x........: main (recursive_mutex.c:?)
Conflicting load by main at 0x........ size 8
at 0x........: main (sem_as_mutex.c:?)
-Allocation context: s_d3 (offset 0, size 8) in sem_as_mutex, NONE:BSS
+Allocation context: unknown
Other segment start (thread_func)
(thread finished, call stack no longer available)
Other segment end (thread_func)
Conflicting store by main at 0x........ size 8
at 0x........: main (sem_as_mutex.c:?)
-Allocation context: s_d3 (offset 0, size 8) in sem_as_mutex, NONE:BSS
+Allocation context: unknown
Other segment start (thread_func)
(thread finished, call stack no longer available)
Other segment end (thread_func)
+++ /dev/null
-
-Conflicting load by main at 0x........ size 8
- at 0x........: main (sem_as_mutex.c:?)
-Allocation context: unknown
-Other segment start (thread_func)
- (thread finished, call stack no longer available)
-Other segment end (thread_func)
- (thread finished, call stack no longer available)
-
-Conflicting store by main at 0x........ size 8
- at 0x........: main (sem_as_mutex.c:?)
-Allocation context: unknown
-Other segment start (thread_func)
- (thread finished, call stack no longer available)
-Other segment end (thread_func)
- (thread finished, call stack no longer available)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
+++ /dev/null
-
-Conflicting load by thread 1 at 0x........ size 4
- at 0x........: main (tc01_simple_race.c:28)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 4
- at 0x........: main (tc01_simple_race.c:28)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
at 0x........: free (vg_replace_malloc.c:...)
by 0x........: main (tc04_free_lock.c:24)
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
at 0x........: bar (tc04_free_lock.c:40)
by 0x........: main (tc04_free_lock.c:26)
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
at 0x........: foo (tc04_free_lock.c:49)
by 0x........: main (tc04_free_lock.c:27)
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
at 0x........: bar (tc04_free_lock.c:40)
by 0x........: main (tc04_free_lock.c:28)
+++ /dev/null
-
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
- at 0x........: bar (tc04_free_lock.c:40)
- by 0x........: (below main) (in /...libc...)
-
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
- at 0x........: foo (tc04_free_lock.c:49)
- by 0x........: (below main) (in /...libc...)
-
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
- at 0x........: bar (tc04_free_lock.c:40)
- by 0x........: (below main) (in /...libc...)
-
-ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
+++ /dev/null
-ERROR SUMMARY: 4 errors from 4 contexts
+++ /dev/null
-
-Conflicting load by thread 1 at 0x........ size 4
- at 0x........: main (tc07_hbl1.c:68)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 4
- at 0x........: main (tc07_hbl1.c:68)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
-Attempt to unlock a mutex that is not locked: address 0x........, recursion count -1, owner 1.
+Mutex not locked by calling thread: mutex 0x........, recursion count 0, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc09_bad_unlock.c:27)
by 0x........: main (tc09_bad_unlock.c:49)
Thread 2:
-Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 1.
+Mutex not locked by calling thread: mutex 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: child_fn (tc09_bad_unlock.c:11)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
by 0x........: clone (in /...libc...)
Thread 1:
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc09_bad_unlock.c:41)
by 0x........: main (tc09_bad_unlock.c:49)
-Attempt to unlock a mutex that is not locked: address 0x........, recursion count -1, owner 1.
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
+ at 0x........: nearly_main (tc09_bad_unlock.c:45)
+ by 0x........: main (tc09_bad_unlock.c:49)
+
+Mutex not locked by calling thread: mutex 0x........, recursion count 0, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc09_bad_unlock.c:27)
by 0x........: main (tc09_bad_unlock.c:50)
Thread 2:
-Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 1.
+Mutex not locked by calling thread: mutex 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: child_fn (tc09_bad_unlock.c:11)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
by 0x........: clone (in /...libc...)
Thread 1:
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc09_bad_unlock.c:41)
by 0x........: main (tc09_bad_unlock.c:50)
-ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
+ at 0x........: nearly_main (tc09_bad_unlock.c:45)
+ by 0x........: main (tc09_bad_unlock.c:50)
+
+ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 0 from 0)
before unlock #2
before unlock #3
before unlock #4
-Attempt to unlock a mutex that is not locked: address 0x........, recursion count -1, owner 1.
+Mutex not locked by calling thread: mutex 0x........, recursion count 0, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: nearly_main (tc10_rec_lock.c:42)
by 0x........: main (tc10_rec_lock.c:47)
+++ /dev/null
-
-Conflicting load by thread 1 at 0x........ size 4
- at 0x........: main (tc11_XCHG.c:78)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 4
- at 0x........: main (tc11_XCHG.c:78)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
+Reader-writer lock not locked by calling thread: rwlock 0x.........
+ at 0x........: pthread_rwlock_unlock* (drd_intercepts.c:?)
+ by 0x........: main (tc12_rwl_trivial.c:29)
-ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
+++ /dev/null
-
-Conflicting load by thread 1 at 0x........ size 1
- at 0x........: main (tc16_byterace.c:34)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-Conflicting store by thread 1 at 0x........ size 1
- at 0x........: main (tc16_byterace.c:34)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
-ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
-Invalid semaphore 0x........
+Invalid semaphore: semaphore 0x........
at 0x........: sem_wait* (drd_intercepts.c:?)
by 0x........: main (tc18_semabuse.c:34)
Conflicting store by thread 1 at 0x........ size 2
at 0x........: main (tc20_verifywrap.c:78)
-Allocation context: unprotected (offset 0, size 2) in tc20_verifywrap, NONE:BSS
+Allocation context: unknown
Other segment start (thread 2)
(thread finished, call stack no longer available)
Other segment end (thread 2)
---------------- pthread_mutex_lock et al ----------------
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_init (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:92)
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_destroy (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:102)
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:108)
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_trylock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:116)
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_timedlock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:121)
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:125)
---------------- pthread_cond_wait et al ----------------
-Mutex not locked: address 0x........, recursion count 0, owner 0.
+Mutex not locked: mutex 0x........, recursion count 0, owner 0.
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:147)
FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
-Mutex not locked: address 0x........, recursion count 0, owner 0.
+Mutex not locked: mutex 0x........, recursion count 0, owner 0.
at 0x........: pthread_cond_timedwait* (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:165)
---------------- pthread_rwlock_* ----------------
+
+Reader-writer lock not locked by calling thread: rwlock 0x.........
+ at 0x........: pthread_rwlock_unlock* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:179)
(1) no error on next line
(2) no error on next line
(3) ERROR on next line
+
+Reader-writer lock not locked by calling thread: rwlock 0x.........
+ at 0x........: pthread_rwlock_unlock* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:196)
+
+Reader-writer lock reinitialization: rwlock 0x.........
+ at 0x........: pthread_rwlock_init* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:199)
(4) no error on next line
(5) no error on next line
(6) no error on next line
(7) no error on next line
(8) ERROR on next line
+Reader-writer lock not locked by calling thread: rwlock 0x.........
+ at 0x........: pthread_rwlock_unlock* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:212)
+
---------------- sem_* ----------------
FIXME: can't figure out how to verify wrap of sem_destroy
-Invalid semaphore 0x........
+Invalid semaphore: semaphore 0x........
at 0x........: sem_wait* (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:242)
------------ dealloc of mem holding locks ------------
-ERROR SUMMARY: 10 errors from 10 contexts (suppressed: 0 from 0)
+Destroying locked rwlock: rwlock 0x.........
+ at 0x........: main (tc20_verifywrap.c:262)
+
+ERROR SUMMARY: 15 errors from 15 contexts (suppressed: 0 from 0)
+++ /dev/null
-
-
-
------- This is output for >= glibc 2.4 ------
-
----------------- pthread_create/join ----------------
-
-Conflicting store by thread 1 at 0x........ size 2
- at 0x........: main (tc20_verifywrap.c:78)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
----------------- pthread_mutex_lock et al ----------------
-
-
-Invalid mutex
- at 0x........: pthread_mutex_init (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:92)
-
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
- at 0x........: pthread_mutex_destroy (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:102)
-
-Invalid mutex
- at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:108)
-
-Invalid mutex
- at 0x........: pthread_mutex_trylock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:116)
-
-Invalid mutex
- at 0x........: pthread_mutex_timedlock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:121)
-
-Invalid mutex
- at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:125)
-
----------------- pthread_cond_wait et al ----------------
-
-
-Mutex not locked: address 0x........, recursion count 0, owner 0.
- at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:147)
-
-FIXME: can't figure out how to verify wrap of pthread_cond_signal
-
-
-FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
-
-
-Mutex not locked: address 0x........, recursion count 0, owner 0.
- at 0x........: pthread_cond_timedwait* (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:165)
-
----------------- pthread_rwlock_* ----------------
-
-(1) no error on next line
-(2) no error on next line
-(3) ERROR on next line
-(4) no error on next line
-(5) no error on next line
-(6) no error on next line
-(7) no error on next line
-(8) ERROR on next line
-
----------------- sem_* ----------------
-
-
-FIXME: can't figure out how to verify wrap of sem_destroy
-
-
-Invalid semaphore 0x........
- at 0x........: sem_wait* (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:242)
-
-FIXME: can't figure out how to verify wrap of sem_post
-
-
------------- dealloc of mem holding locks ------------
-
-
-ERROR SUMMARY: 10 errors from 10 contexts (suppressed: 0 from 0)
Conflicting store by thread 1 at 0x........ size 2
at 0x........: main (tc20_verifywrap.c:78)
-Allocation context: unprotected (offset 0, size 2) in tc20_verifywrap, NONE:BSS
+Allocation context: unknown
Other segment start (thread 2)
(thread finished, call stack no longer available)
Other segment end (thread 2)
[1/1] mutex_init invalid mutex 0x........
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_init (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:92)
[1/1] mutex_init mutex 0x........
[1/1] post_mutex_lock mutex 0x........ rc 0 owner 0
[1/1] mutex_destroy mutex 0x........
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
at 0x........: pthread_mutex_destroy (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:102)
[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:108)
[1/1] post_mutex_lock (?) 0x........ rc 0 owner 0
[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_trylock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:116)
[1/1] post_mutex_lock (?) 0x........ rc 0 owner 0
[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_timedlock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:121)
[1/1] post_mutex_lock (?) 0x........ rc 0 owner 0
+[1/1] mutex_unlock ? 0x........ rc 0
-Invalid mutex
+Not a mutex
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:125)
[1/1] cond_init 0x........
[1/1] mutex_unlock error checking mutex 0x........ rc 0
-Mutex not locked: address 0x........, recursion count 0, owner 0.
+Mutex not locked: mutex 0x........, recursion count 0, owner 0.
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:147)
[1/1] cond_pre_wait 0x........
[1/1] mutex_unlock error checking mutex 0x........ rc 0
-Mutex not locked: address 0x........, recursion count 0, owner 0.
+Mutex not locked: mutex 0x........, recursion count 0, owner 0.
at 0x........: pthread_cond_timedwait* (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:165)
[1/1] cond_pre_wait 0x........
---------------- pthread_rwlock_* ----------------
+
+Reader-writer lock not locked by calling thread: rwlock 0x.........
+ at 0x........: pthread_rwlock_unlock* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:179)
(1) no error on next line
(2) no error on next line
(3) ERROR on next line
+
+Reader-writer lock not locked by calling thread: rwlock 0x.........
+ at 0x........: pthread_rwlock_unlock* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:196)
+
+Reader-writer lock reinitialization: rwlock 0x.........
+ at 0x........: pthread_rwlock_init* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:199)
(4) no error on next line
(5) no error on next line
(6) no error on next line
(7) no error on next line
(8) ERROR on next line
+Reader-writer lock not locked by calling thread: rwlock 0x.........
+ at 0x........: pthread_rwlock_unlock* (drd_intercepts.c:?)
+ by 0x........: main (tc20_verifywrap.c:212)
+
---------------- sem_* ----------------
[1/1] semaphore_init 0x........
[1/1] semaphore_pre_wait 0x........
[1/1] semaphore_post_wait 0x........
-Invalid semaphore 0x........
+Invalid semaphore: semaphore 0x........
at 0x........: sem_wait* (drd_intercepts.c:?)
by 0x........: main (tc20_verifywrap.c:242)
[1/1] semaphore_post 0x........
------------ dealloc of mem holding locks ------------
+
+Destroying locked rwlock: rwlock 0x.........
+ at 0x........: main (tc20_verifywrap.c:262)
[1/1] mutex_destroy error checking mutex 0x........
[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
[1/1] mutex_init recursive mutex 0x........
[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
[1/1] mutex_unlock recursive mutex 0x........ rc 1
-ERROR SUMMARY: 10 errors from 10 contexts (suppressed: 0 from 0)
+ERROR SUMMARY: 15 errors from 15 contexts (suppressed: 0 from 0)
+++ /dev/null
-
-
-
------- This is output for >= glibc 2.4 ------
-
----------------- pthread_create/join ----------------
-
-Conflicting store by thread 1 at 0x........ size 2
- at 0x........: main (tc20_verifywrap.c:78)
-Allocation context: unknown
-Other segment start (thread 2)
- (thread finished, call stack no longer available)
-Other segment end (thread 2)
- (thread finished, call stack no longer available)
-
----------------- pthread_mutex_lock et al ----------------
-
-[1/1] mutex_init invalid mutex 0x........
-
-Invalid mutex
- at 0x........: pthread_mutex_init (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:92)
-[1/1] mutex_init mutex 0x........
-[1/1] pre_mutex_lock mutex 0x........ rc 0 owner 0
-[1/1] post_mutex_lock mutex 0x........ rc 0 owner 0
-[1/1] mutex_destroy mutex 0x........
-
-Destroying locked mutex: address 0x........, recursion count 1, owner 1.
- at 0x........: pthread_mutex_destroy (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:102)
-[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
-
-Invalid mutex
- at 0x........: pthread_mutex_lock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:108)
-[1/1] post_mutex_lock (?) 0x........ rc 0 owner 0
-[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
-
-Invalid mutex
- at 0x........: pthread_mutex_trylock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:116)
-[1/1] post_mutex_lock (?) 0x........ rc 0 owner 0
-[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
-
-Invalid mutex
- at 0x........: pthread_mutex_timedlock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:121)
-[1/1] post_mutex_lock (?) 0x........ rc 0 owner 0
-
-Invalid mutex
- at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:125)
-
----------------- pthread_cond_wait et al ----------------
-
-[1/1] mutex_init error checking mutex 0x........
-[1/1] cond_init 0x........
-[1/1] mutex_unlock error checking mutex 0x........ rc 0
-
-Mutex not locked: address 0x........, recursion count 0, owner 0.
- at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:147)
-[1/1] cond_pre_wait 0x........
-[1/1] cond_post_wait 0x........
-[1/1] post_mutex_lock error checking mutex 0x........ rc 0 owner 0
-[1/1] cond_signal 0x........
-
-FIXME: can't figure out how to verify wrap of pthread_cond_signal
-
-[1/1] cond_broadcast 0x........
-
-FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
-
-[1/1] mutex_unlock error checking mutex 0x........ rc 0
-
-Mutex not locked: address 0x........, recursion count 0, owner 0.
- at 0x........: pthread_cond_timedwait* (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:165)
-[1/1] cond_pre_wait 0x........
-[1/1] cond_post_wait 0x........
-[1/1] post_mutex_lock error checking mutex 0x........ rc 0 owner 0
-
----------------- pthread_rwlock_* ----------------
-
-(1) no error on next line
-(2) no error on next line
-(3) ERROR on next line
-(4) no error on next line
-(5) no error on next line
-(6) no error on next line
-(7) no error on next line
-(8) ERROR on next line
-
----------------- sem_* ----------------
-
-[1/1] semaphore_init 0x........
-
-FIXME: can't figure out how to verify wrap of sem_destroy
-
-[1/1] semaphore_pre_wait 0x........
-[1/1] semaphore_post_wait 0x........
-
-Invalid semaphore 0x........
- at 0x........: sem_wait* (drd_intercepts.c:?)
- by 0x........: main (tc20_verifywrap.c:242)
-[1/1] semaphore_post 0x........
-
-FIXME: can't figure out how to verify wrap of sem_post
-
-[1/1] semaphore_destroy 0x........
-
------------- dealloc of mem holding locks ------------
-
-[1/1] mutex_destroy error checking mutex 0x........
-[1/1] pre_mutex_lock (?) 0x........ rc 0 owner 0
-[1/1] mutex_init recursive mutex 0x........
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 0
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-[1/1] pre_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] post_mutex_lock recursive mutex 0x........ rc 0 owner 1
-[1/1] mutex_unlock recursive mutex 0x........ rc 1
-
-ERROR SUMMARY: 10 errors from 10 contexts (suppressed: 0 from 0)
by 0x........: clone (in /...libc...)
Thread 1:
-Mutex not locked: address 0x........, recursion count 0, owner 0.
+Mutex not locked: mutex 0x........, recursion count 0, owner 0.
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc23_bogus_condwait.c:72)
by 0x........: clone (in /...libc...)
Thread 1:
-Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 2.
+Mutex not locked by calling thread: mutex 0x........, recursion count 1, owner 2.
at 0x........: pthread_cond_wait* (drd_intercepts.c:?)
by 0x........: main (tc23_bogus_condwait.c:78)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)
by 0x........: start_thread (in libpthread-?.?.so)
by 0x........: clone (in /...libc...)
+The impossible happened: mutex 0x........ is locked simultaneously by two threads (recursion count 1, owners 2 and 1) !
Thread 2:
-Mutex not unlocked by owner thread: address 0x........, recursion count 1, owner 1.
+Mutex not locked by calling thread: mutex 0x........, recursion count 2, owner 1.
at 0x........: pthread_mutex_unlock (drd_intercepts.c:?)
by 0x........: grab_the_lock (tc23_bogus_condwait.c:42)
by 0x........: vg_thread_wrapper (drd_intercepts.c:?)