Fixing a 20-year-old bug in Enlightenment E16

A rare, show-stopping bug dating back to 2006 in the Enlightenment E16 window manager was recently fixed. The issue was traced back to a faulty implementation of Newton's algorithm for text truncation.
The editor in chief of this blog was born in 2004. She uses the 1997 window manager, Enlightenment E16, daily. In this article, I describe the process of fixing a show-stopping, rare bug that dates back to 2006 in the codebase. Surprisingly, the issue has roots in a faulty implementation of Newton’s algorithm.
Introduction
Some may find it weird, but I actually greatly enjoy using Enlightenment E16 as my window manager. It’s themable, hackable, lightweight (24MB peak RSS!), amenable to heavy keyboard users like myself, and most importantly - it looks gorgeous. E16 first came to be in 1997, thanks to Carsten Haitzler, and it has been in development ever since. While most have moved to E17 and newer versions, a community of enthusiasts still uses E16. The codebase is old and has accumulated technical debt over the years.
Bugs always come out at the worst times. While working on course slides, I opened a PDF in Atril, and the entire desktop froze.
The bug
I killed the X11 session from a TTY. The hang was deterministic: every time I opened that specific PDF, it happened. Attaching gdb to the live process showed the program was not deadlocked but stuck in a loop. Specifically, __imlib_font_cache_glyph_get was being called repeatedly.
I found that Frame 8 (TextstateTextFitMB at text.c:350) was the constant. This is a call inside the middle-ellipsis truncation loop that tries to fit a string into a pixel limit by removing characters from the middle. This was triggered by a PDF title that was too long for the window decoration. Dumping the frame’s locals revealed a clean two-state oscillation: the Newton-style search was failing to converge and was bouncing between two points forever.
The problematic function
This is a Newton-style search that estimates how many characters to remove based on the average pixels per character. However, the code lacked an iteration limit. Newton’s method can fail to converge or diverge depending on the starting point and the function's nature. In this case, it oscillated forever. Furthermore, the exit tolerance was too tight, and pathological zero-width measurements could potentially cause a divide-by-zero error.
The fix
I applied three defensive changes to both multi-byte and ASCII loops:
- Capped iteration counts at 32. If it exceeds this, we accept the current fit or increment the count by 1 to guarantee termination.
- Floored the removal count at 1 to prevent degenerate strings.
- Floored the average character width at 1 to prevent divide-by-zero errors.
A philosophical detour
Newer is not necessarily better. Fresh software carries brand new bugs and supply chain risks, like the recent XZ backdoor. On the other hand, the number of bugs in old software maintained by competent developers monotonically decreases. If there is a problem in a tool I use and understand, I can fix it myself. There is no supply chain to compromise, and I have full control over my environment.
Source: Hacker News













