You are invited to Log in or Register a free Frihost Account!

Help debugging C++ program

An odd query, I guess. I'm not asking about programming principles, per se, more if someone could take a few minutes to look at the source code of my project:

and tell me why the program segfaults on line 59 of song.cpp if next_event_time is larger than 0.

Alternatively, if someone could tell me how to coax gdb into showing me more than:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1217710384 (LWP 24341)]
0x08059188 in jdkmidi::MIDISequencer::GetNextEvent ()
(gdb) bt
#0  0x08059188 in jdkmidi::MIDISequencer::GetNextEvent ()
#1  0x08051147 in PlayDumpSequencer (main_fretboard=0x860bb20, seq=0x858ec40,
    clock_time=488, last_time=485) at src/song.cpp:59
#2  0x08051377 in song::update (this=0x858b908) at src/song.cpp:859
#3  0x08053e1b in Gshik::main (this=0x8062d84, argc=1, argv=0xbffd22d4)
    at src/main.cpp:174
#4  0xb7eddc36 in main (argc=1, argv=0xbffd22d4) at Unix/clanapp.cpp:47
#5  0xb79f1ebc in __libc_start_main () from /lib/tls/i686/cmov/
#6  0x0804ad81 in _start ()

(i.e., where in jdkmidi::MIDISequencer::GetNextEvent does the segfault occur?

Sorry about my inability to generalise this into a more readable example, but the complexity of the code is perhaps the reason for the bug.


An segmentation fault normally happens if you did not initialize a pointer or if you exceed the limits of a memory block.

For analyzing the code, you must use the code, not the dump you posted here. In your code line 59 of song.cpp, an error occurs. Now you have to look, if every pointer you use is initialized, if your reserved memory blocks are not to small and so on.

It is quite a lot of work, but you have to do this.


This is not really going to be helpful now unless you're planning on rewriting the entire program, but maybe it might help in any future code you write.

i haven't actually used a debugger in years because i haven't had a need to. i don't write perfect code, but i code defensively and use a pair of techniques called test driven design (TDD) and design by contract (DbC). They catch all of the errors right away, so i don't end up with mysterious bugs or segmentation faults.

TDD takes the most work, but the idea is you get a test framework (i use Boost.Test, but others swear by CppUnit) and use that to make your code work. So say you're writing a function to collapse the whitespace in a string (simple example). You want your function to look like:
void collapse_whitespace(std::string&);
but before you write a line of actual code for that function, you write the test suite:
#include <boost/test/unit_test.hpp>

#include "whatever header collapse_whitespace() is declared in"

using boost::unit_test::test_suite;

void test_collapse_whitespace();

test_suite* init_unit_test_suite(int, char* [])
   test_suite* test = BOOST_TEST_SUITE("Really short test suite for one function");
   // We're only testing one function here
   return test;

void test_collapse_whitespace()
   // Make as many tests as you want
   int const num = 3;
   std::string const strings[num][2] = { { "", "" },
                                         { "abc", "abc" },
                                         { "a     b    c", "a b c" } };
   // Run them all
   for (int i = 0; i < num; ++i)
      std::string test(strings[i][0]);
      BOOST_CHECK_EQUAL(test, strings[i][1]);
then you write collapse_whitespace() so that it satisfies the test suite.

Most people balk when they see that method, saying that it's a lot of work. Maybe so, but personally i think hunting down segmentation faults with a debugger is far more work.

The second technique, DbC, is far less work. The idea is simply that you write a bunch of assert() statements at the beginning and end of every function you write, and before and after every call to most functions. You treat every function like a black box and just make sure that no matter what happens, what goes in is what you expect to go in - and the same for what comes out. For example, suppose you were writing a simple function to find the volume of a sphere:
double volume(double radius)
   assert(radius != INF);
   assert(radius != NAN);
   assert(radius >= 0.0); // radius can't be negative
   // Whatever other tests you think you need
   // V = 4/3 * PI * r^3
   double r_cubed = std::pow(radius, 3.0);
   assert((radius > 1.0) ? (r_cubed > radius) :
      ((radius < 1.0) ? (r_cubed < radius) : (radius == 1.0)));
   double volume = 4.0 / 3.0 * M_PI * r_cubed;
   assert(volume != INF);
   assert(volume != NAN);
   assert(volume >= 0.0); // volume can't be negative
   return volume;
then later on in the main program, you goofed and did:
double x = 2.0;
int y = 0;

// Lots of code

x /= y; // Oops, x is INF

x = volume(x);

// Lots of code

// And here you find a problem with x
That's the kind of error you can spend hours and hours tracing down, tracking it slowly back up to volume(), then into volume and so on. But with the DbC asserts in place, the problem shows up immediately, exactly where it happens (or really close to it). (Of course, these examples are kind of silly and anal, but they should give the general idea, i hope.)

Most people say that's too much work and they don't bother, but when it comes to debugging either you put the effort in before compiling or after... and it's a whole lot easier to do it before (gives you much more solid programs too). And if you write games, all of this code - both for TDD and DbC - goes away in a final build, so there's zero overhead.
Well you can both have an e-cookie for being more helpful than Rolling Eyes

makli, the problem is that gdb, despite some "--directory" instructions, won't tell me the line of source code *in* libjdkmidi that's causing the problem. I know exactly what statement in song.cpp is bailing, and all the variables passed to it seem to be in order, but I need to look inside the external lib (for which I do have source-code)

Indi, those are incredibly useful tips, and I'll be making heavy use of (at least) assert() from now on. But the problem here is that I'm sure the function's input is sane, having printed it out etc.
Good news, everyone! I taught the toaster to feel love.

Also, I fixed this. Turns out I accidentally changed my makefile to point to a venerable version of libjdkmidi in /usr that didn't work so much as... crash every 15 seconds.

Thanks for the help; I'm sure it'll come in handy next time I make an error!
Indi, is there a way of asserting that a value has been set?

void foo (int number)
cout << number << endl; // Number must have been set

int main()
int a;
foo(a); // This shouldn't be allowed
simplyw00x wrote:
Indi, is there a way of asserting that a value has been set?

void foo (int number)
cout << number << endl; // Number must have been set

int main()
int a;
foo(a); // This shouldn't be allowed

No, unfortunately not directly. There are two imperfect solutions to the problem, but combined they should mostly do the trick.

First, never, ever, ever create a variable without setting it to a value. You can set it to a sane default, or to an invalid value, depending on what you're doing. (Normally you should be creating variables as close to where they are being used as possible, so there is often no reason to use a default value - you can just initialize it with the desired value right from the start.)

Second, if there is an expected range of values for foo(), you can test for that. For example, if foo() was a function to print someone's age, you could do:
void foo(int number)
   assert(number > 0);
   assert(number < 150);
   cout << number << endl;

But if foo() can take any number, then that won't work.
Related topics
A C program in Linux
A C program in Linux
C program with 3D array, in Linux
CLOSE PLEASE-Need a C++ program - upto 200frih$
[C] Splitting names program
need help debugging C++ script.
Deploying a C# program
how to check if a file exists. please help (visual basics 6)
changing system time using a c program under cygwin
C++ Software
C++ Program Basics
Help With C++ Searching
Writing your first C++ Program
My Small C# Program
Reply to topic    Frihost Forum Index -> Scripting -> Others

© 2005-2011 Frihost, forums powered by phpBB.