Skip to content

Update liblouis to 3.38.0 - #11

Open
henrikottesorensen wants to merge 1 commit into
Notalib:mainfrom
henrikottesorensen:feature/liblouis-3.38.0
Open

Update liblouis to 3.38.0#11
henrikottesorensen wants to merge 1 commit into
Notalib:mainfrom
henrikottesorensen:feature/liblouis-3.38.0

Conversation

@henrikottesorensen

@henrikottesorensen henrikottesorensen commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Five releases on from 3.33.0, which was March 2025. Independent of the other open PRs — it touches Directory.Build.props and one line of PACKAGING.md, and nothing else.

Why now

3.38.0 fixes several memory safety issues in code paths this wrapper P/Invokes directly:

  • a heap buffer overflow in back_passDoAction
  • a segfault in lou_compileString
  • missing length validation in _lou_backTranslate
  • null pointer dereferences in _lou_compileTranslationRule and _lou_compileDisplayRule

The change is two lines

The version and its checksum. Everything else derives from them — the per-RID package versions, LibLouis.NET.Tables, and the runtime.liblouis dependency range. The other two 3.33 references were examples in a comment and in the docs, updated so they don't drift.

The checksum was taken from the release tarball and then re-verified from an independent download.

Verified, not assumed

Check Result
All eight RIDs build Yes, container plus macOS
glibc floor unchanged linux-x86 2.34, linux-x64 2.33, linux-arm64 2.33 — identical to 3.33
All 18 P/Invoke entry points exported Yes, on all eight
No dependency outside the platform allowlist Yes, on all eight
Tables still compile Yes, tests pass

The glibc floor is the one that could have gone wrong quietly. linux-x86 sits exactly on 2.34, so any new upstream code reaching for a newer symbol would have pushed it over and dropped RHEL 9, Debian 12 and Ubuntu 22.04 consumers. It didn't.

win-arm64 still needs the -Wl,--add-stdcall-alias workaround: configure.ac continues to assume *mingw* implies x86 in 3.38, so that stays.

3.38 exports 34 lou_ functions where 3.33 exported 30. 475 tables stage, up from 444.

What this unblocks

3.38 adds five exported functions over 3.33, and every one is a deallocator (verified with nm against the packaged osx-arm64 binary, 30 exported lou_* becoming 34):

lou_freeEmphClasses  lou_freeTableFile  lou_freeTableFiles
lou_freeTableIndex   lou_freeTableInfo

lou_freeTableFile is documented as "Free the memory allocated and returned by lou_findTable".

That matters because #9 deliberately leaks that string. liblouis documents it as caller-frees, but the Windows binaries are mingw-w64 and allocate from msvcrt.dll while .NET frees through ucrtbase.dll; freeing across those heaps corrupts them. Leaking a small string was the safer trade with no alternative available in 3.33. These deallocators free through liblouis's own allocator, so the CRT mismatch disappears and the leak becomes properly fixable.

They also unblock four metadata functions that already existed in 3.33 but would leak identically if wrapped today: lou_findTables (plural), lou_listTables, lou_getTableInfo and lou_getEmphClasses. Those want wrapping as a set with their deallocators rather than piecemeal.

None of that is in this PR — it is only the version bump — but it is the reason to do the bump beyond the security fixes, and the kind of "temporary" workaround that stays for years if nobody writes down what would remove it.

Credit for the analysis to the P/Invoke audit in #9.

Behaviour worth knowing

3.38's one backwards-incompatible change is that the table compiler now rejects uppercase virtual dots (AF); only lowercase is valid. None of Nota's tables use them — the tests compile those tables, and they pass.

3.38 also fixes "a long-standing typo with begnum mt in all 5 Danish Grade 2 tables". That touches upstream's da-dk-g26.ctb and da-dk-g28.ctb, but Nota's forks of those shadow them in the test output, so the tests are unaffected. It is a real difference for anyone consuming LibLouis.NET.Tables directly, and a further sign that Nota's tables have drifted behind upstream — see #10.

🤖 Generated with Claude Code

Five releases on from 3.33.0, which was March 2025. Notable for this
wrapper are memory safety fixes in code paths it P/Invokes directly: a
heap buffer overflow in back_passDoAction, a segfault in
lou_compileString, and missing length validation in _lou_backTranslate.

The version and its checksum are the only functional change; everything
else derives from them. The two remaining 3.33 references were examples
in comments and documentation.

Verified rather than assumed:

- All eight RIDs build. win-arm64 still needs the -Wl,--add-stdcall-alias
  workaround, so that upstream assumption survives, as expected.
- The glibc floor is unchanged: 2.34, 2.33, 2.33 for linux-x86, x64 and
  arm64. That decides which distributions can consume the packages, and
  new upstream code is exactly what could raise it.
- Every binary exports all eighteen P/Invoke entry points and depends on
  nothing outside its platform allowlist. 3.38 exports 34 lou_ functions
  where 3.33 exported 30.
- The tests pass, so the tables still compile. 3.38 rejects uppercase
  virtual dots, which is its one backwards incompatible change, and none
  of Nota's tables use them.

475 tables now stage, up from 444.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@henrikottesorensen
henrikottesorensen requested a review from a team August 5, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants