gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > Clean compile core dump

#8676 - sgeos - Thu Jul 17, 2003 8:51 pm

I ran into a nasty bug last night, and I figured I'd share it. The neat thing about this bug is that the code compiles with no warnings or errors, but dumps core. See if you can spot the bug.

Code:
#include <stdio.h>

int main(void)
{
  int ctr;

  for (ctr = 0; ctr < 16; ctr++)
  {
    printf("%2d)   ", ctr);
    printf("%3d ~ %3d   ", ctr * 8 + 15, ctr * 16 + 15);
    printf("%3d ~ %3d   ", ctr * 10 + 50, ctr * 25 + 100);
    printf("(8 / %2d)", 50 / ctr + 15);
    printf("\n");
  }
  return 0;
}


-Brendan

#8679 - Darryl - Thu Jul 17, 2003 9:56 pm

That is funny I just compiled your code on a Unix box with just the basic compile flags and ran it without producing a core. This is the output...

Code:
 0)    15 ~  15    50 ~ 100   (8 / 15)
 1)    23 ~  31    60 ~ 125   (8 / 65)
 2)    31 ~  47    70 ~ 150   (8 / 40)
 3)    39 ~  63    80 ~ 175   (8 / 31)
 4)    47 ~  79    90 ~ 200   (8 / 27)
 5)    55 ~  95   100 ~ 225   (8 / 25)
 6)    63 ~ 111   110 ~ 250   (8 / 23)
 7)    71 ~ 127   120 ~ 275   (8 / 22)
 8)    79 ~ 143   130 ~ 300   (8 / 21)
 9)    87 ~ 159   140 ~ 325   (8 / 20)
10)    95 ~ 175   150 ~ 350   (8 / 20)
11)   103 ~ 191   160 ~ 375   (8 / 19)
12)   111 ~ 207   170 ~ 400   (8 / 19)
13)   119 ~ 223   180 ~ 425   (8 / 18)
14)   127 ~ 239   190 ~ 450   (8 / 18)
15)   135 ~ 255   200 ~ 475   (8 / 18)


Where did it core on you? Obviously this isn't GBA code with the printf in there.
_________________
Something is only impossible until someone does it the first time.

#8682 - sgeos - Thu Jul 17, 2003 10:53 pm

Darryl wrote:
That is funny I just compiled your code on a Unix box with just the basic compile flags and ran it without producing a core. This is the output...


Clearly your compiler isn't quite as mean as mine is. There is a bug in the code that could hang the GBA from what I've heard, perhaps depending on what the compiler does with it. (I'll wait a while before I give it away.) Thanks for the output though, I was expecting something like that.

Darryl wrote:
Obviously this isn't GBA code with the printf in there.


I do a lot text/curses stuff off the gba and then port it later. (I'd use siprintf on the gba, with a custom output function.)

-Brendan

#8685 - Darryl - Fri Jul 18, 2003 12:37 am

I see it now the division by zero in the first iteration of the loop will cause traps, cores or GPFs on various systems. Depending upon the hardware you run and the compiler you use, it will handle this exception differently.

On the machine and compiler that I used to test, division by zero is a well defined construct (it produces 0 as a result and sets a flag to indicate that it occurred). Recompiling with the option that forces a core dump when division by zero occurs produced a core for me as well.

You gotta love those default compiler options.
_________________
Something is only impossible until someone does it the first time.

#8687 - sgeos - Fri Jul 18, 2003 1:10 am

You got it. It's a simple divide by zero bug.

What struck me as exceptionally nasty about this bug was just how covert it was. No warnings or errors, hidden in fairly clean code in a loop in a small program. =P

From what I understand, dividing by zero using the bios call hangs the GBA.

The simple fix for divide by zero in loops is:
Code:
for (ctr = 0; ctr < n; ctr++)
  if (ctr)  // This is the fix
    printf("%d\n", 20000 / ctr);  // or your divde by zero thing


-Brendan

#8693 - Nessie - Fri Jul 18, 2003 3:58 am

Huh? I don't ever recall any of the various compilers I've used (for numerous different platforms) ever providing any sort of warning about a potential divide by zero. I mean, maybe it would if you coded something like:

printf( "%d\n", 5 / 0 ); // evaluated compile time

or:

#define ZERO 0
printf( "%d\n", 5 / ZERO );

but I'm not sure it would for:

int blah = 0;
printf( "%d\n", d / blah ); // evaluated run-time? probably depends on compiler?

I guess it all depends on whether the compiler evaluates the expression at compile time or if it would get evaluated run-time. Granted, a smart compiler could optimize the third example, assuming just those two lines, but I'd imagine that would only happen with the simplest of code samples....

Still, I wouldn't expect the compiler to catch something like that for me. And yes, I've been bitten by the "order of operations" bug before...based on these bugs, I have gotten in the habit of using parenthesis to group expressions even when not really necessary.

#8695 - sgeos - Fri Jul 18, 2003 4:26 am

Nessie wrote:
Huh? I don't ever recall any of the various compilers I've used (for numerous different platforms) ever providing any sort of warning about a potential divide by zero.


Nor should a warning necessarily be issued. Consider the following:
Code:
int divide(int a, int b)
{
  return a / b;  // or replace this with the bios divide
}


To the extent that a divide by zero invokes undefined bahavior, it is generally not a cool scenario. My compiler decided to dump core, which is more effective than a warning. Darryl's compiler, by default, subbed zero. (Which would have worked for me.)

-Brendan

#8705 - Darryl - Fri Jul 18, 2003 1:42 pm

Various enterprise level compilers when set to the highest error checking level will perform division by zero checks on static values. It would pick up on this error in this example.

The key word here is static values. Values read in a runtime (by user entry, flat files, ect) will not be caught. Some compilers will allow you via complier switches to define the output of an ANSI C "undefined result". These types of features is how the complier companies can get away with charging the big bucks compared to the standard or professional releases.
_________________
Something is only impossible until someone does it the first time.

#8731 - tepples - Fri Jul 18, 2003 6:04 pm

My wrapper around BIOS divide will return INT_MAX if the divisor is zero. This is useful for coordinate transformation applications where division by zero is a valid operation that results in a projective infinity.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.