Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/_avif.c
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,9 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) {
return NULL;
}

Py_BEGIN_ALLOW_THREADS;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Releasing the GIL here allows two Python threads to enter avifDecoderNthImage() concurrently on the same AvifDecoder. That routine mutates shared diagnostics, imageIndex, tile/codec state, and decoder->image; a seek/reset in one call can destroy codec state while another call is decoding. I compiled exact base e41083f383c9cd3db95de52564cc0b6452313d4a, head 3fd310f710a54146d8bf2bd030a1833371815099, and GitHub merge e93744326a73993b88b667a6c597d678bd74182a against Pillow's pinned libavif 1.4.2 with dav1d 1.5.3 and the libyuv fast path, then ran the bundled star.avifs through one shared decoder from two threads. Across ten subprocess trials, base completed 10/10 with zero mismatches, while head crashed 10/10 (8 SIGSEGV, 2 SIGBUS) and merge crashed 10/10 (8 SIGSEGV, 2 SIGBUS). Please add per-decoder serialization covering avifDecoderNthImage() through consumption/conversion of the decoder-owned image, and add a concurrency regression test. Locking only avifDecoderNthImage() is insufficient because decoder->image remains shared through avifImageYUVToRGB().

result = avifDecoderNthImage(decoder, frame_index);
Py_END_ALLOW_THREADS;
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
Expand Down
Loading