ID:1952412
 
Resolved
If the last var accessed before a try/catch was accessed right after the catch(), and another var was accessed in catch() itself, the var access after the catch could be incorrect. (This is a fix to the way worlds are compiled. Affected projects must re-compile.)
BYOND Version:508
Operating System:Linux
Web Browser:Chrome 45.0.2454.99
Applies to:Dream Maker
Status: Resolved (509.1303)

This issue has been resolved.
Descriptive Problem Summary:
Setting an object's var in a catch block, then trying to immediately use a var from that object will cause a nonsense runtime.
This happens even if the catch block isn't run.

Numbered Steps to Reproduce Problem:
Get code.
Compile code.
Run code.
Cry.

Code Snippet (if applicable) to Reproduce Problem:
#define DEBUG

/proc/stuff(msg)

/world/New()
var/obj/o = new

try
if(0);
catch(var/exception/e)
o.name = e.name //comment out this line to fix runtime

//if(0); //OR uncomment this line
stuff("[o.loc]")

del(src)


Expected Results:
No runtime

Actual Results:

runtime error: Cannot read null.loc
proc name: New (/world/New)
source file: repro.dm,14
usr: null
src: world
call stack:
world: New()


Does the problem occur:
Every time? Or how often? Every time.
In other games? Yes; https://github.com/Mloc/loquacious-duck/blob/dmut/modules/ dmut/dmut_manager.dm#L62
In other user accounts?: N/A
On other computers?: Yes

When does the problem NOT occur?
It won't happen if the var isn't touched inside the catch block, or if a junk statement is put before the use of the object.

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.)

Workarounds:

The following attempts to access vars on `d`, instead of null. Looks like the last object whose vars were accessed inside the try block is used?

#define DEBUG

/proc/stuff(msg)

/world/New()
var/obj/o = new
var/datum/d = new

try
if(d.type);
catch(var/exception/e)
o.name = e.name //comment out this line to fix runtime

//if(0); //OR uncomment this line
stuff("[o.loc]")

del(src)


runtime error: undefined variable /datum/var/loc
proc name: New (/world/New)
source file: runtime.dme,15
usr: null
src: world
call stack:
world: New()


edit: confirmed on my system in:
508.1296
508.1299 (latest 508 as of this post)
509.1302 (latest 509 as of this post)




Also reproducible on:
#define DEBUG

/proc/stuff(msg)

/world/New()
var/obj/o = new
var/datum/d = new

world.log << d.type
try
if(0);
catch(var/exception/e)
o.name = e.name //comment out this line to fix runtime

//if(0); //OR uncomment this line
stuff("[o.loc]")

del(src)

Last variable whose vars were accessed? Is there any optimisation on not loading the same object twice to access vars? Could it be optimising out the "double" access of 'o' to access vars to a single access, and failing when 'o' isn't actually the last-accessed object?




#define DEBUG

/proc/stuff(msg)

/world/New()
var/obj/o = new
var/datum/a/a = new

world.log << a.b.type
try
if(0);
catch(var/exception/e)
o.name = e.name //comment out this line to fix runtime

//if(0); //OR uncomment this line
stuff("[o.loc]")

del(src)


/datum/a
var/datum/b/b = new
/datum/b

runtime error: undefined variable /datum/b/var/loc
proc name: New (/world/New)
source file: runtime.dme,16
usr: null
src: world
call stack:
world: New()

Looks like last-accessed-object.
Lummox JR resolved issue with message:
If the last var accessed before a try/catch was accessed right after the catch(), and another var was accessed in catch() itself, the var access after the catch could be incorrect. (This is a fix to the way worlds are compiled. Affected projects must re-compile.)
Really good find there, Mloc. Apparently the issue was a result of the way the blocks are compiled into bytecode after parsing.