views:

915

answers:

2

I have some file writing code that works as expected, but prints an error on Debug mode, no output errors in Release.

Code:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

int main (int argc, char * const argv[]) {
    string cppfilename; 
    std::cout << "Please enter the filename to create: ";

    while ( cppfilename == "" ) {
        getline(cin, cppfilename);    // error occurs here
    }

    cppfilename += ".txt";
    ofstream fileout;
    fileout.open( cppfilename.c_str() );
    fileout << "Writing this to a file.\n"; 
    fileout.close();

    return 0;
}

Debug Output:

Please enter the filename to create: Running…
myfile
FileIO(5403) malloc: *** error for object 0xb3e8: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Created: myfile.txt

Release Output:

FileIO implementation C++
Please enter the filename to create: Running…
myfile
Created: myfile.txt

Aside from not checking for the file descriptor being open (for simplicity) what is wrong with this code?

Update: I broke the code down to the following and it still errors:

 string cppfilename; 
 getline(cin, cppfilename);    // error here
+5  A: 

This looks to be another case of _GLIBCXX_DEBUG being broken with gcc 4.2 on Mac OS X.

Your best options look to be to drop _GLIBCXX_DEBUG or to switch to gcc 4.0.

R Samuel Klatchko
Well, damn. All that time to investigate and write up a long, detailed answer, and it happens that there's another answer right here on SO that says that this is a known problem. I feel silly now.
Brian Campbell
I changed the compiler in Xcode to 4.0 and it fixed the problem. Many thanks
Brock Woolf
+5  A: 

This looks to me like a bug in Apple's libstdc++, at least when compiled in debug mode. If I compile the two line reduction you gave above:

#include <iostream>
#include <string>

using namespace std;

int main() {
  string cppfilename; 
  getline(cin, cppfilename);    // error here

  return 0;
}

With the following command line (with defines taken from Xcode's default settings for a Debug build in a C++ project):

g++ -D_GLIBCXX_DEBUG=1 -D_GLIBCXX_DEBUG_PEDANTIC=1 -g -o getline getline.cpp

Then I get the same error that you saw:

$ ./getline foo
getline(74318) malloc: *** error for object 0x1000021e0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap

This pops up a crash report, which gives us a stack trace (you can also get a stack trace from the debugger by running this under Xcode; I just wanted to reproduce it in as clean an environment as possible, to try and isolate the cause, without anything else strange Xcode might be doing):

Thread 0 Crashed:  Dispatch queue: com.apple.main-thread
0   libSystem.B.dylib               0x00007fff83c37fe6 __kill + 10
1   libSystem.B.dylib               0x00007fff83cd8e32 abort + 83
2   libSystem.B.dylib               0x00007fff83bf0155 free + 128
3   libstdc++.6.dylib               0x00007fff813e01e8 std::string::reserve(unsigned long) + 90
4   libstdc++.6.dylib               0x00007fff813e0243 std::string::push_back(char) + 63
5   libstdc++.6.dylib               0x00007fff813c92b5 std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, char) + 277
6   getline                         0x00000001000011f5 std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) + 64 (basic_string.h:2451)
7   getline                         0x0000000100000cbf main + 34 (getline.cpp:10)
8   getline                         0x0000000100000c04 start + 52

This looks an awful lot like a bug to me. We're using some standard library functions in the most trivial possible way, and hitting an assertion failure.

At this point, if we were using proprietary software (which much of Apple's software is, but luckily libstdc++ is free software), we would have to give up, file a bug report with our vendor, and try to find a workaround. Luckily, this is free software, so we can investigate the root cause. Unfortunately, I don't have the time at the moment to track this down to the root cause, but the source is available for perusal.

You should probably file a bug about this. A workaround in this case would be to remove the _GLIBCXX_DEBUG=1 definition (and probably the _GLIBCXX_DEBUG_PEDANTIC=1 as well). You can do this in Xcode by finding your Target, double clicking on the executable it builds, going to the build tab, making sure the configuration is set to Debug, scrolling down to the GCC 4.2 - Preprocessing section, and deleting the two values from the Preprocessor Macros line. This way the code will build and run, and seems to work in this case, but you'll get fewer assertions that the debug build of the standard library might have been able to catch.

Brian Campbell
Wow thanks for such a comprehensive answer Brian. I have to give you +1
Brock Woolf