ID:1983385
 
Resolved
list.Cut() could lead to reference errors in some cases by not properly clearing junk data. This manifested most often when adding items to the list via list[++list.len]=value.
BYOND Version:1314
Operating System:Linux
Web Browser:Chrome 46.0.2490.86
Applies to:Dream Daemon
Status: Resolved (509.1315)

This issue has been resolved.
Tested in BYOND 509.1310, 509.1314

Descriptive Problem Summary:
When two 'threads' (spawn) exchange large quantities of references to objects (lists, datums, etc) through a queue list accessible to both, the console gets 'Bad ref' output

Numbered Steps to Reproduce Problem:
Run the below code.
Observe that the console is rapidly filled with "BUG: Bad ref [...]"

Code Snippet (if applicable) to Reproduce Problem:
var/list/queue = list()

/world
New()
spawn produce()
spawn consume()

proc/consume()
while(1)
sleep(1)
for(var/i = 1 to 100)
if(queue.len)
// do something with queue[1]
queue.Cut(1,2)

proc/produce()
while(1)
// does NOT happen if this is less than 5 (???), reliably happens if it's 5 or larger
for(var/i = 1 to 5)
/* does NOT happen if this is not a reference (tested with list, datum, number
* and string; only list/datum produce bad ref output), though it can be the same
* reference every time; if it is the same every time, the bad ref applies also
* to produce(), if it differs it is only consume()
*/

queue[++queue.len] = list()
sleep(1)


Expected Results: No 'Bad ref' output

Actual Results: Lots of 'Bad ref' output

Does the problem occur:
Every time? Or how often? Every time
In other games? Irrelevant
In other user accounts? Not tested
On other computers? Not tested

When does the problem NOT occur? When the queue contains less than 5 objects???

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked? Unknown

Workarounds: None

On further testing the 5-element minimum seems to have been chance; there does seem to be a point where each 'type' of reference (constant list, varying list, constant datum, varying datum) changes from a single badref at startup to a spam of them, but it's not always 5; 5 is the first spam value for a varying list, however.

edit:
varying reference - 3+ for a single, 5+ for a spam
constant reference - 3+ for a spam

double edit: mob and obj references behave identically
this has been an issue for a long time, but we've never been able to reliably reproduce it.
Appears to happen in a single 'thread' too, spawn unrelated.
This is gonna sound really weird but... the element that badrefs is consistent for a given number of elements in the queue.

#define N <val>

/world/New()
var/list/queue = list()
for(var/x = 1 to 2)
for(var/i = 1 to N)
queue[++queue.len] = list()

var/i = 0
while(queue.len)
world.log << "REMOVE [i]:"
queue.Cut(1,2)
i++
world.log << "END"
del(src)









N badref index
0 none
1 3
2 4
3 5
N same as for (N-1) / 4

(/ above is integer division, not floating-point)

edit: Tested it on another machine (Ubuntu, BYOND 508.1296) and got... slightly different results. The second machine's badrefs are one element before the first's, i.e. at index 2, 3, 4 instead of 3, 4, 5. I am not sure why.

edit 2: Updating the other machine to 509.1314 did not change its behaviour.

edit 3: Looks like I made an off-by-one error copying the code, re-copying via non-manual means has brought the second machine to index 3, 4, 5 badrefs in the same places the first machine does.
I'll take a look. I'd prefer if you'd post the whole bug statement, not just the bad ref part, as "bad ref" always includes the routine where it happened. Leaving important info out of a bug report is never a good idea.
The comments in the first post do mention it, but I'll grab some raw output for you.

if it is the same every time, the bad ref applies also to produce(), if it differs it is only consume()

Code in initial post:
BUG: Bad ref (f:12) in DecRefCount(DM consume)
BUG: Bad ref (f:9) in DecRefCount(DM consume)
BUG: Bad ref (f:12) in DecRefCount(DM consume)
BUG: Bad ref (f:9) in DecRefCount(DM consume)
[...]

Code in fifth post for N=50:
BUG: Bad ref (f:52) in DecRefCount(DM New)

ninja edit: with the same reference each time: http://sprunge.us/ggAD

double edit: i'm dumb and you probably meant C++ routine (ie the DecRefCount etc), but eh, raw output above anyway :)
Right, I meant the decrefcount part.
Lummox JR resolved issue with message:
list.Cut() could lead to reference errors in some cases by not properly clearing junk data. This manifested most often when adding items to the list via list[++list.len]=value.