Commit e1e516f3b8 for aom

commit e1e516f3b800f2098f824e9f87d7c263cf460846
Author: Jingning Han <jingning@google.com>
Date:   Mon Nov 9 09:09:41 2026 -0800

    decode_mt_init: resume worker setup after error

    Worker and thread data creation in decode_mt_init() was only attempted
    when pbi->num_workers == 0. If a previous call bailed out via
    aom_internal_error() part way through (tile thread creation failure or
    a thread data allocation failure), num_workers would be non-zero while
    the remaining thread_data[i].td entries were left NULL. The next frame
    decoded with the same decoder instance would then skip the setup and
    dereference a NULL td in the mc_buf allocation loop, causing a segfault.

    Make the setup resumable: allocate the worker arrays only if they are
    not yet allocated, create any workers at or beyond num_workers, and
    allocate any missing thread data.

    Change-Id: I91649d5a3b923e167cbe5446d5b36ac488383a33

diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index fcb328de40..90c705b917 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -3584,20 +3584,26 @@ static inline void sync_dec_workers(AV1Decoder *pbi, int num_workers) {
 static inline void decode_mt_init(AV1Decoder *pbi) {
   AV1_COMMON *const cm = &pbi->common;
   const AVxWorkerInterface *const winterface = aom_get_worker_interface();
+  const int num_threads = pbi->max_threads;
   int worker_idx;

-  // Create workers and thread_data
-  if (pbi->num_workers == 0) {
-    const int num_threads = pbi->max_threads;
+  // Create workers and thread_data. This may be re-entered after a previous
+  // call bailed out via aom_internal_error() (e.g., thread creation or memory
+  // allocation failure), so only set up what is still missing.
+  if (pbi->tile_workers == NULL) {
     CHECK_MEM_ERROR(cm, pbi->tile_workers,
                     aom_malloc(num_threads * sizeof(*pbi->tile_workers)));
+  }
+  if (pbi->thread_data == NULL) {
     CHECK_MEM_ERROR(cm, pbi->thread_data,
                     aom_calloc(num_threads, sizeof(*pbi->thread_data)));
+  }

-    for (worker_idx = 0; worker_idx < num_threads; ++worker_idx) {
-      AVxWorker *const worker = &pbi->tile_workers[worker_idx];
-      DecWorkerData *const thread_data = pbi->thread_data + worker_idx;
+  for (worker_idx = 0; worker_idx < num_threads; ++worker_idx) {
+    AVxWorker *const worker = &pbi->tile_workers[worker_idx];
+    DecWorkerData *const thread_data = pbi->thread_data + worker_idx;

+    if (worker_idx >= pbi->num_workers) {
       winterface->init(worker);
       worker->thread_name = "aom tile worker";
       if (worker_idx != 0 && !winterface->reset(worker)) {
@@ -3605,16 +3611,16 @@ static inline void decode_mt_init(AV1Decoder *pbi) {
                            "Tile decoder thread creation failed");
       }
       ++pbi->num_workers;
+    }

-      if (worker_idx != 0) {
-        // Allocate thread data.
-        CHECK_MEM_ERROR(cm, thread_data->td,
-                        aom_memalign(32, sizeof(*thread_data->td)));
-        av1_zero(*thread_data->td);
-      } else {
-        // Main thread acts as a worker and uses the thread data in pbi
-        thread_data->td = &pbi->td;
-      }
+    if (worker_idx == 0) {
+      // Main thread acts as a worker and uses the thread data in pbi
+      thread_data->td = &pbi->td;
+    } else if (thread_data->td == NULL) {
+      // Allocate thread data.
+      CHECK_MEM_ERROR(cm, thread_data->td,
+                      aom_memalign(32, sizeof(*thread_data->td)));
+      av1_zero(*thread_data->td);
       thread_data->error_info.error_code = AOM_CODEC_OK;
       thread_data->error_info.setjmp = 0;
     }