Search code examples
c++abortcodecvt

Abort in wifstream destructor


The following C++ code gets a mysterious error ("Debug Error!...abort() has been called") when the return is executed. This is Visual Studio 2017 15.6.3, and the program is a 64-bit debug build, running under 64-bit Windows 7. What is causing this error, and how can I fix it?

wifstream inFile;

std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian> cv1;
inFile.imbue(std::locale(inFile.getloc(), &cv1));
return 0;

Tracing through with the debugger shows the message is coming from the disassembler instruction

call        std::basic_ifstream<wchar_t,std::char_traits<wchar_t> >::`vbase destructor'

The last entry on the stack, other than msvcp140d.dll, vcruntime140d.dll and ucrtbased.dll is

    MyApp.exe!std::basic_ifstream<wchar_t,std::char_traits<wchar_t> >::`vbase destructor'() C++

The purpose of this code is the input file infile is Unicode (little-endian), and I am reading it into a std::string variable.


Solution

  • std::locale maintains a reference count for each facet that is associated with it. The std::locale constructor you are calling will increment a reference count for the std::codecvt_utf16 object you are passing in, and then std::locale's destructor will decrement that reference count. When the reference count of the std::codecvt_utf16 falls to 0, it will be destroyed via the delete operator. That is why you are getting the abort error - when the std::wifstream destructor is cleaning up the imbue'd locale, the locale's destructor tries to delete something that was not allocated with the new operator to begin with.

    Do this instead:

    inFile.imbue(std::locale(inFile.getloc(),
        new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));
    

    See the example in the std::codecvt_utf16 documentation on cppreference.com.