It seems that any refs returned by a proc called from byondapi are left hanging for some possibly indefinite amount of time.
Numbered Steps to Reproduce Problem:
1. Define a byondapi function that calls a proc (global or object)
2. Define a proc that returns a ref-counted object
3. Call_ext the byondapi function to call the proc with the appropriate arguments
Code Snippet (if applicable) to Reproduce Problem:
C++ code:
extern "C" BYOND_EXPORT CByondValue call_global(int n, CByondValue v[]) {
CByondValue result;
ByondValue_Clear(&result);
if (n < 1 || !ByondValue_IsStr(&v[0])) {
return result;
};
char* procname;
u4c char_count;
Byond_ToString(&v[0], nullptr, &char_count);
procname = new char[char_count];
Byond_ToString(&v[0], procname, &char_count);
const CByondValue* args = n > 1 ? &v[1] : nullptr;
if(!Byond_CallGlobalProc(procname, args, n-1, &result)) {
ByondValue_Clear(&result);
}
return result;
}
DM code:
/proc/_new(type, ...)
if(args.len > 1)
return new type(arglist(args.Copy(2)))
else
return new type()
/datum/New() //This is just to show that our proc call did create the object
world.log << "New: [\ref(src)]"
/datum/Del()
world.log << "Del: [\ref(src)]"
/proc/case()
call_ext(LIB, "byond:call_global")("_new", "/datum")
world/New()
case()
Expected Results:
The
world.log << "Del: [\ref(src)]"
line should execute after a short while (tgstation waits 5 minutes for refs held by byond to automatically clear themselves before assuming they are left hanging and need to be hard-deleted with del()
)Actual Results:
So far, I haven't seen the aforementioned line execute after even 5 minutes.
Does the problem occur:
Every time? Or how often?
It seems to happen with any byondapi proc call that returns a ref-counted object.
In other games?
N/A
In other user accounts?
N/A
On other computers?
Untested
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.)
Untested
Workarounds:
While calling
Byond_DecRef
after any byondapi proc call will definitely remove whatever erroneous ref is created, this also runs the risk of decrementing proper ref counts, causing erroneous deletions.
For the Del() call, don't forget that ..() needs to be called as well.
I was going to say that you should be able to produce a simpler demo case by calling Byond_New() instead of a global proc. But in testing I've discovered that the global call does indeed hold a ref too long, so I'm digging in to find out why. Calling Byond_New() however works exactly as expected.
This is my simplified test case: