HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

"Gamecache" bug

08-03-2006, 08:01 PM#1
Vexorian
No idea if this is the one reported by people. Icefrog sent me a map where apparentally 2 local variables of handle types may have the same pointer, or maybe a unit's handle index is swapped to another handle's one if it is true then it is a huge problem about local variables and not really a gamecache issue. It had nothing to do with the return bug, even the local variable lost the correct reference.
08-03-2006, 08:08 PM#2
Captain Griffen
Any chance of us seeing this map or the code?
08-03-2006, 08:26 PM#3
The)TideHunter(
IceFrog probally wouldent allow it, its most probally the a Dota map.
08-03-2006, 09:13 PM#4
emjlr3
why are you posting this if u dont intend to share the knowledge?

just asking..
08-03-2006, 09:33 PM#5
Alevice
He probably will in time. Don't jump into conclussions that soon.
08-03-2006, 10:16 PM#6
Vexorian
I am trying to reproduce the bug outside dota (old vesion that was) or to check the code and see if something else produced the problem , Icefrog also says he has more detailed information at home I am waitting for it as well.
08-03-2006, 10:17 PM#7
masda70
Well here is a bug I've recently discovered (yesterday), concerning handle integer ids. It will make the next N number of handles created bug and have the ID.
Everything in the code is needed as far as I'm concerned, the comments give a better idea of what each are. I've told PipeDream about it, and it seems to be a new thing. It has to do with code execution (trigger execute, executefunc), handle creation and destroying trigger, stuff that is often part of gamecache use methods.

You can check out the demo map I have attached. Trig_Test_Actions is triggered by a chat event.

The bug is actually very hard to find in a real game because it considers functions that will 'do nothing', but I'm actually just talking about a function that must not run a call functionname() at its runtime. It could aswell do local variable declarations, boolean or integer arithmetics and even set/if-then/loop? statements as long as it doesn't call other functions.

Collapse JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function NothingAction takes nothing returns nothing
    local boolean b=false
    if (udg_d and udg_b) and  b then  // it evaluates false, it will actually do nothing, and that's essential for the bug to happen
        call CreateTrigger()
    else
        set udg_d=true
    endif
endfunction

function CreateAction takes nothing returns nothing
    call CreateTrigger() //Create any object
endfunction

function RunStuff takes nothing returns nothing
    local integer i=0
    local integer h=0
    call TriggerSleepAction(0.00) //This wait action is needed for the bug to happen
    call ExecuteFunc("NothingAction") //These can be TriggerExecute and still bug
    call ExecuteFunc("CreateAction") //A function creating handles is called between two others that 'do nothing
    call ExecuteFunc("NothingAction")
    call TriggerSleepAction(0.00)
    set i=1
    loop
        exitwhen i > 10
        set udg_loc[i]=Location(0.,0.)
        if H2I(udg_loc[i])==h then
            call BJDebugMsg("FATALatindex:"+I2S(i)+";"+I2S(H2I(udg_loc[i])))
        else
            call BJDebugMsg("Index:"+I2S(i)+";"+I2S(H2I(udg_loc[i])))
        endif
        set h=H2I(udg_loc[i])
        set i=i+1
    endloop
    call BJDebugMsg("Ended")
endfunction


function Trig_Test_Actions takes nothing returns nothing
    call ExecuteFunc("RunStuff")
    call DestroyTrigger(GetTriggeringTrigger())  //Without this call, the bug won't happen
endfunction

To test this, run the demo map and type 'test' as a chat message to trigger the buggy method. Watch the 'FATALatindex' messages they show that a newly created handle had the same handle id as a previous one.

A few notes: From test experience, you can try this with any kind of handle: unit,destructable, trigger,multiboard, location,rect... I haven't tested them all but there are good reasons to think this is true.
- The more functions are called to do nothing the more created handle will bug =[.
Attached Files
File type: w3mThreadHandleBug.w3m (16.7 KB)
08-03-2006, 10:20 PM#8
masda70
Since you have two threads about the same topic:
I have just posted about a bug I've recently discovered related to buggy handle id creation in the thread 'Bounty: Reproduce the "gamecache bugs"'
08-03-2006, 10:22 PM#9
Vexorian
I am gonna crash the other one and move your post here
08-03-2006, 10:26 PM#10
masda70
Oh cool, btw I have just edited a few things that didn't seem to be clear at all.
08-03-2006, 10:37 PM#11
Vexorian
The whole contents of the NothingAction are not needed, just an empty function does the trick
08-03-2006, 10:41 PM#12
Vexorian
Collapse JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function NothingAction takes nothing returns nothing
endfunction

function CreateAction takes nothing returns nothing
    call CreateTrigger() //Create any object
endfunction

function RunStuff takes nothing returns nothing
local integer i=0
local handle b=null
    call TriggerSleepAction(0.00) //This wait action is needed for the bug to happen
    call ExecuteFunc("NothingAction")//These can be TriggerExecute and still bug
    call ExecuteFunc("CreateAction") //A function creating handles is called between two others that 'do nothing
    call ExecuteFunc("NothingAction")
    call TriggerSleepAction(0.00)
    set i=1
    loop
        exitwhen i > 10
        set udg_loc[i]=Location(0.,0.)
        if udg_loc[i]==b then
            call BJDebugMsg("FATALatindex:"+I2S(i)+";"+I2S(H2I(udg_loc[i])))
        else
            call BJDebugMsg("Index:"+I2S(i)+";"+I2S(H2I(udg_loc[i])))
        endif
        set b=udg_loc[i]
        set i=i+1
    endloop
    call BJDebugMsg("Ended")
endfunction


function Trig_Test_Actions takes nothing returns nothing
    call ExecuteFunc("RunStuff")
    call DestroyTrigger(GetTriggeringTrigger())  //Without this call, the bug won't happen
endfunction

//===========================================================================
function InitTrig_Test takes nothing returns nothing
    set gg_trg_Test = CreateTrigger(  )
    set udg_t[0]= CreateTrigger(  )
    set udg_t[1]= CreateTrigger(  )
    call TriggerAddAction( udg_t[0], function NothingAction )
    call TriggerAddAction( udg_t[1], function CreateAction )
    call TriggerRegisterPlayerChatEvent( gg_trg_Test, Player(0), "test", true )
    call TriggerAddAction( gg_trg_Test, function Trig_Test_Actions )
endfunction


So no way it is related to return bug, here you can see simple locals failing.

Notice it seems to be related to DestroyTrigger, you are destroying a trigger before waiting in the same trigger. The bug shall be there although it messes with our current understanding of threads
08-03-2006, 10:48 PM#13
Vexorian
Even without calling "CreateAction" the bug happens
08-03-2006, 10:53 PM#14
Vexorian
It is not the local variables' mistake either

Still bugs out:
Collapse JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function NothingAction takes nothing returns nothing
endfunction

function CreateAction takes nothing returns nothing
    call CreateTrigger() //Create any object
endfunction

function RunStuff takes nothing returns nothing
local integer i=0

    call TriggerSleepAction(0.00) //This wait action is needed for the bug to happen
    call ExecuteFunc("NothingAction")//These can be TriggerExecute and still bug
    call TriggerSleepAction(0.00)
    set i=1
    set udg_locus=null
    loop
        exitwhen i > 10
        set udg_loc[i]=Location(0.,0.)
        if udg_loc[i]==udg_locus then
            call BJDebugMsg("FATALatindex:"+I2S(i)+";"+I2S(H2I(udg_loc[i])))
        else
            call BJDebugMsg("Index:"+I2S(i)+";"+I2S(H2I(udg_loc[i])))
        endif
        set udg_locus=udg_loc[i]
        set i=i+1
    endloop
    call BJDebugMsg("Ended")
endfunction


function Trig_Test_Actions takes nothing returns nothing
    call TriggerExecute(udg_t[5])
    call DestroyTrigger(GetTriggeringTrigger())  //Without this call, the bug won't happen
endfunction

//===========================================================================
function InitTrig_Test takes nothing returns nothing
    set gg_trg_Test = CreateTrigger(  )
    set udg_t[0]= CreateTrigger(  )
    set udg_t[1]= CreateTrigger(  )
    call TriggerAddAction( udg_t[0], function NothingAction )
    call TriggerAddAction( udg_t[1], function CreateAction )
    set udg_t[5]=CreateTrigger()
    call TriggerAddAction(udg_t[5],function RunStuff)
    call TriggerRegisterPlayerChatEvent( gg_trg_Test, Player(0), "test", true )
    call TriggerAddAction( gg_trg_Test, function Trig_Test_Actions )
endfunction
08-03-2006, 10:55 PM#15
masda70
Yea I know the content in nothingaction is not needed, but I also wanted to prove this can happen to any REAL map maker and not only to those that like to have empty functions! I actually discovered this when I was working on a map which had a system implemented that was dynamically calling hundreds of execfuncs based on the function names stored in variables. Some of these functions created thing when a few conditions were met (stored in boolean array), so basically it happened that some functions did create stuff but some didn't do anything at all!

EDIT: Hmm creationaction is not needed? That's actually weird, I remember testing it. Actually I think that when I put the createaction function not between the nothingaction calls but at the end the 'buggy' wc3 state caused by the empty functions was somewhat being cleared by the dummy handle creation which had the last word at runtime.