The self-contained C path (ekp-c-break-lines, ekp-c-load-hyphenator,
ekp-c-hyphenate, ekp-c-set-spacing, ekp_paragraph.c, ekp_hyphen.c,
~1500 lines) was never used by ekp.el, diverged semantically from the
real pipeline (no kinsoku, no protrusion, no two-pass emergency), and
contained an exploitable heap overflow reachable from Lisp:
ekp_para_create sized its box array as box_count * 2, but a long word
hyphenates into arbitrarily many syllable boxes, overflowing the
calloc'd buffer. Deleting the path deletes the bug class.
Hardening of the live path:
- thread pool: sized from the machine's core count instead of a
hardcoded 8; created lazily on the first multi-paragraph batch
(single-paragraph users never start worker threads); a full queue
now blocks the submitter until a worker makes room — tasks were
silently dropped before, degrading the batch to the Elisp fallback
exactly when parallelism mattered most.
- unified failure gate: a partial allocation used to silently drop
kinsoku, hyphenation or protrusion data and continue with a subtly
different layout; any allocation failure or pending Lisp signal
(non-local exit from a bad element type) now fails the whole call,
and ekp.el falls back to the Elisp engine. The Elisp bridge wraps
both C entry points in condition-case, and a whole-batch nil no
longer crashes the per-paragraph loop.
- integer safety: every extracted pixel value is clamped to int32
instead of silently wrapping.
- EKP_INFINITY (the unreachable-state sentinel) is now a real
infinity: extremely degenerate paragraphs could legitimately
accumulate demerits past the old 1e10 constant, making C consider
reachable states dead and diverge from the Elisp engine.
BREAKING: the four experimental module functions are gone; rebuild
with make -C ekp_c clean all (version gate unchanged at 1.5).
92 ERT green; fuzz 300/300 byte-identical across engines.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- add COPYING (GPL-3.0-or-later) and license headers to all elisp
and C sources; real author/maintainer info replaces placeholders
- convert user-facing options to defcustom under new group `ekp'
(spacing internals managed by ekp-param-set stay defvars)
- autoload user commands: ekp-param-reset, ekp-clear-caches,
ekp-c-module-load, ekp-c-module-build
- ekp--load-dicts: a missing dictionaries/ directory now only
disables hyphenation instead of breaking (require 'ekp);
ekp--split-with-hyphen degrades gracefully (and resolves the
hyphenator once per call instead of once per word)
- package summary no longer redundantly says "for Emacs"
- Makefile: drop personal Windows EMACS_ROOT default; add guidance
- ekp_c/README.md: fix stale 1.1 version references (module is 1.4)
- DEVELOPER*.md: remove archive/ from file map (not in the repo)
- remove unreferenced 10 MB demo GIF
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>