- Joined
- Aug 18, 2009
- Messages
- 4,099
Agent types in wc3 log the remaining references on the object, such as variables or hashtable entries. The agent's id cannot be released until the object is no longer referenced. This grants the advantage it cannot happen that a new object obtains the old id and is still attributed the remaining data/actions.
Now when we have techniques like the return bug, the principle is undercut, causing vulnerability. Same is the case with struct types. They are represented by integers. So if, for example, you make a wrapper type for the native "unit" called "Unit":
The wrapper, top, is good to immediately access the custom information inside Unit without having to load the object from the native unit first everytime. It lacks the refcounting, however. And since the whole struct management is not very type-safe, but also because tracking every reference in jass seems very ineffective, I do not see a hundred percent replacement for this.
Instead I only manually insert addRef/removeRef lines in critical places, where the object could potentially get destroyed while being operated on. But I want to have some uniformity, therefore inject the system in all allocation methods and make a propose:
The object starts with one reference and a flag "destroyed" set to false on allocation. Destroy methods may do some individual stuff like calling events but are to set the "destroyed" flag to false, subtract the reference and check the current ref count if the object id can be deallocated already.
The "destroyed" flag serves as a lock so no further destroy method can be called on the object and may as well be used to prevent other method calls. What you would really want to block are the procedures that actively change something on the object.
The lines with // are auto-injected. Of course the destroy method would have to be marked as such.
A classic example where I use refs is the multi-missile:
A single spell instance spawns multiple missiles, maybe in periods, maybe with a flexible amount. All missiles reference a parent data holder instead of copying it all. So the parent is not allowed to disperse until all missiles have been spawned and all spawned missiles have been destroyed. They need to prolong the parent's life.
Now when we have techniques like the return bug, the principle is undercut, causing vulnerability. Same is the case with struct types. They are represented by integers. So if, for example, you make a wrapper type for the native "unit" called "Unit":
JASS:
function abc
local Unit someUnit
JASS:
function def
local unit someUnit
The wrapper, top, is good to immediately access the custom information inside Unit without having to load the object from the native unit first everytime. It lacks the refcounting, however. And since the whole struct management is not very type-safe, but also because tracking every reference in jass seems very ineffective, I do not see a hundred percent replacement for this.
Instead I only manually insert addRef/removeRef lines in critical places, where the object could potentially get destroyed while being operated on. But I want to have some uniformity, therefore inject the system in all allocation methods and make a propose:
The object starts with one reference and a flag "destroyed" set to false on allocation. Destroy methods may do some individual stuff like calling events but are to set the "destroyed" flag to false, subtract the reference and check the current ref count if the object id can be deallocated already.
The "destroyed" flag serves as a lock so no further destroy method can be called on the object and may as well be used to prevent other method calls. What you would really want to block are the procedures that actively change something on the object.
JASS:
struct abc
//integer refs
//boolean destroyed
//method deallocate
//if (refs > 0)
//return
//endif
//...
//endmethod
//method subRef
//refs = refs - 1
//deallocate()
//endmethod
//static method allocate
//...
//destroyed = false
//refs = 1
//return this
//endmethod
destroyMethod Destroy
//if this.destroyed then
//return
//endif
//this.destroyed = true
...custom lines
//subRef()
endmethod
The lines with // are auto-injected. Of course the destroy method would have to be marked as such.
A classic example where I use refs is the multi-missile:
A single spell instance spawns multiple missiles, maybe in periods, maybe with a flexible amount. All missiles reference a parent data holder instead of copying it all. So the parent is not allowed to disperse until all missiles have been spawned and all spawned missiles have been destroyed. They need to prolong the parent's life.