ID:2374236
 
Descriptive Problem Summary:
Essentially on tgstation or hippiestation servers (they use the same code) there is a runtime error that occurs very rarely. I get a runtime concerning out an out of bound index in the lighting subsystem array. I noticed the specific error while playing on my on private server running the latest version of the code. This runtime causing the games lighting subsystem to slow down considerably and cause the server to eat up resources and lag.


Numbered Steps to Reproduce Problem:
It doesn't happen very often and I have tried to reproduce it as much as possible without any luck as of recently.

Code Snippet (if applicable) to Reproduce Problem:
/datum/controller/subsystem/lighting/fire(resumed, init_tick_checks)
MC_SPLIT_TICK_INIT(3)
if(!init_tick_checks)
MC_SPLIT_TICK
var/i = 0
for (i in 1 to GLOB.lighting_update_lights.len)
var/datum/light_source/L = GLOB.lighting_update_lights[i]

L.update_corners()

L.needs_update = LIGHTING_NO_UPDATE

if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
break
if (i)
GLOB.lighting_update_lights.Cut(1, i+1)
i = 0

if(!init_tick_checks)
MC_SPLIT_TICK

for (i in 1 to GLOB.lighting_update_corners.len)
var/datum/lighting_corner/C = GLOB.lighting_update_corners[i]

C.update_objects()
C.needs_update = FALSE
if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
break
if (i)
GLOB.lighting_update_corners.Cut(1, i+1)
i = 0


if(!init_tick_checks)
MC_SPLIT_TICK

for (i in 1 to GLOB.lighting_update_objects.len)
var/atom/movable/lighting_object/O = GLOB.lighting_update_objects[i]

if (QDELETED(O))
continue

O.update()
O.needs_update = FALSE
if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
break
if (i)
GLOB.lighting_update_objects.Cut(1, i+1)

this is the lighting system code we use and the line var/datum/light_source/L = GLOB.lighting_update_lights[i] + var/datum/lighting_corner/C = GLOB.lighting_update_corners[i]

are the reported runtime lines.

Expected Results:
Lighting system to not fuck up.


Actual Results:
It fucks up.


Does the problem occur:
Every time? Or how often?
used to occur almost every game.
In other games?
Not that I'm aware, just SS13.
In other user accounts?
Everyone.
On other computers?
I would assume.

When does the problem NOT occur?
The latest beta version of byond has possibly resolved this issue. I'm just not sure yet.

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked? (Visit http://www.byond.com/download/build to download old versions for testing.)
Not that I know of.

Workarounds:
Probably a byond glitch but I'm not confident yet.


I'm trying to rewrite and improve this section code here. If anyone could help improve and/or make this better/more robust, I would appreciate it.
Moved to Developer Help.

If you're seeing a runtime error that an array index was out of bounds, that's absolutely a problem in your code. It's nearly impossible for something to go wrong in the engine in such a way as to cause that error message to happen, as a bug that caused list length or a var value to spontaneously change would be indicative of heap corruption which would almost always cause a crash.

I believe the problem you're having is that you're calling CHECK_TICK in a for() loop that uses the "to" operator instead of re-checking the list length. IIRC, when you use "to" the start and end values of the loop are interpreted before the loop begins. The CHECK_TICK command used in some SS13 branches can sleep the proc, during which time the list length can change. Thus, this is bad:

for (i in 1 to GLOB.lighting_update_corners.len)

This is what you want instead:

for (i = 1, i <= GLOB.lighting_update_corners.len, i++)
AH thank you! I will give this a try.
This doesn't work. Lighting doesn't update at all.
/datum/controller/subsystem/lighting/fire(resumed, init_tick_checks)
MC_SPLIT_TICK_INIT(3)
if(!init_tick_checks)
MC_SPLIT_TICK
var/i = 0
for (i = 1, i < GLOB.lighting_update_lights.len; i++)
var/datum/light_source/L = GLOB.lighting_update_lights[i]

L.update_corners()

L.needs_update = LIGHTING_NO_UPDATE

if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
break
if (i)
GLOB.lighting_update_lights.Cut(1, i+1)
i = 0

if(!init_tick_checks)
MC_SPLIT_TICK

for (i = 1, i < GLOB.lighting_update_corners.len; i++)
var/datum/lighting_corner/C = GLOB.lighting_update_corners[i]

C.update_objects()
C.needs_update = FALSE
if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
break
if (i)
GLOB.lighting_update_corners.Cut(1, i+1)
i = 0


if(!init_tick_checks)
MC_SPLIT_TICK

for (i = 1, i < GLOB.lighting_update_objects.len; i++)
var/atom/movable/lighting_object/O = GLOB.lighting_update_objects[i]

if (QDELETED(O))
continue

O.update()
O.needs_update = FALSE
if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
break
if (i)
GLOB.lighting_update_objects.Cut(1, i+1)


https://4st.me/jON80.png

I turned my flashlight on and off. It doesn't work anymore.

Edit: Hang it does, but only when I turn on and off the light switch and even then it's very glitchy and doesn't update everything.

https://4st.me/Geczp.png

Edit 2: https://4st.me/V5Xyv.png

Wew. I guess I should change i = 1 to i = 0?
This is what happens when I changed. i = 1 to i = 0

https://4st.me/s0Bc5.png

Edit: So I didn't see the <= and now my code looks like this

    var/i = 0
for (i = 1, i <= GLOB.lighting_update_lights.len; i++)
var/datum/light_source/L = GLOB.lighting_update_lights[i]


and I get https://4st.me/n0a0D.png

line 47 being
    if (i)
GLOB.lighting_update_lights.Cut(1, i+1)
i = 0


the GLOB.lighting etc statement
    var/i = 0
for (i = 1, i <= GLOB.lighting_update_lights.len; i++)
var/datum/light_source/L = GLOB.lighting_update_lights[i]

L.update_corners()

L.needs_update = LIGHTING_NO_UPDATE

if(init_tick_checks)
CHECK_TICK
else if (MC_TICK_CHECK)
break
if (i)
GLOB.lighting_update_lights.Cut(1, i)
i = 0


this works perfectly.
I made a mistake above (corrected now); the semicolon before i++ should be a comma.
I will definitely give that a try.