HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Game freezes for one minute / trigger dies.

07-25-2007, 06:27 PM#1
MrApples
I have a bit of code here which does not crash or lock the game, but freezes it for a minute, and ends the trigger prematurely. I checked for infinite loops/etc and I can't seem to find anything... so i'm hoping its my nub experience with JASS(this is really my second shot at full-JASS).

Its the core code of a save load I'm working on. The test I used saved 3 values with a val of 6, and a max of 11, all same.

Collapse JASS:
function SaveCode takes integer c returns string
    local integer xi = 0
    local integer xi2 = 0
    local integer xi3 = 0
    local integer a = 1
    local integer a2 = udg_Code_Saves[c]
    local integer b = 0
    local integer b2 = 0
    local string result = null
    local string xs = null
    local string xs2 = null
    if ( a2 <= 0 ) then
        // No values saved for this code. Duh?
        set result = "nosaves"
        return result
    endif
    loop
        // Lets make it multi-demensional.
        set xi3 = ( a + ( 1000 * (c - 1)))
        set xi = udg_Save_Val[xi3]
        set xi2 = udg_Save_Max[xi3]
        set b = 1
        // Find space needed.
        loop
            exitwhen xi2 < udg_SL_Powers[b]
            set b = ( b + 1)
        endloop
        // BooStuffer - Eats teh scraps.
        if ( xi2 <= ( udg_SL_Powers[b] - xi2 ) ) then
            if ( xs != null ) then
                if ( SubString( xs, 1, 1 ) == "1" ) then
                    set xi = ( xi + xi2 )
                endif
                set xs = SubString( xs, 2, StringLength(xs) )
            else
                // Create opt error. xs = null.
            endif
        endif
        //BooStuffer
        set b = ( b - 1 )
        loop
            if ( xi >= udg_SL_Powers[b] ) then
                set xi = ( xi - udg_SL_Powers[b] )
                set xs = ( "1" + xs )
            else
                set xs = ( "0" + xs )
            endif
            set b = ( b - 1 )
            exitwhen ( b == 0 )
        endloop
        loop
            if ( ModuloInteger( StringLength(xs), 6 ) != 0 ) then
                set xs = ( xs + "0" )
            else
                exitwhen true
            endif
        endloop
    exitwhen a == a2
    set a = ( a + 1 )
    endloop
    set xi = StringLength(xs)
    set a = 1
    set b = 1
    loop
        set xs2 = SubString( xs, a, (a+5))
        loop
            if ( xs2 == SubString( udg_SL_BinSet, b, (b+5)) ) then
                // Start BooStuffer
                // If a value can be above 64, and is above 64, then extra is 1, else 0. Same goes for 32.
                // Yes it makes sense, stop forgetting that.
                if (b <= (udg_SL_Chars - udg_SL_Base)) then
                    if ( xs != null ) then
                        if SubString( xs, 1, 1) == "1" then
                            set b = (b + udg_SL_Base)
                        endif
                        set xs = SubString( xs, 2, StringLength(xs))
                        if (b <= (udg_SL_Chars - udg_SL_Base2)) then
                            if ( xs != null ) then
                                if SubString( xs, 1, 1) == "1" then
                                    set b = (b + udg_SL_Base2)
                                endif
                                set xs = SubString( xs, 2, StringLength(xs))
                            else
                                // Create Opt Error. xs was = null.
                            endif
                        endif
                    else
                        //Create Opt Error. xs was = null.
                    endif
                endif
                // End BooStuffer
                set result = result + SubString( udg_SL_CharSet, b, b )
                exitwhen true
            endif
            set b = ( b + 1 )
        endloop
    exitwhen ( a2 == xi )
    set a = ( a + 6 )
    endloop
    return result
endfunction
07-25-2007, 06:50 PM#2
Strilanc
Put a call to display different text inside each of the loops, and it will be pretty obvious which one is not exiting.

As for loops which may be unending:
- the first inner loop compares xi2 and udg_SL_powers[b]. I don't know what that array is, but are you sure it will match the conditions eventually?

- the second inner loop ('BooStuffer') exits when b == 0, this should be b <= 0 just in case b is one-off from what you expect it to be.

- same thing with the last condition on the first and second outer loop, use a >= a2 just in case. (there are lots of bugs in real software caused by looping conditions being too lazy like this)

- The inner loop of the second loop will cause an infinite loop if udg_SL_BinSet doesn't contain xs2.

In general, you want to make your loops easier to break out of by checking for 'that could never happen' conditions (like checking for a substring past the end of a string)on them.
07-25-2007, 07:21 PM#3
MrApples
An infinite loop should cause a crash though right? Theres no waits in that code.
07-25-2007, 08:33 PM#4
blu_da_noob
An infinite loop should cause a momentary freeze at worst (rus until it hits the thread limit), as long as you aren't calling this multiple time. One thing I did notice though is that your one loop exits when a == xi but you increment a by 6 every iterations, which means it might pass xi without ever being exactly equal. Might want to change that to >=.
07-25-2007, 08:55 PM#5
MrApples
The loop before that main loop makes the string divisible by 6. There isn't a problem with strings where they're longer then they say they are is there?

I found the problem with this, it is a infinite loop, but its caused by something which shouldn't happen( a non-existant value being saved, different script), and i'm busy figuring out why that is.
07-26-2007, 06:48 AM#6
Strilanc
Quote:
Originally Posted by MrApples
The loop before that main loop makes the string divisible by 6. There isn't a problem with strings where they're longer then they say they are is there?

That's the type of thing you don't want to rely on. Writing a function like a house of cards, where future parts rely on many of the specifics and implementations of past parts, is asking for trouble.

Changing the test to >= guarantees that the loop will exit when it should, AND when something goes wrong. Also, >= is ~exactly as expensive as ==, so there's not even a slow down to worry about in this case.