darktable-org / darktable-org/darktable

`hotpixels`: the fixed-pixel count can be silently lost between the GUI's read and its reset

Open Beginner friendly
#22,063 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

scope: threading scope: UI
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() writes g->pixels_fixed with the count for the run.
  • GTK side: the draw callback reads it, formats it with the label text, and stores
    -1 back 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.