#1145428 sanei_thread: async cancellation crashes/hangs reader threads; fix 8acc267d unreleased

#1145428#5
Date:
2026-08-25 01:26:59 UTC
From:
To:
Package: src:sane-backends
Version: 1.4.0-1
Severity: normal
Tags: patch upstream fixed-upstream

Dear Maintainer,

sanei/sanei_thread.c enables PTHREAD_CANCEL_ASYNCHRONOUS in local_thread(), so a reader thread cancelled through sanei_thread_kill() is unwound at an arbitrary instruction rather than at a defined cancellation point.  I discovered this problem while examining the xsane source code and attempting to fix issues there. This issue has existed since 1.0.13 (2003).

Upstream fixed this in commit 8acc267d ("sanei_thread.c: Use deferred cancellation mode", MR !881), merged 2025-07-14. That landed seven weeks after the 1.4.0 tag (2025-05-24) and no release has followed, so every released sane-backends still carries it -- including 1.4.0-1 in unstable and 1.3.1-3 in trixie. A patch is attached; it is a straight cherry-pick. I would rather submit this now and prevent future issues vs having to be reactive towards this issue.

Upstream's commit message describes the Linux symptom as a hang, with this reproducer:

  while true; do scanimage --verbose --device=test --batch-count=2; done

"The command hangs after several iterations." Upstream cites perl-Image-Sane's test suite as the affected consumer.

HONESTY ABOUT REPRODUCTION ON DEBIAN/UBUNTU
I could not reproduce the hang on glibc: 40 iterations of the above on Ubuntu 24.04 (1.2.1-7build4) completed cleanly. glibc's unwinder appears to tolerate asynchronous cancellation well, so on Debian this is a latent defect rather than one users are likely hitting today. I am reporting it because the code is unambiguously wrong, the fix is upstream and trivial, and the failure is a race -- a passing run proves nothing.

WHERE IT IS NOT LATENT
The same code is fatal on Windows, where winpthreads implements asynchronous cancellation by force-unwinding the target thread via setjmp/RtlUnwind. Built for mingw-w64 (MSYS2 ships sane-backends 1.4.0), a scan segfaults at end of image in roughly nine runs out of ten:

  #6  local_thread (arg=...) at sanei_thread.c:360
  #5  libwinpthread-1.dll
  #3  ucrtbase!.intrinsic_setjmpex
  #2  ntdll!RtlUnwind                       -> SIGSEGV

With 8acc267d applied, a test-backend scan driven directly through libsane went from about 1 run in 10 succeeding to 20 out of 20 clean, reading the full image every time (48 reads, 278480 bytes at 590x472 grey/150dpi).

This is mentioned only as evidence that the defect is real and that the fix works; I am not asking Debian to care about Windows. It does mean sanei_thread is shared machinery used by real hardware backends, not just the test backend, so the exposure is not limited to test setups.

RELATED
Upstream issue #816 ("Should APPLE/MACH be using SIGUSR2 to kill a thread?") touches the same function and is still open: https://gitlab.com/sane-project/backends/-/work_items/816

Debian #869318 ("libimage-sane-perl: FTBFS randomly: build hangs during tests", serious, 2017) is, I believe, the same defect seen from the other end. It is exactly the reproducer upstream describes -- a perl-Image-Sane test suite hanging intermittently -- but it was filed against the consumer, never reassigned here, and closed by working around it in libimage-sane-perl/5-3. Its log mentions neither pthread nor cancellation. It is not a duplicate of this report; it is evidence that the race has been costing people time for years while presenting as a flaky test.

I searched the BTS (src:sane-backends, 13 open bugs), Ubuntu, and upstream before filing; this defect does not appear to have been reported anywhere.

A 1.4.1 point release carrying 8acc267d would fix this for every distribution at once, which may be worth raising with upstream. In my opinion, though, If debian just adds this to the patch list, this will prevent future issues.