.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...
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.
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.
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.