0

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.

Drise
  • 4,310
  • 5
  • 41
  • 66
Woody20
  • 791
  • 11
  • 30
  • 2
    This "program" is not a program; it's a code snippet. Add just enough code so that it compiles and runs and shows the problem. – Pete Becker Mar 21 '18 at 17:48
  • 1
    If you're trying to use the stream you imbued using `cv1`'s address after it has been destroyed, its likely to fail. But we can't tell that until we've seen your [mcve]. You've been here for long enough to understand why one is required. – Toby Speight Mar 21 '18 at 17:54

1 Answers1

1

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Tnx for your prompt (and correct!) response. When I compile your code, I get an `error C2661: 'std::_Crt_new_delete::operator new': no overloaded function takes 3 arguments`. This comes from `#ifdef _DEBUG / #define new DEBUG_NEW / #endif`` that Visual Studio puts into a dialog source file. Removing that compiles and runs without error. So there is some Visual Studio incompatibility. – Woody20 Mar 21 '18 at 19:55
  • The code I presented doesn't pass 3 arguments to `new`, it should compile no matter what `new` is defined as. Otherwise VS is breaking core language functionality. What is `DEBUG_NEW` defined as? I don't use VS. – Remy Lebeau Mar 21 '18 at 20:10
  • `#define DEBUG_NEW new(THIS_FILE, __LINE__)`, and `#define THIS_FILE __FILE__`. And, yes, it is a bug in VS, which I will report. Nothing wrong w/your code! – Woody20 Mar 22 '18 at 18:39
  • The only way that such a `DEBUG_NEW` could work like this is if there is an overloaded `operator new` in scope that takes 3 parameters: `void* operator new (size_t size, const char *filename, int line)` (see [this example](https://stackoverflow.com/a/583079/65863)). It sounds like that is not actually the case in your situation, which would explain the compiler error you are seeing. – Remy Lebeau Mar 22 '18 at 19:05