• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Pseudo-recursive call stops working

Status
Not open for further replies.
Level 15
Joined
Aug 7, 2013
Messages
1,338
Hi,

I have a recursive struct called Quad. Basically a Quad is a wrapper around a JASS rect. Each Quad also has a Quad array of max size 5 (so quads within quads, to resemble the recursive structure of rectangles).

I have this function that cleans up a quad and all of its subquads. It works if I have a single Quad and it has any number of quads in its array. But for some reason, if the the Quads within those quads in the array also have quads in their array, the function fails to clean THOSE ones up.

Here is the function
JASS:
    method flush takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i == BOLTS_PER_RECT
            call DestroyLightning(bolts[i])
            set bolts[i] = null
            set i = i + 1
        endloop
        set i = 0
        loop
            exitwhen subQuads[i] == 0
            call subQuads[i].flush()
            set i = i + 1
        endloop
        call RemoveRect(r)
        set r = null
        call this.destroy()
    endmethod

So here is where it works 100% of the time:
JASS:
//this works as expected
local Quad q = Quad.create(...)
set q.subQuads[0] = Quad.create(...)
...
set q.subQuads[4] = Quad.create(...)
call q.flush() //after calling flush, q is cleaned up
//and each Quad in its quad array is also cleaned up

Here is where it seems to fail 100% of the time and start building up leaks
JASS:
//this fails to work as expected
local Quad q = Quad.create(...)
set q.subQuads[0] = Quad.create(...)
...
set q.subQuads[4] = Quad.create(...)
set q.subQuads[0].subQuads[0] = Quad.create(...)
...
set q.subQuads[4].subQuads[4] = Quad.create(...)
call q.flush() //after calling flush, q is cleaned up
//and I believe its Quad array members are...
//BUT the array members of those Quad array members don't get cleaned up!!

So inherently there is a contradiction. We know that flush() works if we have this situation:
a single Quad and any number of quad array members

Now, since each quad array member is also a quad, and each quad can have an array of members, it must be the case that calling flush() also works as expected, since it's the same exact conditions.

But testing it out this is actually not the case!

So either I've got insane, there's some weird case in my code I'm failing to cover, or somehow my calls start to crash for a reason that I can't control (limit of warcraft 3 engine with pseudo-recursion?).
 
JASS:
        loop
            exitwhen subQuads[i] == 0
            call subQuads[i].flush()
            set i = i + 1
        endloop

This is the issue I think. Since Quad contains a Quad array of size exactly 5, subQuads[5] comparator will cause undefined behavior (kill virtual thread I think)

Edit: Also, referencing a array instance not initialized will cause undefined behavior, eg:

JASS:
local integer array q[5]
set q[0] = 1
if q[1]==0 then
    //undefined behavior
endif
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
543
Edit: Also, referencing a array instance not initialized will cause undefined behavior, eg:

JASS:
local integer array q[5]
set q[0] = 1
if q[1]==0 then
    //undefined behavior
endif

nah, we're not in c-land. it will just return 0- value based on the type: 0, 0.0, false, null

see also
 
nah, we're not in c-land. it will just return 0- value based on the type: 0, 0.0, false, null

see also

JASS:
scope test initializer i
	private function i takes nothing returns nothing
		local unit q
		call BJDebugMsg("hello world")
		if q==null then
			call BJDebugMsg("was null")
		endif
		if q!=null then
			call BJDebugMsg("was not null")
		endif
		call BJDebugMsg("test")
	endfunction
endscope
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
543
JASS:
scope test initializer i
	private function i takes nothing returns nothing
		local unit q
		call BJDebugMsg("hello world")
		if q==null then
			call BJDebugMsg("was null")
		endif
		if q!=null then
			call BJDebugMsg("was not null")
		endif
		call BJDebugMsg("test")
	endfunction
endscope

yeah, that's no array though.
reading an uninitialized variable kills the thread.
 
Status
Not open for further replies.
Top