After attempting to implement the necessary annotations to an existing codebase, I was unable to remove a seemingly simple warning. I backed into the most simple example, and still no joy.
I have cut-and-pasted the mutex.h header exactly as specified at Thread Safety Analysis. I cannot seem to do a scoped lock without producing a warning. Here is the code:
#include "mutex.h"
#include <iostream>
// functions added just to complete the implementation
void Mutex::Lock()
{
}
void Mutex::GenericUnlock()
{
}
// test a scoped lock
void do_something(Mutex &m)
{
auto locker = MutexLocker(&m);
std::cout << "Hello, world!\n";
}
int main(int argc, char** argv)
{
Mutex my_mutex;
do_something(my_mutex);
}
Compiling with clang++ -o thread_static_analysis thread_static_analysis.cpp -std=c++17 -Wthread-safety produces the following warning:
thread_static_analysis.cpp:18:1: warning: releasing mutex 'locker' that was not held [-Wthread-safety-analysis]
}
^
1 warning generated.
Either (1) I am missing something, or (2) this is a false-positive that must be ignored until a clang implementation issue is resolved. A search for such issues has as-yet given no useful results.
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
My understanding is that you are potentially creating a copy of temporary MutexLocker object in
auto locker = MutexLocker(&m);
(or thread safety analysis thinks you are creating it). The temporary is then destroyed and calls m.Unlock(). Then at the end of the function the locker object is destroyed and calls m.Unlock() again (thus causing a double release error).
Related
The following code in a Visual Studio Professional 2019 project (version 16.3.6) produces a warning:
#include <thread>
#include <future>
class Foo {
public:
mutable std::recursive_mutex _writingMutex;
std::recursive_mutex& writingMutex() const { return _writingMutex; }
};
int main()
{
Foo a;
std::lock_guard<std::recursive_mutex> lock(a.writingMutex()); // produces C26110
std::lock_guard<std::recursive_mutex> lock2(a._writingMutex); // no warning
}
The first lock produces the warning C26110:
Warning C26110 Caller failing to hold lock 'lock' before calling function 'std::lock_guard::~lock_guard'
Why is this so? Does passing the mutex as reference not work?
Based on the compilation result of Alan and the comment of rustyx, I will answer my own question:
This is likely to be a code analysis bug in Visual Studio. Looks like C26110 can't recognize a mutex via a reference. The issue was reported here and I added my minimal example as comment there. The issue persists in the most recent version 16.3.7 as well
I get surprising and conflicting behavior when I try to run the following code.
#include <iostream>
#include <mutex>
int main() {
std::mutex mtx;
std::unique_lock<std::mutex> lock1(mtx);
std::unique_lock<std::mutex> lock2(mtx, std::try_to_lock);
std::cout << "lock1 owns lock: " << lock1.owns_lock() << std::endl;
std::cout << "lock2 owns lock: " << lock2.owns_lock() << std::endl;
}
When I run this on my computer (linux with either clang++ 4.0.1 or g++ 7.3.0) it prints out that both lock1 and lock2 own the lock (surprising). When I run this on cpp.sh it says that lock1 does own, but lock2 does not own the lock (what I expected).
All are using C++11 and -Wall without optimizations.
As stated in documentation for std::unique_lock constructor:
Tries to lock the associated mutex without blocking by calling m.try_lock(). The behavior is undefined if the current thread already owns the mutex except when the mutex is recursive.
Emphasis is mine. Since std::mutex is not recursive you have undefined behaviour - std::mutex::try_lock()
If try_lock is called by a thread that already owns the mutex, the behavior is undefined.
As was answered here, locking mutex that is already owned by the current thread is an undefined behavior according to the C++ standard, but it seems that you know that your implementation is based on POSIX Threads, which has a different set of requirements:
The pthread_mutex_trylock() function shall be equivalent to
pthread_mutex_lock(), except that if the mutex object referenced by
mutex is currently locked (by any thread, including the current
thread), the call shall return immediately.
What you are observing is most likely caused by you not building your code using -pthread flag. GNU C++ library detects if program is linked against libpthread.so and if it is not, then all calls to lock/unlock functions are turned into no-op.
You can find some information here:
__gthread_mutex_lock is a one-line function that forwards to pthread_mutex_lock. Using GNU libc if you don't link to libpthread.so
then pthread_mutex_lock is a no-op function that does nothing. It is
quicker to just call it than to spend time checking if threads are
active.
Or you can check the source code for std::mutex::lock in your header files yourself. You will see something like this:
void
lock()
{
int __e = __gthread_mutex_lock(&_M_mutex);
// EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
if (__e)
__throw_system_error(__e);
}
static inline int
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
{
if (__gthread_active_p ())
return __gthrw_(pthread_mutex_lock) (__mutex);
else
return 0;
}
Function __gthread_active_p will return 0 if libpthread.so is not present in the current process, making mutex locking a no-op.
Adding -pthread will fix your problem, but you shouldn't rely on this - as demonstrated by your case.
I have a little piece of code in C++:
#include <iostream>
#include <iterator>
#include <string>
using namespace std;
int main() {
int i=0;
istream_iterator<string> EOS;
double x;
return 0;
}
Now i compile it with my g++ (GCC) 4.4.4
g++ -W -Wall -pedantic test.cc -o test
And get:
test.cc: In function 'int main()':
test.cc:9: warning: unused variable 'i'
test.cc:11: warning: unused variable 'x'
Why there is no warning for unused EOS?
It is not a primitive value, so its constructor and/or destructor might have desired side effects.
To illustrate that this happens in practice: I use a class to time sections of code, that looks roughly like this:
class Timed {
double start;
public:
Timed() { start = now(); }
~Timed() { std::cout << (now() - start) << '\n'; }
}
So to measure how long a function takes, I simply do:
void slow() {
Timed t;
// heavy operation here...
}
The variable t never gets used, but it's still important to the behaviour of the code.
istream_iterator<string> has a constructor, so the declaration of EOS isn't really a no-op like the declarations of i and x are.
Often you want to declare a class-type object and then not do anything with it. For example, consider std::lock_guard in C++0x (boost::scoped_lock in Boost) or any other kind of scope guard class. You don't usually want to do anything with that kind of object, you just want to create the object so that its destructor get run at the end of the block to perform whatever cleanup needs to be performed.
Because you could have done that with a purpose. It's not a primitive. Maybe the constructor and destructor do something important?
MFC even had classes that operated that way, you could do this:
void foo()
{
CWaitCursor cursor;
[...]
}
That would display an hourglass icon for the duration of the function.
I tried to build my application with ltalloc. I tried it with MinGW32 4.9.1 and MinGW64-32 4.9.2.
It compiles and links fine but when I run it a Segmentation Fault occurs. Debugging pinpointed the problem to the following code:
#include <pthread.h>
#pragma weak pthread_once
#pragma weak pthread_key_create
#pragma weak pthread_setspecific
static pthread_key_t pthread_key;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
static void init_pthread_key() { pthread_key_create(&pthread_key, release_thread_cache); }
static thread_local int thread_initialized = 0;
static void init_pthread_destructor()//must be called only when some block placed into a thread cache's free list
{
if (unlikely(!thread_initialized))
{
thread_initialized = 1;
if (pthread_once)
{
pthread_once(&init_once, init_pthread_key); // <--- THIS CAUSES THE SEGSEGV
pthread_setspecific(pthread_key, (void*)1);//set nonzero value to force calling of release_thread_cache() on thread terminate
}
}
}
As far as I know both versions support thread-local storage natively. The Wiki of of ltalloc also wrote the following:
Warning: in some builds of MinGW there is a problem with emutls and order of execution of thread destructor (all thread local variables destructed before it), and termination of any thread will lead to application crash.
Unfortunately this warning doesn't tell me anything. Googling it also didn't make me smarter.
Out of the blue, try this:
static void init_pthread_key(void)
{
if (pthread_key_create)
{
pthread_key_create(&pthread_key, release_thread_cache);
}
}
Also adding full error checking to the pthread_* might not only help during debugging.
I have a little piece of code in C++:
#include <iostream>
#include <iterator>
#include <string>
using namespace std;
int main() {
int i=0;
istream_iterator<string> EOS;
double x;
return 0;
}
Now i compile it with my g++ (GCC) 4.4.4
g++ -W -Wall -pedantic test.cc -o test
And get:
test.cc: In function 'int main()':
test.cc:9: warning: unused variable 'i'
test.cc:11: warning: unused variable 'x'
Why there is no warning for unused EOS?
It is not a primitive value, so its constructor and/or destructor might have desired side effects.
To illustrate that this happens in practice: I use a class to time sections of code, that looks roughly like this:
class Timed {
double start;
public:
Timed() { start = now(); }
~Timed() { std::cout << (now() - start) << '\n'; }
}
So to measure how long a function takes, I simply do:
void slow() {
Timed t;
// heavy operation here...
}
The variable t never gets used, but it's still important to the behaviour of the code.
istream_iterator<string> has a constructor, so the declaration of EOS isn't really a no-op like the declarations of i and x are.
Often you want to declare a class-type object and then not do anything with it. For example, consider std::lock_guard in C++0x (boost::scoped_lock in Boost) or any other kind of scope guard class. You don't usually want to do anything with that kind of object, you just want to create the object so that its destructor get run at the end of the block to perform whatever cleanup needs to be performed.
Because you could have done that with a purpose. It's not a primitive. Maybe the constructor and destructor do something important?
MFC even had classes that operated that way, you could do this:
void foo()
{
CWaitCursor cursor;
[...]
}
That would display an hourglass icon for the duration of the function.