HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Timer bug denialism

03-10-2009, 08:59 AM#1
xombie
I was reading up on some bugs that occur (specifically when destroying a trigger before it is done being used) and it seems like you need a TriggerSleepAction in order to make it bug. What exactly is the problem with timers?

Collapse JASS:
function SomeTriggerGotExecuted takes nothing returns nothing
    // if you have a wait, nothing will work properly after it - this is basic
    // thread logic because a wait will kill the thread. However, if there is
    // no wait then it should execute properly - so where is the problem
    // with timers?
endfunction

function SomeFunction takes nothing returns nothing
    call TriggerExecute(someTrigger)
    call DestroyTrigger(someTrigger)
endfunction

This is more or less a reproduction of what can screw up triggers. I fail to see how (unless you do something that would logically result in a bug, as seen above) timers would get bugged up. Part of the reason I am skeptical at all is because I have never, ever had a single problem with any of my timers ever not doing anything other than exactly what they were supposed to.
03-10-2009, 10:20 AM#2
Pyrogasm
If I remember correctly, I think it has to do with timers being destroyed and not getting removed from the handle stack properly (thus permanently increasing the handle count), or being prematurely removed from the handle stack (so two handles have the same ID).

This is simply a facet of DestroyTimer() and what setting a timer variable = null does.
03-10-2009, 10:27 AM#3
xombie
So what you're saying is that it is a bug in blizzard's engine? I find it strange that there is such a bug yet in years upon years of using timers I have not once encountered any problems. The reason I ask is because I want to be certain that its not just the flaw of the user, doing something that should not be done (such as the example I posted before).
03-10-2009, 10:33 AM#4
Pyrogasm
The 'flaw' of the user would be setting timer variables to null and destroying timers.

I personally have not encountered this either, but if you want an example play some of the middle-ish versions of AotZ. There are a lot of timer-caused bugs in there, which is why Dusk wants to recode it for 3.0
03-10-2009, 10:43 AM#5
xombie
Yea, but he also uses TriggerSleepActions, which aren't safe at all. It seems like these "bugs" only pop up in places where they are accompanied by other unsafe actions.
03-10-2009, 10:53 AM#6
Pyrogasm
There was a thread recently where we (by "we" I mean people who are not me, because I don't know too much about this) were discussing some of these infamous bugs and trying to figure out which of them were related to each other or were, in fact, the same bug.

I'll look for it.

Edit:http://www.wc3c.net/showthread.php?t=104679 Post #24
03-10-2009, 11:16 AM#7
xombie
It seems like it might still be kind of iffy though, like it is possible that if you're map is completely stable you won't get this bug, even though you may or may not recycle timers. I don't know, it really does not affect my life that much. The only difference it would make is if I tried to submit something that did not use TimerUtils to the site - because based on common belief timers are not safe.
03-10-2009, 01:24 PM#8
Vexorian
Quote:
This is more or less a reproduction of what can screw up triggers.
The part I don't get is why are you posting this in this thread? Seems off topic.

However, did you actually test by yourself that trigger bug? It is not true you just need a wait, you need TWO waits, just one wait doesn't cause issues apparently. It's also nothing to do with "basic thread logic" as a trigger object is not a thread object. Blizz didn't give us any tool to hold threads. As a matter of fact, destroying a trigger does not destroy the threads it started, if it did, we wouldn't have that bug.

Quote:
I fail to see how (unless you do something that would logically result in a bug, as seen above) timers would get bugged up. Part of the reason I am skeptical at all is because I have never, ever had a single problem with any of my timers ever not doing anything other than exactly what they were supposed to

I already said the other day that I am sure that the timer-set-to-null bug was the I2H bug in disguise. However, recycling timers is still a healthy thing as it assists for making fast&stable timer systems such as all the available TimerUtils implementations, they wouldnt' work ok without recycling. Since you can't run waits inside timer functions, waits have nothing to do with the timer bug.
--

Something to notice is that there is another DestroyTrigger() bug which does not involve waits. Just because two TriggerSleepActions cause a bug, it doesn't necessarily mean it is the only bug.


Quote:
I have never, ever had a single problem with any of my timers ever not doing anything other than exactly what they were supposed to
Famous last words.

Just for everybody's info, although I think the timer bug was just the I2H bug, I have no proof whatsoever for that besides my own intuition. As Destroying timers is yet to be proved safe, I just wouldn't do it. Not like there is a good reason not to recyle, unless your ego of course makes you unable to use stuff made by other people, even then, it would be great that you had your own recycling method - Recycling is faster than blizz' handle allocator anyway...

There are already two perfectly known and reproduce-able ways to corrupt the handle stack. Both of them are very different situations. I think that by now it is naive to think those are the only blizz bugs that can do it. The DestroyTrigger bug is yet to be explained by just I2H and waits, for example.

There's an slight possibility that if your whole map is stable and well coded you wouldn't need to recycly timers, however I doubt anyone has ever made a map that was 100% completely stable and well coded, I guess those maps exist only in the land of unicorns and honest politicians... Nevertheless, if you have one of these perfect maps but plan to add new code to your perfect map, you might at least for a small period of time add a bug to it, it would be a nice idea to prevent the perfectly-made section of your map to become affected by a bug from other code. It is basic software engineering logic.
03-10-2009, 02:07 PM#9
Rising_Dusk
The timer set to null bug has vanished from my maps whenever I eliminated I2H entirely from them. The catalyst appears to be setting the timer to null, however I am convinced the source of the bug is as Vex claims, I2H itself.
03-10-2009, 02:23 PM#10
Vexorian
If you don't set timers to null and specially if you don't destroy them but recycle them, you are basically making them immune to handle stack corruptions.
03-10-2009, 02:46 PM#11
xombie
Thank you for setting up this post then, I assume Anitarf did it - I appreciate the title, how becoming of me.
03-10-2009, 02:48 PM#12
Vexorian
It was Anitarf.
03-10-2009, 02:50 PM#13
xombie
That's wha 'a said!
03-11-2009, 12:20 AM#14
PipeDream
If it is handle stack corruption, then the only way to be immune would be to allocate all your timers at game start.

Consider this process:
* Handle id duplicated on free stack
* Handle id allocated to timer
* Handle id allocated to unit, handle object pointer overwritten, timer inaccessible.

But that doesn't explain why not setting your timers to null will help.

Reversing the order of timer/unit allocation brings the refc into the mix:
* Handle id duplicated on free stack
* Handle id allocated to unit, refc = 2
* Handle id allocated to timer, refc = 3, handle object pointer overwritten
* Unit destroyed, refc = 1
* Timer set to null, refc = 0
* Handle deallocated, handle object pointer overwritten, timer inaccessible

This would happen rarely since you need to get a duplicated handle and have a start A start B end A end B pattern to the lives of the timer and other object. But once you stop setting to null, the first process can still occur, so you would not eliminate the bug.
03-11-2009, 03:04 AM#15
Anitarf
Quote:
Originally Posted by PipeDream
Reversing the order of timer/unit allocation brings the refc into the mix:
* Handle id duplicated on free stack
* Handle id allocated to unit, refc = 2
* Handle id allocated to timer, refc = 3, handle object pointer overwritten
* Unit destroyed, refc = 1
* Timer set to null, refc = 0
* Handle deallocated, handle object pointer overwritten, timer inaccessible
You mean the refcount should be 1 and 2 at the start, not 2 and 3, right?
Also, for the handle index to get recycled upon the unit being removed by the game, wouldn't the timer variable have to have been set to null before the unit was removed so that when the unit was removed the refcount would hit 0 (technically it wouldn't hit 0 when the unit was removed but when the unit variable was set to null; when the unit was removed it'd check the ref counter to decide whether to recycle the handle id)?

If it is still 1 when the unit is removed and only hits 0 afterwards when the timer variable is set to null, it shouldn't get recycled because the timer is still there, right?

I'm a bit confused, could you describe that second example again correctly, or describe why it is already correct if that's the case? :)