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
Related
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).
Yesterday I asked a question about this problem, but I wasn't able to give a MVCE. I've managed to reproduce this with a simple program. The problem is with using an std::list as a static inline declaration in a class. Microsoft Visual Studio does support this new C++17 feature. It had some bugs as of March, but as far as I know they've been fixed since. Here are instructions of how I can get this problem, this happens in debug mode.
In main.cpp
#include <iostream>
#include "header1.h"
int main()
{
return 0;
}
In header1.h:
#include <list>
struct Boo
{
static inline std::list<int> mylist;
};
In anotherCPP.cpp
#include "Header1.h"
When the program exits main() it destroys all the static objects and throws an exception.
If this doesn't crash, maybe on your system the compiler/linker optimised some code out, so you can try making main.cpp and anotherCPP.cpp do something. In anotherCPP.cpp:
#include <iostream>
#include "Header1.h"
void aFunction()
{
std::cout << Boo::mylist.size();
}
And make main.cpp:
#include <iostream>
#include "Header1.h"
void aFunction();
int main()
{
std::cout << Boo::mylist.size();
afunction();
return 0;
}
When the program exits I get an exception here when the std::list is being cleared. Here is the Visual Studio debug code where it crashes:
for (_Nodeptr _Pnext; _Pnode != this->_Myhead(); _Pnode = _Pnext)
{ // delete an element
_Pnext = _Pnode->_Next; // Here: Exception thrown:
// read access violation.
// _Pnode was 0xFFFFFFFFFFFFFFFF.
this->_Freenode(_Pnode);
}
This happens only if I declare the static inline std::list< int > mylist in the class. If I declare it as static std::list< int > mylist in my class and then define it separately in one .cpp as std::list< int > Boo::mylist; it works fine. This problem arises when I declare the std::list static inline and I include the header for the class in two .cpp files.
In my project I have stepped through the std::list clear loop from above, I took note of the "this" pointer address. I stepped through the loop as it freed nodes in my list. It then came back to free other std::lists, including in std::unordered_map (as they also use std::lists from the looks of it). Finally when the read access exception is thrown and _Pnode is an invalid pointer address, I noticed the "this" pointer address is the same as the "this" pointer address when clearing std::list< int > mylist, which makes me think that it's trying to delete it twice, and probably why it's crashing.
I hope someone can reproduce this, I'm not sure what this is, if it's a bug or something I'm doing wrong. Also this happens for me in 32 and 64 bit, but only in debug mode, because the node freeing loop I provided is under a macro:
#if _ITERATOR_DEBUG_LEVEL == 2
This issue was filed as a bug here under the title "Multiple initializations of inline static data member in Debug mode".
This was found in Visual Studio 2017 version 15.7.
The VS compiler team has accepted this and have fixed the problem in an upcoming release.
I've been porting some c++ app from Visual Studio 2013 to Visual Studio 2017. Aside from the plethora of new warnings that I had to fix, the compilation and linking went okay.
However, when running the app, it 'stalled' when trying to re-enter the constructor of a singleton (when successive function calls form a loop back to the constructor). It seems that this behaviour was okay in VS2013, but is no longer valid in VS2017. There is no error message.
I'm aware of all the bad things related to singletons, and that there should at least not be loops. The question is not there.
Is there a way to tell the VS2017 compiler that I'd like to shoot myself in the foot, and allow the same behaviour that was there in VS2013?
I don't have access to the code that causes this behaviour because it comes from a third-party library, this is why I can't 'just fix it', unfortunately.
Here is an example which works in VS2013, but doesn't work in VS2017:
main.cpp
#include "Singleton.h";
int
main( void )
{
std::cout << "let's do this!" << std::endl;
int two = Singleton::GetReference().getTwo();
std::cout << "ok" << std::endl;
return 0;
}
Singleton.h
#pragma once
class Stuff;
class Singleton
{
public:
static Singleton& GetReference();
int getTwo() { return 2; }
private:
Singleton();
Stuff* stuff;
};
Singleton.cpp
#include "Singleton.h"
#include "Stuff.h"
Singleton&
Singleton::GetReference() {
static Singleton theInstance;
return theInstance;
}
Singleton::Singleton()
{
stuff = new Stuff();
}
Stuff.h
#pragma once
class Stuff
{
public:
Stuff();
private:
int two;
};
Stuff.cpp
#include "Stuff.h"
#include "Singleton.h"
Stuff::Stuff()
{
two = Singleton::GetReference().getTwo();
}
In the code above, when step-by-step debugging, the first time we get on the line static Singleton theInstance; will work as expected, but the second time, a F11 will go to the file thread_safe_statics.cpp, into the method extern "C" void __cdecl _Init_thread_header(int* const pOnce). A Shift+F11 will exit the method and the program will wait indefinitely at the line specified (observed when pausing the program from the debugger).
PS
This issue probably occurs in Visual Studio 2015 too, as the documentation linked from the accepted answer mentions VS2015.
/Zc:threadSafeInit-
The general "Conformance" page is MSDN: Conformance, which details which new features you can disable.
I needed the code for sizedDealloc, where my new compiler was creating a sized new operator for a library which broke older compiled expectations.
As this is a compile flag, at least some of the code would be in your control, and you should be able to unravel the beast.
The constructor Stuff::Stuff is calling a function on an incompletely constructed object.
That would create "Undefined behavior". If the value "2" is not set till the end of the constructor (for example).
Probably the Singleton needs to be split into 2, one which delivers the early static data (e.g. 2).
The second which delivers the held object Stuff. Stuff would only rely on the first, which would break the deadlock.
Alternatively, a second constructor to Stuff which told it which object to use, and was called from the Singleton::Singleton
The MSDN article to disable "Magic Statics" MSDN : disable threadsafe static initialization
I run into problem with rvalue references in MSVC 2012.
#include <thread>
#include <string>
#include <future>
void foo(std::promise<std::string> &&prms) { /* some code */ }
int main() {
std::promise<std::string> prms;
// std::future<std::string> ftr = prms.get_future();
std::thread th(&foo, std::move(prms));
// some other code
}
Compiler says: error C2664: 'void (std::promise<_Ty> &&)' : cannot convert parameter 1 from 'std::promise<_Ty>' to 'std::promise<_Ty> &&'
Is there my mistake (then how to fix it) or compiler issue (then I'd like to know origin of such behaviour)?
This is a known issue in the Visual C++ 2012 implementation of std::thread. See the following bug on Microsoft Connect:
std::thread constructor doesn't handle movable object
The response to that bug states:
We attempted to fix this during VC11's development, but it exploded horribly and we had to revert the change. As it turns out, std::thread can't be powered by bind(), because thread needs to move its arguments, and bind() is forbidden from doing so (since bound functors should be repeatedly invokable, without their bound arguments being moved-from). So we'll need to reimplement std::thread's ctor to avoid using bind().
I've tried compiling this with Visual Studio 2012 RC and Intel C++ Compiler XE 12.1. I'd appreciate if you tried with some other compiler. See my comments in the code to really appreciate the weirdness of this bug. Does anyone know what's going on, and where should I file a bug report about this?
// File: NamedSameA.h
#pragma once
// File: NamedSameA.cpp
#include <vector>
#include "NamedSameA.h"
struct NamedSame // Rename this class to something else to make the program work
{
std::vector<int> data;
// Comment out the previous line or change
// the data type to int to make the program work
};
static NamedSame g_data; // Comment out this line to make the program work
// File: NamedSameB.h
#pragma once
void test();
// File: NamedSameB.cpp
#include <vector>
#include "NamedSameA.h"
#include "NamedSameB.h"
struct NamedSame
{
int data1; // Comment out this line to make the program work
std::vector<int> data2;
};
void test()
{
NamedSame namedSame;
namedSame.data2.assign(100, 42);
// The previous line produces the following runtime error:
// -------------------------------------------------------
// Debug Assertion Failed!
// Program: C:\Windows\system32\MSVCP110D.dll
// File: c:\program files (x86)\microsoft visual studio 11.0\vc\include\vector
// Line: 240
// Expression: vector iterators incompatible
}
By giving the same name to two different classes/structures you've violated the One Definition Rule. This results in undefined behavior, so any result is possible - including a crash.
I've found over the years that the more convinced I am that I've found a compiler bug, the more likely it is that my program has a fundamental flaw.