Professional C__ - Marc Gregoire [470]
>gdb buggyprogram
[ Start-up messages omitted for brevity ]
Reading symbols from /home/marc/c++/gdb/buggyprogram...done.
(gdb) run
Starting program: buggyprogram
Enter a file name ("STOP" to stop): paper1.txt
[ correct output of reading paper1.txt omitted for brevity ]
Enter a file name ("STOP" to stop): paper2.txt
Program received signal SIGSEGV, Segmentation fault.
0x06a87bdc in std::basic_string (gdb) When the program crashes, the debugger breaks the execution, and allows you to poke around in the state of the program at that time. The bt command shows the current stack trace. Such a stack trace shows the last operation at the top, with frame number zero, #0: (gdb) bt #0 0x06a87bdc in std::basic_string #1 0x06a87cb5 in std::basic_string #2 0x080492ba in ArticleCitations::ArticleCitations (this=0xbffff2c4, src=...) at ArticleCitations.cpp:24 #3 0x080499ba in main (argc=1, argv=0xbffff384) at ArticleCitationsTest.cpp:20 When you get a stack trace like this, you should try to find the first stack frame from the top that is in your own code. In this example, this is stack frame #2. From this frame you can see that there seems to be some sort of problem in the ArticleCitations copy constructor. This copy constructor is invoked because the main() function calls processCitations() and the argument is passed by value. Of course, in production code you should pass a const reference, but pass-by-value is used for this example of a buggy program. You can tell the debugger to switch to stack frame #2 with the up command, which requires an argument specifying how many frames to go up: (gdb) up 2 #2 0x080492ba in ArticleCitations::ArticleCitations (this=0xbffff2c4, src=...) at ArticleCitations.cpp:24 24 mCitations[i] = src.mCitations[i]; This output shows that the following line caused a problem: mCitations[i] = src.mCitations[i]; Now, use the list command to show the code in the current stack frame around the offending line: (gdb) list 19 mNumCitations = src.mNumCitations; 20 // Allocate an array of the correct size 21 mCitations = new string[mNumCitations]; 22 // Copy each element of the array 23 for (size_t i = 0; i < mNumCitations; i++) { 24 mCitations[i] = src.mCitations[i]; 25 } 26 } 27 28 ArticleCitations& ArticleCitations::operator=(const ArticleCitations& rhs) In gdb, you can print values available in the current scope with the print command. In order to find the root cause of the problem, you can try printing some of the object member variables. The error happens inside the copy constructor, so checking the value of the src parameter is a good start: (gdb) print src $3 = (const ArticleCitations &) @0xbffff2b4: {mArticle = "Author with no citations", mCitations = 0x804c00c, mNumCitations = 5} Ah-ha! Here’s the problem. This article isn’t supposed to have any citations. Why is mNumCitations set to 5? Take another look at the code in readFile() for the case that there are no citations. In that case, it looks like it never initializes mNumCitations and mCitations! They are left with whatever junk is already in those memory locations. In this case, the previous ArticleCitations object had the value 5 in mNumCitations. The second ArticleCitations object must have been placed in the same location in memory and so received that same value.