darktable-org / darktable-org/darktable
`atrous`: the sample count and the array it bounds are published to the GUI as an unlocked pair
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 13.1k
- Forks
- 1.4k
- Avg merge
- 22h 14m
- Merged PRs (30d)
- 198
Description
Found by code analysis (Claude + Codex, cross-checked) during the gui_data threading
audit, 2026-08-19. No known crash.
Description
atrous hands two related values from a pixelpipe worker thread to a GTK draw callback:
the number of wavelet scales it used, and the array describing them. Neither is written
nor read under a critical section, and — the point of this report — they are two
fields that must agree with each other, so an unlocked handoff can pair a fresh count
with stale samples, or the reverse.
Of the three reverse-direction cases found in this audit (the others are hotpixels and
denoiseprofile) this is the one worth looking at first, because the other two publish a
single independent scalar each.
Evidence
All code is in src/iop/atrous.c.
- Pipe side:
get_samples()fillsg->sample[]and its return value is then assigned to
g->num_samples(lines 295, 382, 501). The two stores are separate and unordered with
respect to any reader. - GTK side:
area_draw()usesg->num_samplesto bound a loop overg->sample[]
(lines 1167-1182). - The module never calls
dt_iop_gui_enter_critical_section().
Impact
No out-of-bounds risk: the count is clamped by the array size — num_samples cannot
exceed the MAX_NUM_SCALES extent of g->sample. The consequence is a mismatched pair,
so the drawing code renders the wrong scale markers for a frame.
Display only, low severity. Listed because it is the one case in the group where the
correctness condition is a relationship between two fields, which a per-field fix or a
per-field atomic would not establish.
Suggested fix
Write the count and the array under one critical section on the pipe side, and read
them under one critical section on the GUI side. A per-field lock, or making
num_samples atomic, does not fix this — the pair has to be published and consumed
atomically.
If holding the lock across the whole array copy is unwelcome on the draw path, copy both
into locals inside the section and draw from the locals afterwards.
Related
hotpixels and denoiseprofile are the other two pipe-to-GUI readouts from the same
audit, 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
Start in src/iop/atrous.c by reading get_samples() and area_draw(), focusing on the assignments and loop described around lines 295, 382, 501, and 1167-1182. Review how dt_iop_gui_enter_critical_section() is used elsewhere, then ensure the count and sample array are published and consumed as one consistent pair. Done means the GUI cannot combine a fresh count with stale samples and the display remains correct.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 70/100