HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Double Free Struct Issues

07-17-2007, 02:52 AM#1
Beardo
I've been getting alot of these errors. I've read a few other threads about this, but they were pertaining to handles.

I've been trying to change it around to get it to work

Used to be just:

Collapse JASS:
...
local invdata inv = GetUnitUserData(u)
//(Blah Blah Blah)

call inv.destroy()

Now I tried

Collapse JASS:
...
local invdata inv = GetUnitUserData(u)
//(Blah Blah Blah)

call inv.destroy()
set inv = 0

Still get double frees.


Finally:
Collapse JASS:
...
local invdata inv = GetUnitUserData(u)
//(Blah Blah Blah)

set inv = 0
call inv.destroy()

"attempt to destroy null struct" (duh) error.


I can't win. how do I avoid the double frees with structs?

EDIT: I should mention that I use the same struct name (local invdata inv) in practically all of my functions. I doubt it matters but would it cause the double free problem?
07-17-2007, 02:57 AM#2
PipeDream
You need to match each create with a single destroy. Mentally step through your program, and when you reach a point where the data in the struct will not be needed by anything else, destroy it. The data in the struct is off in a block of memory somewhere; there's only one copy.
One trick to figure out where you won't need it anymore is to figure out where you won't be able to find it anymore. So in your example, unless you SetUnitUserData() to something else, you don't want to destroy!
07-17-2007, 03:03 AM#3
Beardo
OH. I think get it... It's basically like nulling integers... if you're just reading (or pointing to, whatever) struct data with a variable you dont need to null it. am I right?

So take this for example:
Collapse JASS:
local herodata hd = GetTableInt(d, "hdat")

would there be any need to destroy that ?


EDIT: Bahhh im conufsed again

Take vexs example...
Collapse JASS:
function testpairs takes nothing returns nothing
 local pairpair A=pairpair.create()
 local pair x

    set A.x=pair.create()
    set A.y=pair.create()

    set x=A.y //notice we are saving A.y in a backup variable so we can destroy it.
    set A.y= pair_sum(A.x,A.y) //this replaces A.y that's the reason we saved it

    call BJDebugMsg(I2S(  A.y.x )+" : "+I2S( A.y.y )) //notice the nesting of the . operator

    call A.x.destroy()
    call A.y.destroy()
    call A.destroy()
    call x.destroy()
endfunction

Why is x destroyed?
07-17-2007, 03:17 AM#4
DioD
"local invdata inv" is INTEGER reference to struct, GetUnitUserData(u) here is nothing more then Do_Struct_AllocId() analog, its set handle of given struct.

Before you set UUD you have to generate it with Do_Struct_AllocId()

local invdata inv = Do_Struct_AllocId()
call SetUnitUserData(Unit,inv)

this will pass cause struct in function is integer.
07-17-2007, 03:28 AM#5
grim001
What the heck are you talking about DioD? Do_Struct_AllocId()? I think it would be a good idea to ignore that post.

The actual problem here is that you don't seem to understand how structs work Beardo. When you get that integer from the userdata you're just getting a pointer to the struct. You aren't creating a new struct just by declaring a local integer. You don't destroy the struct at the end of every function. Destroy the struct when it will no longer be used, like you would destroy a unit or something.
07-17-2007, 03:32 AM#6
Beardo
Okay, thanks for clearing that up

Just a quick question though. vexs example...

Collapse JASS:
struct pair
    integer x=1
    integer y=2
endstruct

function pair_sum takes pair A, pair B returns pair
 local pair C=pair.create()
    set C.x=A.x+B.x
    set C.y=A.y+B.y
 return C
endfunction

function testpairs takes nothing returns nothing
 local pair A=pair.create()
 local pair B=pair_sum(A, A)
 local pair C=pair_sum(A,B)

    call BJDebugMsg(I2S(C.x)+" : "+I2S(C.y))

//Dont forget, if you are not using an struct instance anymore, you destroy it
    call B.destroy()
    call C.destroy()
    call pair.destroy(A)

endfunction



"//Dont forget, if you are not using an struct instance anymore, you destroy it"

I find that VERY misleading


Collapse JASS:
function IGetCalledWhenTheUnitDies takes unit u returns nothing
local invdata inv = GetUnitUserData(u)

call inv.destroy()
endfunction

Is that how you would destroy the struct when the unit dies?
Does inv.destroy() destroy what inv is pointing to?



Also, how would SetUnitUserData() work? Would you have to destroy the "old" struct ?
07-17-2007, 10:20 AM#7
Anitarf
Well, you should think of structs in a similar way you think of handles. Whenever you create a new struct the map allocates an index in a bunch of parallel arrays for it in the same way as the game allocates memory when you create a new unit group, for example. Your struct variable is just a pointer to the struct's index in the same way a unit group variable is a pointer to the handle index of the group.

So, yes, you only need to destroy a struct when you no longer need it, like when the unit to whom the struct belongs is killed. It's important that you destroy all your structs when you no longer need them, otherwise you're in danger of hitting the 8191 array index limit. Also, it's important that you try to destroy a struct only once, since trying to destroy the same struct twice gives you, at best, double free warning, and at worst, destroys another struct that recycled the previous struct's index after it was destroyed.
07-17-2007, 10:38 AM#8
DioD
grim001
damn do you realy sure than everyone use same version of editor and structs?
Do_Struct_AllocId()
do - nc
struct -nc
allocid - it generate handle for struct, new handle for every struct in game.

SetUnitUserData()
may store reference only to one struct, cos vhelper generate id's for every struct in different functions multiple structs will have same id at time.

pair.create()
will return ID of created struct, this ID have to be stored in UUD. Only after it you will able to destroy struct correctly.