| Summary: | drd reports false positive for concurrent __atomic_base access | ||
|---|---|---|---|
| Product: | [Developer tools] valgrind | Reporter: | ewirch <wirch.eduard> |
| Component: | drd | Assignee: | Bart Van Assche <bart.vanassche+kde> |
| Status: | RESOLVED NOT A BUG | ||
| Severity: | normal | ||
| Priority: | NOR | ||
| Version First Reported In: | 3.9.0 | ||
| Target Milestone: | --- | ||
| Platform: | Compiled Sources | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
|
Description
ewirch
2013-12-06 15:37:17 UTC
Forgot to mention: address is onto stack, valgrind executed with --check-stack-var=yes Similar bug reported for helgrind: 327881 It is not possible for a run-time analysis tool like DRD to recognize sig_atomic_t variables at runtime. My recommendation is either to use a data type that can be recognized by DRD (std::atomic ?) or to use DRD_IGNORE_VAR(). Thanks for the info Bart. But I am using std::atomic: ==2561== at 0x421E3B: std::__atomic_base<bool>::load(std::memory_order) const (atomic_base.h:496) ==2561== by 0x421598: std::atomic_bool::operator bool() const (atomic:77) If you can provide a test program that allows to reproduce the above output I will look further into this issue. Sure:
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string>
#include <atomic>
using namespace std;
class Thread {
public:
Thread() {
}
virtual ~Thread() {
}
void run() {
int err;
err = pthread_create(&pThread_, NULL, &Thread::invokeRun, (void*)this);
if (err != 0) {
throw string("Thread::run(): failed to create a thread.");
}
}
void join() {
void *threadRetValue;
int err = pthread_join(pThread_, &threadRetValue);
if (err != 0) {
throw string("Thread::join(): failed to join.");
}
}
virtual void threadWork() = 0;
private:
static void *invokeRun(void *instance);
pthread_t pThread_;
};
void *Thread::invokeRun(void *instance) {
reinterpret_cast<Thread*>(instance)->threadWork();
return NULL;
}
class LockDoesLock_Thread1: public Thread {
public:
atomic<bool> lockAcquired_;
atomic<bool> tryLocked_;
atomic<bool> unlocked_;
atomic<bool> tryLockSuccess1_;
atomic<bool> tryLockSuccess2_;
pthread_mutex_t &mutex_;
LockDoesLock_Thread1(pthread_mutex_t &pLock) :
mutex_(pLock) {
lockAcquired_ = false;
tryLocked_ = false;
unlocked_ = false;
tryLockSuccess1_ = false;
tryLockSuccess2_ = false;
}
void threadWork() {
pthread_mutex_lock(&mutex_);
lockAcquired_ = true;
while (!tryLocked_) {
};
pthread_mutex_unlock(&mutex_);
unlocked_ = true;
}
};
class AutoLockDoesLock_Thread1: public LockDoesLock_Thread1 {
public:
AutoLockDoesLock_Thread1(pthread_mutex_t &pLock) :
LockDoesLock_Thread1(pLock) {
}
void threadWork() {
doAutoLock();
unlocked_ = true;
}
void doAutoLock() {
pthread_mutex_lock(&mutex_);
lockAcquired_ = true;
while (!tryLocked_) {
};
pthread_mutex_unlock(&mutex_);
}
};
class LockDoesLock_Thread2: public Thread {
public:
LockDoesLock_Thread2(LockDoesLock_Thread1 &buddy) :
buddy_(buddy) {
}
void threadWork() {
while (!buddy_.lockAcquired_) {
}
buddy_.tryLockSuccess1_ = (pthread_mutex_trylock(&buddy_.mutex_) == 0);
buddy_.tryLocked_ = true;
while (!buddy_.unlocked_) {
}
buddy_.tryLockSuccess2_ = (pthread_mutex_trylock(&buddy_.mutex_) == 0);
if (buddy_.tryLockSuccess2_) {
pthread_mutex_unlock(&buddy_.mutex_);
}
}
private:
LockDoesLock_Thread1 &buddy_;
};
int main(int argc, char** argv) {
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
AutoLockDoesLock_Thread1 t1(mutex);
LockDoesLock_Thread2 t2(t1);
t1.run();
t2.run();
t1.join();
t2.join();
if (t1.tryLockSuccess1_ != false) printf("Test fail 1\n");
if (t1.tryLockSuccess2_ != true) printf("Test fail 2\n");
return true;
}
Compile with: g++ -std=c++11 atomictest.cpp -o atomictest -lpthread
Test with: valgrind --tool=drd --check-stack-var=yes ./atomictest
What I see in libstdc++ is the following: * atomic<bool> is represented by a single byte. * atomic<bool>::store() uses __atomic_store_n(), and for bool __atomic_store_n() is a compiler-built-in that uses a regular single-byte store. Sorry but it's not clear to me how DRD or any other Valgrind tool could discern such store operations from regular store operations. Please use DRD_IGNORE_VAR() or equivalent to suppress race reports on atomic<bool> variables. |