Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2002-09

The inexplicable overflow.

6 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Unknown author

Hi,
The game I am working on is actually nearing completion. My enemy ruleset is virtually complete and they can always find the player, though not quite by the shortest path yet, the version now uses a very simple AI. I check wether the enemy is above or below the player, then work out the enemy's true line of site and try to head for the closest route up or down (as the case may be) within that.

However one enormous bug keeps foiling me. This affects only the player (which is wierd since the program doesn't actually know the difference between the player and the enemies, they are just different instantiantiouns of the same object - the only difference is that player status is set by asynchronous keyboard commands, and the enemies are controlled by a simple AI procedure).
The program makes use of two sets of coordinates for each character, including the player. X and Y stores the character's virtual location on the map, where is an SDL_Rect which stores it's actual screen location, X and Y is easy to work out as I know the borders of each tile and can change them whenever a character passes a border( e.g. if where.X = 62 then X := 1).

However mysteriously the where.Y value is throwing getting a very strange overflow. This is completely unrelated to any keyboard input (since not hitting any keys still causes it to happen). The overflow happens
instantaneously, and since Where.Y is an unsigned integer (SDL) it becomes ZERO dumping the player in the top line of the screen, mysteriously the program keeps running, but X and Y do not change (as can be veryfied by the fact that although stuck on the top line, you are still bound by the physics of the line you were on when it happened.) This can only be since 0 is not a tile border and therefore the setXY procedure ignores it.

I have added a whatch on where.y which was only usefull in that it confirmed my suspiciouns -there is indeed an overflow happening. Furthermore this often happens while the player is standing still or
the where.Y value should not
even be a hunch I added a temporary variable - increased on each alteration of the gameloop, and thus was able to determine the only common factor between occurences of the error - it always happens after the gameloop has run 1900 times and before it gets to 2100. I cannot determine the exact point (asuming that there is one) because the loop is too fast. However I have yet to get it happening before 1900 or after 2100.

Any idea what could cause this.

I have spent the last three days trying to find it. It is easy to fix a bug if you can figure out what causes it, but I cannot even come up with a theory this time (which is very infuriating) I have checked and rechecked every line of code that looks at or alters the value of where.Y and I cannot find anything like this.

If anybody would like to look at the source, as usual, I am working open-source and will share on request until release time - and all helpers will be credited.

PS. Thanks a bundle for the tips on the last run, my program now runs exponentially faster and never crashes

mail2web - Check your email from the web at
http://mail2web.com/ .

Reply by email

Lee, John

Assume you've tried compiling everything with -gl (and/or with the various range checking eg -Cort enabled) & running. This will tell you the line at which the overflow happens.

Regards john
------------------------
If anybody would like to look at the source, as usual, I am working open-source and will share on request until release time - and all helpers will be credited.

PS. Thanks a bundle for the tips on the last run, my program now runs exponentially faster and never crashes

mail2web - Check your email from the web at
http://mail2web.com/ .

Reply by email

A.J. Venter

Hi,
If followed the advice presented and recompiled with range checking and overflow checking on. My program subsequently caused a near immediate 201 crash.
The compiler issues this warning:

minerunner.pas(95,56) Warning: Mixing signed expressions and cardinals
here may cause a range check error

Line 95 looks like this:
If (level.block[blockX,blockY].what = pit) And
(SDL_Getticks > level.block[blockX,blockY].digtime + 10000) Then

The code in question steps through the level, looking for pit's (holes dug by the player) and when it finds them the if statement above is used to compare the time when the hole was dug with the current time, if more than 10 secconds elapsed the hole is filled up again.

It is interesting that a different problem occurs if I turn on integer overflow checking and not range checking, the program then fails in characters.draw (though I cannot determine which character is being drawn when it happens).

What I would love to do is a line by line step over and execute like you could in BP, however GDB refuses to step unless you run the program - which then happens without a pause until the program exits or waits for input - since the game's input is asynchrounous it never waits for input.

Is there anyway to do this ? So I can step over the code and determine the exact moment of the errors - which when combined with a few whatches should allow me to solve them.

TIA
A.J. Venter

------------------ "If you can't beat your computer at chess - do what I did. Try kickboxing" Anonymous A.J. Venter www.headrush.co.za

Reply by email

Pierre Muller
to A.J. Venter

At 10:03 27/09/2002 , vous avez écrit:

Show quoted text 32 lines
Hi, If followed the advice presented and recompiled with range checking and overflow checking on. My program subsequently caused a near immediate 201 crash. The compiler issues this warning: minerunner.pas(95,56) Warning: Mixing signed expressions and cardinals here may cause a range check error Line 95 looks like this: If (level.block[blockX,blockY].what = pit) And (SDL_Getticks > level.block[blockX,blockY].digtime + 10000) Then The code in question steps through the level, looking for pit's (holes dug by the player) and when it finds them the if statement above is used to compare the time when the hole was dug with the current time, if more than 10 secconds elapsed the hole is filled up again. It is interesting that a different problem occurs if I turn on integer overflow checking and not range checking, the program then fails in characters.draw (though I cannot determine which character is being drawn when it happens). What I would love to do is a line by line step over and execute like you could in BP, however GDB refuses to step unless you run the program - which then happens without a pause until the program exits or waits for input - since the game's input is asynchrounous it never waits for input. Is there anyway to do this ? So I can step over the code and determine the exact moment of the errors - which when combined with a few whatches should allow me to solve them.

Why don't you simply use the FP IDE?

Its gdb surrounded by an editor (similar to BP editor) and you can set breakpoints
by using Ctrl-F8 key,
after this you Run the program at it will stop when it comes to your breakpoint. For that point you can use F7 to 'step into' or F8 to 'step over' If you need more details on what is going on,
you can get a mixed source/assembler window
by first calling the 'Debug|Call stack' (Ctrl-F3)
and then Alt-I key...
Inside this window F7 behave like a instruction step and F8 like GDB nexti (instruction step, but
without stepping inside called func/procedures...)

If you never used the IDE before,
you will need first to configure your IDE to get your program to compile correctly.
For this:
1) select Debug mode in "Options|Mode" menu.
2) select the native target in 'Compiler|Target'
(you can not cross debug.. with the IDE)
3) set all options in 'Options|Compiler'
4) set all directories in 'Options|Directories'
5) Compile with 'Compile|Build'
(this way ou will add debug information to most of the units that you use).

Once that is done, you can go on with the list above.

Reply by email

A.J. Venter
to Pierre Muller

On Fri, 27 Sep 2002, Pierre Muller wrote:

After significant further searches and hacking the problem still evades me. However, I have since learned that it is apparently not an overflow.

The value certainly does switch to maxint and then to 0 (which is why I thought it was an overflow) but compiling with range checking and overflow checking does not crash the program when it happens.

In other words, it hits maxint and then 0 but never exceeds maxint. What's even funnier is that it does not build up to maxint, it simple becomes it out of the blue and without warning.

I went so far as to do a text search for the line where.Y throughout all the source code, but I didn't find any lines accessing this value directly except the two which are changed when a character move, and these are just inc and dec's. If the problem was here, then surely it could not reach maxint directly - especially as these lines are often not being executed at the time of the bug.

The most perplexing thing remains the fact that only the player seems to suffer this, the enemies (like I said, different instantiations of the same object) are completely untouched.

I will asume by now that nobody here is interested in joining the project (hint, hint) and just hope for some good advice.

Thank you all though, the advice from this list has solved many, many problems for me over a very long time.

Ciao
A.J. Venter

Reply by email

Pierre Muller
to A.J. Venter

At 15:28 27/09/2002 , vous avez écrit:

Show quoted text 29 lines
On Fri, 27 Sep 2002, Pierre Muller wrote: After significant further searches and hacking the problem still evades me. However, I have since learned that it is apparently not an overflow. The value certainly does switch to maxint and then to 0 (which is why I thought it was an overflow) but compiling with range checking and overflow checking does not crash the program when it happens. In other words, it hits maxint and then 0 but never exceeds maxint. What's even funnier is that it does not build up to maxint, it simple becomes it out of the blue and without warning. I went so far as to do a text search for the line where.Y throughout all the source code, but I didn't find any lines accessing this value directly except the two which are changed when a character move, and these are just inc and dec's. If the problem was here, then surely it could not reach maxint directly - especially as these lines are often not being executed at the time of the bug. The most perplexing thing remains the fact that only the player seems to suffer this, the enemies (like I said, different instantiations of the same object) are completely untouched. I will asume by now that nobody here is interested in joining the project (hint, hint) and just hope for some good advice. Thank you all though, the advice from this list has solved many, many problems for me over a very long time.

There answer to your problem is probably much
easier to find if you use another feature of GDB:
'watchpoints'
A watchpoint in GDB sense (as opposed to the IDE sense) is an expression that is evaluated and
checked for changes.
This expression can be rather complex and invole checked several memory locations.

In your case, it seems that its simply a globabl variable that suddenly gets set to an unexpected value....
This is the best case of use of GDB watchpoints.

So using command line GDB
you should use
(gdb) watch BLOCKY
or from inside the IDE you should use
"Debug|Breakpoint list"
Select "New" button
insert BLOCKY in name filed and set
type field to watch.

Running the program after setting this watch will
make gdb stop the program whenever the
value of the watched expression is changed.

If you get too many stops, you could try to add a
condition (for instance BLOCKY = 0)
so that it only stops when the unexpected value is set.

It might well be that you variable is
changed by some write operation in a released
heap fragment that has been reused by the heap manager....

If your expression is not too complex,
the watchpoint will be a hardware watchpoint,
which means that it works really quickly.
Otherwise the program gets really slow, because its is run instruction by instruction....

Hoping that this will help you to find your problem.

Reply by email