Fix crash due to crosss-thread list access.
authorCarl Hetherington <cth@carlh.net>
Fri, 21 Mar 2025 12:37:34 +0000 (13:37 +0100)
committerCarl Hetherington <cth@carlh.net>
Sat, 22 Mar 2025 12:29:59 +0000 (13:29 +0100)
I've seen it happen that item points to a different QueueItem after the
lock was unlocked here, which I didn't think was possible.  Backtraces
suggest that when problems happen _queue is being sorted in another
thread, and perhaps this is not allowed (I couldn't find any conclusive
proof in any documentation).

There is also a potential problem with the newly-added zombify() method,
which takes the lock and clears the list.

src/lib/writer.cc

index 90c5a54cfa9937f7b4de4962986943e554e0a938..7a933724c45f50153111e7b5e15b4f893d9716ab 100644 (file)
@@ -471,23 +471,14 @@ try
 
                        DCPOMATIC_ASSERT(item != _queue.rend());
                        ++_pushed_to_disk;
-                       /* For the log message below */
-                       int const awaiting = _last_written[_queue.front().reel].frame() + 1;
-                       lock.unlock ();
-
-                       /* i is valid here, even though we don't hold a lock on the mutex,
-                          since list iterators are unaffected by insertion and only this
-                          thread could erase the last item in the list.
-                       */
 
-                       LOG_GENERAL("Writer full; pushes %1 to disk while awaiting %2", item->frame, awaiting);
+                       LOG_GENERAL("Writer full; pushes %1 to disk while awaiting %2", item->frame, _last_written[_queue.front().reel].frame() + 1);
 
                        item->encoded->write_via_temp(
                                film()->j2c_path(item->reel, item->frame, item->eyes, true),
                                film()->j2c_path(item->reel, item->frame, item->eyes, false)
                                );
 
-                       lock.lock ();
                        item->encoded.reset();
                        --_queued_full_in_memory;
                        _full_condition.notify_all ();