From cf617fdae0b9bfabd27282854c8e81450d955efa Mon Sep 17 00:00:00 2001
From: Victorien Le Couviour--Tuffet <victorien@videolan.org>
Date: Mon, 13 Mar 2023 13:46:43 +0100
Subject: [PATCH] threading: Ensure passing the correct retval to
 decode_frame_exit

We must reload error just before calling dav1d_decode_frame_exit, as
it may have become stale between the last load and that call.
This can result in crashes since we signal a seemingly successfully decoded
frame, when it's not.
Reloading error within the frame done condition's body ensures a non-stale
value, as we use 'f->task_thread.task_counter == 0' to ensure all other
threads / tasks have already completed when entering it. In other words, only
the last thread still working on this frame can execute this code, after
all other threads have returned to doing something else.
---
 src/thread_task.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/thread_task.c b/src/thread_task.c
index ab2376c30..bfedf6e5b 100644
--- a/src/thread_task.c
+++ b/src/thread_task.c
@@ -795,6 +795,7 @@ void *dav1d_worker_task(void *data) {
                     atomic_load(&f->task_thread.done[0]) &&
                     (!uses_2pass || atomic_load(&f->task_thread.done[1])))
                 {
+                    error = atomic_load(&f->task_thread.error);
                     dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
                                             error ? DAV1D_ERR(ENOMEM) : 0);
                     f->n_tile_data = 0;
@@ -891,6 +892,7 @@ void *dav1d_worker_task(void *data) {
             if (!num_tasks && atomic_load(&f->task_thread.done[0]) &&
                 atomic_load(&f->task_thread.done[1]))
             {
+                error = atomic_load(&f->task_thread.error);
                 dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
                                         error ? DAV1D_ERR(ENOMEM) : 0);
                 f->n_tile_data = 0;
@@ -920,6 +922,7 @@ void *dav1d_worker_task(void *data) {
         if (!num_tasks && atomic_load(&f->task_thread.done[0]) &&
             (!uses_2pass || atomic_load(&f->task_thread.done[1])))
         {
+            error = atomic_load(&f->task_thread.error);
             dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
                                     error ? DAV1D_ERR(ENOMEM) : 0);
             f->n_tile_data = 0;
-- 
GitLab