Checking leaks in JASS?

woot

New Member
Reaction score
8
I know there's a GUI leak checker program.. but is there a JASS leak checker?

I know how leaks work.. I just want to be sure I didn't accidentally miss something in my code..


Addition:

Romek posted this multiboard that counts the handles in your game:
JASS:
scope HC initializer Init

    globals
        private leaderboard udg_HandleBoard
    endglobals

    private function L2I takes location P returns integer
            return P
            return 0
    endfunction

    private function Update takes nothing returns nothing
            local integer i = 0
            local integer id
            local location array P
            local real result=0
            loop
                    exitwhen i >= 50
                    set i = i + 1
                    set P<i> = Location(0,0)
                    set id = L2I(P<i>)
                    set result = result + (id-0x100000)
            endloop
            set result = result/i-i/2
            loop
                    call RemoveLocation(P<i>)
                    set P<i> = null
                    exitwhen i &lt;= 1
                    set i = i - 1
            endloop
            call LeaderboardSetItemValue(udg_HandleBoard,0,R2I(result))
    endfunction

    private function Actions takes nothing returns nothing
            set udg_HandleBoard = CreateLeaderboard()
            call LeaderboardSetLabel(udg_HandleBoard, &quot;Handle Counter&quot;)
            call PlayerSetLeaderboard(GetLocalPlayer(),udg_HandleBoard)
            call LeaderboardDisplay(udg_HandleBoard,true)
            call LeaderboardAddItem(udg_HandleBoard,&quot;Handles&quot;,0,Player(0))
            call LeaderboardSetSizeByItemCount(udg_HandleBoard,1)
            call Update()
            call TimerStart(GetExpiredTimer(),0.05,true,function Update)
    endfunction

    function Init takes nothing returns nothing
        debug call TimerStart(CreateTimer(),0,false,function Actions)
    endfunction

endscope</i></i></i></i>


Works really well :D (And it only runs on debug mode)
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
It's not too hard considering you can look up what each function returns.

If a function returns a force, group, location, effect, texttag, lightning, or anything like that, you need to destroy it when you're finished with it.

If you have a local variable that is not a trigger, real, integer, boolean, string, or code, you have to set it to null.

It's funny that JASS is actually easier to leak-check, don't you think?

I haven't heard of any programs that do this though. Sorry. :(
 

Flare

Stops copies me!
Reaction score
662
Well, if you are unsure, you can just post the code and someone will probably take a look at it

As regards location/group leaks, there's no really easy method.
For special effects, you would probably notice if a special effect wasn't destroyed (depending on the effect being used)
For handle leaks, you can use emjlr3's Handle Counter - it won't point out where your leaks are, but it displays the current number of handles in-game so if the counter continually rises, you'll know that you've got handle leaks somewhere (and you should be able to narrow it down, if you know what triggers were running at the time)

If you have a local variable that is not a trigger
Triggers are a handle-type and must be nulled, AFAIK
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Triggers are a handle-type and must be nulled, AFAIK

Only if you're planning on destroying the trigger at any time. That goes for every type of handle. It only causes a leak if the handle ends up pointing to nothing (the object is removed). If it's never going to get removed, it's no leak.

>emjlr3's Handle Counter

Is a very good tool. I have a slightly modified version of it, and it works very well.
 

woot

New Member
Reaction score
8
wait a minute wait a minute


handles must be nulled??

this i had no idea..

so.. if I do

Code:
set g = (units in playable map are)

loop
exitwhen sizeof(g) == 0
set u = GroupPickRandomUnit(g)
//blah blah
groupRemoveUnit(g,u)
endloop
DestroyGroup(g)

by the time the function exits I need to set u to null??

do I have to set it to null within the loop? as in, every time i set it to a new unit.. or just before the function exits?
 

Romek

Super Moderator
Reaction score
963
Only if you're planning on destroying the trigger at any time. That goes for every type of handle. It only causes a leak if the handle ends up pointing to nothing (the object is removed). If it's never going to get removed, it's no leak.

>emjlr3's Handle Counter

Is a very good tool. I have a slightly modified version of it, and it works very well.
As do I.

Here's my one:
JASS:
scope HC initializer Init

    globals
        private leaderboard udg_HandleBoard
    endglobals

    private function L2I takes location P returns integer
            return P
            return 0
    endfunction

    private function Update takes nothing returns nothing
            local integer i = 0
            local integer id
            local location array P
            local real result=0
            loop
                    exitwhen i &gt;= 50
                    set i = i + 1
                    set P<i> = Location(0,0)
                    set id = L2I(P<i>)
                    set result = result + (id-0x100000)
            endloop
            set result = result/i-i/2
            loop
                    call RemoveLocation(P<i>)
                    set P<i> = null
                    exitwhen i &lt;= 1
                    set i = i - 1
            endloop
            call LeaderboardSetItemValue(udg_HandleBoard,0,R2I(result))
    endfunction

    private function Actions takes nothing returns nothing
            set udg_HandleBoard = CreateLeaderboard()
            call LeaderboardSetLabel(udg_HandleBoard, &quot;Handle Counter&quot;)
            call PlayerSetLeaderboard(GetLocalPlayer(),udg_HandleBoard)
            call LeaderboardDisplay(udg_HandleBoard,true)
            call LeaderboardAddItem(udg_HandleBoard,&quot;Handles&quot;,0,Player(0))
            call LeaderboardSetSizeByItemCount(udg_HandleBoard,1)
            call Update()
            call TimerStart(GetExpiredTimer(),0.05,true,function Update)
    endfunction

    function Init takes nothing returns nothing
        debug call TimerStart(CreateTimer(),0,false,function Actions)
    endfunction

endscope</i></i></i></i>


Works really well :D (And it only runs on debug mode)

And yes, You'd need to null the group and the unit there.
 

woot

New Member
Reaction score
8
ooh, can I just copy and paste that code to test my map?


also.. sorry I added an edit above.. but do I need to null the unit only before the function exits.. or at the end of every loop cycle before I set it to a new unit?


also, how do I set my game to debug mode (is this default when you click the check mark in newgen world editor?)
 

Romek

Super Moderator
Reaction score
963
You only null things at the end of the function, or before returns (unless the function returns what you're nulling).

The debug mode option is in one of the tabs at the top of the WE (Grimoire, or JassHelper or something.)

You can just copy and paste that into your map and it'll just work.
 

Viikuna

No Marlo no game.
Reaction score
265
You only null things at the end of the function, or before returns (unless the function returns what you're nulling).

Is there something wrong with nulling local handles when you dont need them, and calling some other functions after nulling?
 

woot

New Member
Reaction score
8
oh boy.. thanks for the info!

what if you have a local array of handles? do you have to go through the array and null each handle.. or will simply setting the array to null work?
 

Flare

Stops copies me!
Reaction score
662
oh boy.. thanks for the info!

what if you have a local array of handles? do you have to go through the array and null each handle.. or will simply setting the array to null work?

You null the array values that you've used e.g.
JASS:
local &lt;handle type&gt; array something
set something[0] = ...
set something [599] = ...
set something[0] = null
set something[599] = null


And you can null the handle whereever you like, as long as you don't null it while it's still needed :)
 

woot

New Member
Reaction score
8
Hmm something in my map is leaking handles like crazy

i get like 100 new handles every second..


... but I just went through everything and set variables to null before functions exit ...


... i'm gunna have to look at this more :(

thanks for the help all, you've been amazing
 

woot

New Member
Reaction score
8
does this leak? .. assuming that I destroy the group and the point properly.. what I'm asking is.. is there some object that is a "range area" object or something that leaks

Code:
(Units within 60.00 of tempPoint)


thanks :)
 

woot

New Member
Reaction score
8
Ok lets narrow this down

This is definitely leaking handles..

Can anyone tell me why?

Code:
CheckHeartyAura
    Events
        Time - Every 1.00 seconds of game time
    Conditions
    Actions
        Custom script:   call CheckHeartyAura()

Code:
function CheckHeartyAura takes nothing returns nothing
    local integer i = 0
    local integer j = 0
    local real currentLife = 0
    local real maxLife = 0
    local group g = null
    local unit u = null
    local unitInfo uI = 0
    
    set i=0
    loop
    exitwhen i >= 5
        set g = GetUnitsInRectAll(boards[i].r)
        loop
        exitwhen CountUnitsInGroup(g) == 0
        set u = GroupPickRandomUnit(g)
        set uI = GetCSData(u)
            if(uI != 0 and uI.isUnitEffect==false)then
                if(UnitHasBuffBJ(u, 'B004'))then
                        if(uI.hasHeartyApplied == false)then
                            set uI.hasHeartyApplied = true
                            set currentLife = GetUnitStateSwap(UNIT_STATE_LIFE, u)
                            set maxLife = GetUnitStateSwap(UNIT_STATE_MAX_LIFE, u)
                            call SetUnitState(u, UNIT_STATE_MAX_LIFE, maxLife * 1.75)
                            call SetUnitState(u, UNIT_STATE_LIFE, currentLife * 1.75)
                        endif
                    else
                        if(uI.hasHeartyApplied == true)then
                            set uI.hasHeartyApplied = false
                            set currentLife = GetUnitStateSwap(UNIT_STATE_LIFE, u)
                            set maxLife = GetUnitStateSwap(UNIT_STATE_MAX_LIFE, u)
                            call SetUnitState(u, UNIT_STATE_MAX_LIFE, maxLife / 1.75)
                            call SetUnitState(u, UNIT_STATE_LIFE, currentLife / 1.75)
                        endif
                    endif
            endif
        call GroupRemoveUnit(g,u)
        endloop
        call DestroyGroup(g)
    set i=i+1
    endloop
    set u = null
endfunction


unitInfo is a struct of mine.. looks like this
Code:
struct unitInfo
    integer x = -1
    integer y = -1
    string motionType = ""
    integer moveAmount = 0
    string attackType = ""
    integer attackAmount = 0
    
    //information for being attacked values
    real damagedModifier = 1
    integer missedModifier = 0
    
    boolean isUnitEffect = false
    integer count=9999
    
    string state =""
    
    integer array bBuffId[48]
    integer array bAbilityId[48]
    integer array bCount[48]
    integer array bAttackCount[48]
    integer array bAttackedCount[48]
    integer bSize = 0
    
    integer array attackAbilities[12]
    integer attackAbilitiesSize=0
    
    player realOwner = null
    
    boolean hasHeartyApplied = false
endstruct

could it have something to do with a player object being in there? .. local structs are just integers though... (unless you create one) =\ and I do destroy them properly (when I destroy them) .. I don't get it
 

Romek

Super Moderator
Reaction score
963
Is there something wrong with nulling local handles when you dont need them, and calling some other functions after nulling?

No. It's easier to keep track of them if they're at the end though.

does this leak? .. assuming that I destroy the group and the point properly.. what I'm asking is.. is there some object that is a "range area" object or something that leaks

Code:
(Units within 60.00 of tempPoint)


thanks :)

Leaks a unit group.
 

woot

New Member
Reaction score
8
hmmmm

if i change the function to this it seems to leak a lot less (perhaps not at all)

EDIT .. nevermind its still leaking
was:
Code:
if(UnitHasBuffBJ(u, 'B004'))then

changed to:
Code:
if(UnitHasBuffBJ(u, 'B004')==true)then


Code:
function CheckHeartyAura takes nothing returns nothing
    local integer i = 0
    local integer j = 0
    local real currentLife = 0
    local real maxLife = 0
    local group g = null
    local unit u = null
    local unitInfo uI = 0
    
    set i=0
    loop
    exitwhen i >= 5
        set g = GetUnitsInRectAll(boards[i].r)
        loop
        exitwhen CountUnitsInGroup(g) == 0
        set u = GroupPickRandomUnit(g)
        set uI = GetCSData(u)
            if(uI != 0 and uI.isUnitEffect==false)then
                if(UnitHasBuffBJ(u, 'B004')==true)then
                        if(uI.hasHeartyApplied == false)then
                            set uI.hasHeartyApplied = true
                            set currentLife = GetUnitStateSwap(UNIT_STATE_LIFE, u)
                            set maxLife = GetUnitStateSwap(UNIT_STATE_MAX_LIFE, u)
                            call SetUnitState(u, UNIT_STATE_MAX_LIFE, maxLife * 1.75)
                            call SetUnitState(u, UNIT_STATE_LIFE, currentLife * 1.75)
                        endif
                    else
                        if(uI.hasHeartyApplied == true)then
                            set uI.hasHeartyApplied = false
                            set currentLife = GetUnitStateSwap(UNIT_STATE_LIFE, u)
                            set maxLife = GetUnitStateSwap(UNIT_STATE_MAX_LIFE, u)
                            call SetUnitState(u, UNIT_STATE_MAX_LIFE, maxLife / 1.75)
                            call SetUnitState(u, UNIT_STATE_LIFE, currentLife / 1.75)
                        endif
                    endif
            endif
        call GroupRemoveUnit(g,u)
        endloop
        call DestroyGroup(g)
    set i=i+1
    endloop
    set u = null
endfunction
 

woot

New Member
Reaction score
8
nevermind its still leaking

but it isn't leaking every 1 second like clockwork

sometimes it leaks.. sometimes it doesnt.. sometimes it waits a while and then starts leaking for a bit..


this is so weird
 

trb92

Throwing science at the wall to see what sticks
Reaction score
142
function CheckHeartyAura

group g isn't nulled. That leaks a handle.
 

woot

New Member
Reaction score
8
what the hell

the counter goes up for this too:

Code:
Test
    Events
        Player - Player 1 (Red) types a chat message containing -test as An exact match
    Conditions
    Actions
        Set tempGroup = (Units in (Playable map area) matching (((Matching unit) is A Hero) Equal to True))
        Unit Group - Pick every unit in (Units in (Playable map area) matching (((Matching unit) is A Hero) Equal to True)) and do (Actions)
            Loop - Actions
                Hero - Set (Picked unit) Hero-level to 10, Hide level-up graphics
                Unit - Set mana of (Picked unit) to 100.00
                Set tempUnit = (Picked unit)
        Custom script:   call DestroyGroup(udg_tempGroup)


but it doesn't just go up 1 every time.. it goes up more if i wait a bit before typing -test

and at first it actually causes the count to go down.. but then as you keep typing the count goes up more


what the hell is going on
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top