.qc (dot qc) - the group for quake c coders of all denominations. If you make quake one mods and write code in quake c, join our group! I'll try to answer any quake c questions - please post your inquiry in the forums...

  • View media
  • View media
  • View media
  • View media
  • View media
  • View media
Add media Report RSS Quake c - gone bad #A (view original)
Quake c - gone bad #A
embed
share
view previous next
Share Image
Share on Facebook Post Email a friend
Embed Image
Post comment Comments
numbersix Author
numbersix - - 2,244 comments

This was a bot match test (6 bots) running for 2 days after the alpha release of Archon: Moddb.com

One thing I dont want to see with officially released code (even if it is alpha) is this kind of nasty server crash.

What happened here?

A bot got a morph cube, turned into a zombie and fired off a cloudkill (a new kind of weapon morphed player zombies have access to.) Cloudkill is a noxious area affect that afflicts any player in range with continuous minor damage.
Running into one while low on health or being attacked is a death sentence.

We can see from the server crash dis-assembly that somewhere in the cloudkill function around the cparticle_lorg conditional test an infinite loop occurs.

Here is the code fragment (forgive the comment block for stripping the tabs):

if (DARKPLACES) // clouds from mdl
{
local entity e;
head = findradius(self.origin, self.distance * mult);
f = TRUE;
if (clc > 15)
while (head && f)
{
if (head.classname == "clouds")
if (vlen(head.origin - cparticle_lorg) < 10)
f = FALSE;
head = head.chain;
}

// rest of conditional code - makes clouds
}

In the case of the darkplaces engine (first conditional test) a model is used to generate the cloud appearance - since quake one still doesnt have volumetric fog.
What this test does is see if we can make more clouds.

Reply Good karma+1 vote
numbersix Author
numbersix - - 2,244 comments

The while () statement is our (potentially infinite) loop.
To exit the loop, either head must be set to world (0 entity) or f must be set to FALSE by the contditional. Since head is set by findradius, it should be a given that eventually some head.chain (findradius links a set of entities in the given range together via .chain) will have the value world - meaning no more entities are left in range to test.

An infinite loop here means the .chain sequence has no end (loops to itself) and the conditional never sets f to FALSE. Oops.

Here is the fix:

head = findradius(self.origin, self.distance * mult);
f = 200;
if (clc > 15)
while (head && f > 0)
{
if (head.classname == "clouds")
if (vlen(head.origin - cparticle_lorg) < 10)
f = FALSE;
head = head.chain;
f = f - 1; // safety - Cat - 10.29.12
}

Now f will count down to 0 if it is not assigned the FALSE condition first. Even if head.chain does not end in value world, the loop will exit.

Whenever you have a quake-c loop with various conditional exit tests, putting in a countdown variable as a safety and making it part of the loop test is a good way to limit the loop run. You must simply estimate the maximum number of loops to accomplish your purpose.

Reply Good karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account:

Description

I've already showcased the infinite loop fail. Here I'll add a comment showing how I put in a fix for the latest one.