Commit Graph
7 Commits
Author SHA1 Message Date
FredApps a68db8e1f8 Merge approved PhotoCraft PR #8905: fix(plugins): bound a run's total plug-in memory, not just each instance
Port behavior and regression coverage into current modules; preserve current upstream behavior.
Bound aggregate parallel plugin memory and preserve serial/parallel equality and total-budget regressions.
2026-10-29 04:47:32 +01:00
David MannandClaude Opus 5.5 68c0f034d5 Plug-ins: refuse a code section with no functions but many bytes instead of panicking (#9679)
wasmi 2.0's strict limits divide the code section's size by its function
count before validating it, so a module whose code section declares 0
functions but more than 1000 bytes (crafted, truncated inside the section,
or a duplicate code section) panicked in Plugin::load. Check every code
section for that one case before handing the bytes to wasmi and return
Error::Module; everything else is still left to wasmi.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-26 14:34:41 +01:00
Roni Balthazar 81d842d307 fix(tiff): preserve PSD byte order in layered TIFF text descriptors (#9098) 2026-10-24 13:37:31 +01:00
Dylan M. Taylor 530e0b6b70 security(plugins): reject host routing keys, bound bands and start fuel, open without blocking on FIFOs 2026-10-23 14:41:52 -04:00
John Turnbach 0fdc625919 fix(plugins): bound a run's total plug-in memory, not just each instance
A filter run gives each band a fresh wasmi instance capped at 512 MiB of
linear memory, and ran one band per rayon worker. The cap was therefore
per instance times the thread count: one run on a 16-thread machine could
hold about 8 GiB, and a plug-in smart filter repeated that on every
re-render.

Limits gains max_total_memory_bytes (default 2 GiB), the budget for all
of one run's instances together, and Limits::parallel_bands(threads),
which allows only as many concurrent bands as max_memory_bytes fits into
that budget (at least one). Plugin::apply uses it to size its groups of
parallel bands, so with the defaults a run holds at most four instances
at the cap however many cores there are. Plug-ins configured with a
smaller per-instance cap keep every worker busy. The limit is listed in
docs/plugins.md.

Tests (crates/plugins/tests/abi.rs):
- parallel_bands_fit_the_total_memory_budget: 16 workers with the
  default limits run 4 bands at once, not 16 (failed before: 16 != 4).
- one_band_at_a_time_matches_parallel_bands: a budget that holds one
  instance still covers every band on an 8-thread pool, with the same
  pixels as parallel bands.

Fixes #8603
2026-10-23 11:43:32 -04:00
midasdfandClaude Opus 5.5 40f14d25e8 Plug-ins: keep the originating error across parallel bands (#1654)
When one band failed, its siblings stopped with a generic "another band failed"
error, which could win the collection order and hide the real cause. The abort
flag now carries the first error, so every band reports it; tests cover traps,
error codes and the instruction budget across parallel bands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:11:00 -04:00
Brandon ThomasandClaude Opus 5.5 7a5c1930b3 Sandboxed WebAssembly plug-ins: photocraft-plugins (wasmi), plugin.* commands, Filter › Plug-ins (#67)
* photocraft-plugins: sandboxed WebAssembly filter plug-ins (wasmi host, ABI v1)

A new L4 crate runs plug-ins in wasmi (pure Rust, MIT/Apache) with no host
imports, a fuel budget metered in slices with a wall-clock deadline, a memory
cap, a recursion cap and wasmi's strict module limits. Every band gets a fresh
instance; traps, budgets, bad manifests and bad pointers are all Errors.
Pixels go over as interleaved normalised f32 in tile-aligned bands, in
parallel on native, blended by the selection. Includes the example Invert
plug-in (no_std Rust, examples/plugins/invert-rs) built into a test fixture,
hostile-module tests, and docs/plugins.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Engine: plugin.* commands (install, list, run, remove, reload)

plugin.run filters the active pixel layer, a targeted channel or a smart
object (recorded as a smart filter) as one undo step; Preferences >
Plug-ins gains Use Additional Plug-ins Folder, loaded when prefs apply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* UI: Filter > Plug-ins lists installed plug-ins with generated dialogs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Plug-ins: bands never outgrow the memory cap; regenerate parity

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Bench: example plug-in Invert vs built-in Invert on 24 MP

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 16:08:28 -04:00