Strange behaviour when using C++17 static inline members in Visual Studio
Asked Answered
V

1

6

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
Vendue answered 15/10, 2018 at 4:4 Comment(8)
Seems like this should be a MSVC bug report, rather than a SO questionDenn
Kinda naive to assume all bugs in VS were fixed since March.Rumpf
" but only in debug mode" I am pretty sure this happens in release also, but it is silent failure.Ubiquitarian
@StoryTeller You're right. That would be silly of me. I just don't know if this is a VS bug or something particular to my system. Maybe I should do M.M said and file a bug report even though I'm not sure it's a bug?Vendue
You should. In this particular case, it may at most be consolidated with another bug report. You seem to grasp inline variables well, no need for self doubt.Rumpf
developercommunity.visualstudio.com/content/problem/261624/…Hyperemia
@Hyperemia Wow, thank you for finding that. It's surprising such an obvious issue could slip through. And that comment on September 7 about Clang having the same problem, amazing.Vendue
@Zebrafish: Since you have confirmed this, I will write a short answer indicating the same so that this question can be moved out of the list of unanswered questions.Hyperemia
H
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.

Hyperemia answered 15/10, 2018 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.