Added a "Dubious" error category to cover this kind of error.
/helgrind/tests/bar_bad
/helgrind/tests/bar_trivial
/helgrind/tests/bug322621
+/helgrind/tests/bug392331
/helgrind/tests/cond_init_destroy
/helgrind/tests/cond_timedwait_invalid
/helgrind/tests/cond_timedwait_test
170510 Don't warn about ioctl of size 0 without direction hint
351857 confusing error message about valid command line option
+392331 Spurious lock not held error from inside pthread_cond_timedwait
444110 priv/guest_ppc_toIR.c:36198:31: warning: duplicated 'if' condition.
444488 Use glibc.pthread.stack_cache_size tunable
444568 drd/tests/pth_barrier_thr_cr fails on Fedora 38
XE_UnlockBogus, // unlocking an address not known to be a lock
XE_PthAPIerror, // error from the POSIX pthreads API
XE_LockOrder, // lock order error
- XE_Misc // misc other error (w/ string to describe it)
+ XE_Misc, // misc other error (w/ string to describe it)
+ XE_Dubious // a bit like misc for cases where the POSIX
+ // spec is unclear on error conditons
}
XErrorTag;
XS_UnlockBogus,
XS_PthAPIerror,
XS_LockOrder,
- XS_Misc
+ XS_Misc,
+ XS_Dubious
}
XSuppTag;
HG_(record_error_Misc_w_aux)(thr, errstr, NULL, NULL);
}
+void HG_(record_error_Dubious_w_aux) ( Thread* thr, const HChar* errstr,
+ const HChar* auxstr, ExeContext* auxctx )
+{
+ XError xe;
+ tl_assert( HG_(is_sane_Thread)(thr) );
+ tl_assert(errstr);
+ init_XError(&xe);
+ xe.tag = XE_Dubious;
+ xe.XE.Misc.thr = thr;
+ xe.XE.Misc.errstr = string_table_strdup(errstr);
+ xe.XE.Misc.auxstr = auxstr ? string_table_strdup(auxstr) : NULL;
+ xe.XE.Misc.auxctx = auxctx;
+ // FIXME: tid vs thr
+ tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
+ tl_assert( thr->coretid != VG_INVALID_THREADID );
+ VG_(maybe_record_error)( thr->coretid,
+ XE_Dubious, 0, NULL, &xe );
+}
+
+void HG_(record_error_Dubious) ( Thread* thr, const HChar* errstr )
+{
+ HG_(record_error_Dubious_w_aux)(thr, errstr, NULL, NULL);
+}
+
Bool HG_(eq_Error) ( VgRes not_used, const Error* e1, const Error* e2 )
{
XError *xe1, *xe2;
case XE_Misc:
return xe1->XE.Misc.thr == xe2->XE.Misc.thr
&& 0==VG_(strcmp)(xe1->XE.Misc.errstr, xe2->XE.Misc.errstr);
+ case XE_Dubious:
+ return xe1->XE.Misc.thr == xe2->XE.Misc.thr
+ && 0==VG_(strcmp)(xe1->XE.Misc.errstr, xe2->XE.Misc.errstr);
default:
tl_assert(0);
}
tl_assert(xe);
switch (VG_(get_error_kind)(err)) {
+ case XE_Dubious:
+ announce_one_thread( xe->XE.Misc.thr );
+ break;
case XE_Misc:
announce_one_thread( xe->XE.Misc.thr );
break;
emit( " <kind>%s</kind>\n", HG_(get_error_name)(err));
switch (VG_(get_error_kind)(err)) {
+ case XE_Dubious: {
+ tl_assert( HG_(is_sane_Thread)( xe->XE.Misc.thr ) );
+
+ if (xml) {
+
+ emit( " <xwhat>\n" );
+ emit( " <text>Thread #%d: %s</text>\n",
+ (Int)xe->XE.Misc.thr->errmsg_index,
+ xe->XE.Misc.errstr );
+ emit( " <hthreadid>%d</hthreadid>\n",
+ (Int)xe->XE.Misc.thr->errmsg_index );
+ emit( " </xwhat>\n" );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.Misc.auxstr) {
+ emit(" <auxwhat>%s</auxwhat>\n", xe->XE.Misc.auxstr);
+ if (xe->XE.Misc.auxctx)
+ VG_(pp_ExeContext)( xe->XE.Misc.auxctx );
+ }
+
+ } else {
+
+ emit( "Thread #%d: %s\n",
+ (Int)xe->XE.Misc.thr->errmsg_index,
+ xe->XE.Misc.errstr );
+ VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+ if (xe->XE.Misc.auxstr) {
+ emit(" %s\n", xe->XE.Misc.auxstr);
+ if (xe->XE.Misc.auxctx)
+ VG_(pp_ExeContext)( xe->XE.Misc.auxctx );
+ }
+
+ }
+ break;
+ }
case XE_Misc: {
tl_assert( HG_(is_sane_Thread)( xe->XE.Misc.thr ) );
case XE_PthAPIerror: return "PthAPIerror";
case XE_LockOrder: return "LockOrder";
case XE_Misc: return "Misc";
+ case XE_Dubious: return "Dubious";
default: tl_assert(0); /* fill in missing case */
}
}
TRY("PthAPIerror", XS_PthAPIerror);
TRY("LockOrder", XS_LockOrder);
TRY("Misc", XS_Misc);
+ TRY("Dubious", XS_Dubious);
return False;
# undef TRY
}
case XS_PthAPIerror: return VG_(get_error_kind)(err) == XE_PthAPIerror;
case XS_LockOrder: return VG_(get_error_kind)(err) == XE_LockOrder;
case XS_Misc: return VG_(get_error_kind)(err) == XE_Misc;
+ case XS_Dubious: return VG_(get_error_kind)(err) == XE_Dubious;
//case XS_: return VG_(get_error_kind)(err) == XE_;
default: tl_assert(0); /* fill in missing cases */
}
ExeContext* auxctx );
void HG_(record_error_Misc) ( Thread* thr, const HChar* errstr );
+void HG_(record_error_Dubious_w_aux) ( Thread*, const HChar* errstr,
+ const HChar* auxstr,
+ ExeContext* auxctx );
+void HG_(record_error_Dubious) ( Thread* thr, const HChar* errstr );
+
/* Statistics pertaining to error management. */
extern ULong HG_(stats__LockN_to_P_queries);
"pthread_cond_{signal,broadcast}: associated lock is a rwlock");
}
if (lk->heldBy == NULL) {
- HG_(record_error_Misc)(thr,
+ HG_(record_error_Dubious)(thr,
"pthread_cond_{signal,broadcast}: dubious: "
"associated lock is not held by any thread");
}
annotate_smart_pointer.vgtest annotate_smart_pointer.stdout.exp \
annotate_smart_pointer.stderr.exp \
bug322621.vgtest bug322621.stderr.exp \
+ bug392331.vgtest bug392331.stdout.exp bug392331.stderr.exp \
+ bug392331_supp.vgtest bug392331_supp.stdout.exp bug392331_supp.stderr.exp \
+ bug392331.supp \
cond_init_destroy.vgtest cond_init_destroy.stderr.exp \
cond_timedwait_invalid.vgtest cond_timedwait_invalid.stdout.exp \
cond_timedwait_invalid.stderr.exp \
# should be conditionally compiled like tc20_verifywrap is.
check_PROGRAMS = \
annotate_hbefore \
+ bug392331 \
cond_init_destroy \
cond_timedwait_invalid \
cond_timedwait_test \
endif
bug322621_SOURCES = bug322621.cpp
+bug392331_SOURCES = bug392331.cpp
+bug392331_CXXFLAGS = $(AM_CXXFLAGS) -std=c++17
+
--- /dev/null
+// For this Bugzilla item https://bugs.kde.org/show_bug.cgi?id=392331
+// Example from https://en.cppreference.com/w/cpp/thread/condition_variable
+
+#include <iostream>
+#include <string>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+
+std::mutex m;
+std::condition_variable cv;
+std::string data;
+bool ready = false;
+bool processed = false;
+
+void worker_thread()
+{
+ // Wait until main() sends data
+ std::unique_lock lk(m);
+ cv.wait(lk, []{return ready;});
+
+ // after the wait, we own the lock.
+ std::cout << "Worker thread is processing data\n";
+ data += " after processing";
+
+ // Send data back to main()
+ processed = true;
+ std::cout << "Worker thread signals data processing completed\n";
+
+ // Manual unlocking is done before notifying, to avoid waking up
+ // the waiting thread only to block again (see notify_one for details)
+ lk.unlock();
+ cv.notify_one();
+}
+
+int main()
+{
+ std::thread worker(worker_thread);
+
+ data = "Example data";
+ // send data to the worker thread
+ {
+ std::lock_guard lk(m);
+ ready = true;
+ std::cout << "main() signals data ready for processing\n";
+ }
+ cv.notify_one();
+
+ // wait for the worker
+ {
+ std::unique_lock lk(m);
+ cv.wait(lk, []{return processed;});
+ }
+ std::cout << "Back in main(), data = " << data << '\n';
+
+ worker.join();
+}
+
--- /dev/null
+---Thread-Announcement------------------------------------------
+
+Thread #x is the program's root thread
+
+----------------------------------------------------------------
+
+Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
+ at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
+ by 0x........: pthread_cond_signal (hg_intercepts.c:...)
+ ...
+ by 0x........: main (bug392331.cpp:47)
+
+---Thread-Announcement------------------------------------------
+
+Thread #x was created
+ ...
+ by 0x........: pthread_create@* (hg_intercepts.c:...)
+ ...
+ by 0x........: main (bug392331.cpp:38)
+
+----------------------------------------------------------------
+
+Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
+ at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
+ by 0x........: pthread_cond_signal (hg_intercepts.c:...)
+ ...
+ by 0x........: worker_thread() (bug392331.cpp:33)
+ ...
+ by 0x........: mythread_wrapper (hg_intercepts.c:...)
+ ...
+
--- /dev/null
+main() signals data ready for processing
+Worker thread is processing data
+Worker thread signals data processing completed
+Back in main(), data = Example data after processing
--- /dev/null
+{
+ Check that Dubious suppression works
+ Helgrind:Dubious
+ fun:pthread_cond_signal_WRK
+ fun:pthread_cond_signal
+ fun:_ZNSt3__118condition_variable10notify_oneEv
+}
--- /dev/null
+vgopts: -q
+prog: bug392331
--- /dev/null
+main() signals data ready for processing
+Worker thread is processing data
+Worker thread signals data processing completed
+Back in main(), data = Example data after processing
--- /dev/null
+vgopts: -q --suppressions=bug392331.suppr
+prog: bug392331