darktable-org / darktable-org/darktable
`hotpixels`: the fixed-pixel count can be silently lost between the GUI's read and its reset
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 13.1k
- Forks
- 1.4k
- Avg merge
- 22h 14m
- Merged PRs (30d)
- 198
Description
Description
hotpixels counts the pixels it corrected on a pixelpipe worker thread and hands the
number back to the GUI through g->pixels_fixed. The module has no critical section
anywhere, so the handoff is unsynchronised — and unlike the mask-display toggles found in
the same audit, this one is not a one-way handoff: the draw callback reads the field,
formats it into the label, and then resets it to -1 (src/iop/hotpixels.c:422-425).
A pipe-thread write landing between the read and the reset is overwritten by the reset
and lost, so a count can silently fail to appear.
This is the direction dev-doc/GUI.md already documents as requiring a critical section,
which makes it a clearer violation of an existing written rule than the toggle cases.
Evidence
All code is in src/iop/hotpixels.c.
- Pipe side:
process()writesg->pixels_fixedwith the count for the run. - GTK side: the
drawcallback reads it, formats it with the label text, and stores
-1back into the same field (lines 422-425) so that a subsequent draw with no new
pipe run shows nothing. - Neither side calls
dt_iop_gui_enter_critical_section(); the module never calls it.
Impact
Display only: a count that never reaches the label, or a stale one. No memory unsafety —
the field is a plain int, not a pointer, and it is not used as an index.
Low severity taken alone. It is worth fixing because the read-modify-write makes it a
genuine lost update rather than only a stale read, and because the module is one of the
in-tree examples someone will copy.
Suggested fix
Take dt_iop_gui_enter_critical_section() on both sides. On the GTK side the read and
the reset must be in the same critical section, so that the pair is atomic with
respect to the pipe's write:
dt_iop_gui_enter_critical_section(self);
const int fixed = g->pixels_fixed;
g->pixels_fixed = -1;
dt_iop_gui_leave_critical_section(self);
then format fixed outside the section.
Related
Two other modules in the same audit hand a pipe-computed value back to the GUI with no
lock: denoiseprofile (three variance floats) and atrous (a count and the array it
bounds) — both filed separately in this directory. The toggle-direction cases are in
#22064.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read src/iop/hotpixels.c, focusing on process() and the draw callback around lines 422-425, then consult dev-doc/GUI.md for the critical-section rule. Verify that the pipe-side write and the GUI-side read/reset are protected as one handoff, and confirm that the displayed count is no longer lost or stale.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 88/100