Skip to content

fix: a library with a runtime of its own keeps it on Linux and FreeBSD (#3481) - #3482

Closed
nicolas-maman wants to merge 2 commits into
mainfrom
fix/oct30-abi-matrix
Closed

nicolas-maman wants to merge 2 commits into
mainfrom
fix/oct30-abi-matrix

Conversation

@nicolas-maman

@nicolas-maman nicolas-maman commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Main's Linux / GCC leg has failed the cross-version ABI matrix since the 0.861.0 release (#3481), so every PR is red there. This fixes it with the model the owner chose: a library that carries its own runtime keeps it on Linux and FreeBSD, as it already does on macOS and Windows.

What was wrong

The first commit makes the matrix print an Aether consumer's stderr on failure, which showed:

aether: the library was made for Aether runtime 0.860.0/abi1 and runs on 0.863.0/abi1: rebuild it with the Aether of the runtime it runs on
aether: panic outside any try/catch or actor: ...

The chain:

  • ae build links a program -rdynamic, because plugins loaded through std.dl and script_gateway resolve runtime symbols against it. On ELF the program therefore exports its runtime.
  • A library's calls into the runtime it carries then bound to the program's runtime instead.
  • The library's runtime ABI check (Discussion: compiler/runtime ABI compatibility policy for shipped native libraries #2957) saw a runtime it was not made for, and refused.
  • The importer ended on the panic.

It surfaced only when two runtimes that both have the check met with different versions:

  • equal versions passed (0.860.0 against 0.860.0);
  • a pair where one side predates the check passed (0.860.0 against 0.859.0);
  • macOS (two-level namespace) and Windows (PE) never bind across, and pass.

The fix

  • The link. On ELF, ae links a library with its own runtime -Bsymbolic, so its references bind to its own definitions. It still exports them, for a C host. A --shared-runtime library is unchanged.
  • The same behaviour everywhere. Two things ae did only on macOS and Windows now apply everywhere, both naming --shared-runtime: refusing an import that needs one runtime (a struct holding strings, a builder that uses its config, A string an --emit=lib export returns is never released (C hosts and binary imports) #2931), and warning that a library's actors are not drained at exit.
  • Libraries linked before this fix. On ELF, a library of another runtime ABI linked without -Bsymbolic is refused at import, naming the rebuild, instead of the program ending on its first call. The flag is read from the file's dynamic section (DT_SYMBOLIC, or DF_SYMBOLIC in DT_FLAGS). The reader was checked on x86_64, aarch64 and 32-bit ARM libraries built with and without -Bsymbolic.

What changes for Linux and FreeBSD users:

  • A static-runtime library's panics no longer reach the program's catch.
  • Its actors' in-flight messages are no longer drained at exit.
  • An import that needs one runtime is refused.

--shared-runtime gives one runtime, as it already does on macOS and Windows.

Tests

  • The ABI matrix:
    • checks that this ae links SYMBOLIC on ELF (it fails on main);
    • runs the 0.860.0 importer with this library (it aborts on main);
    • expects the refusal for the 0.860.0 library under this importer.
  • Four tests drop their Linux-only branch: binary_import_actors, binary_import_ownership, binary_import_structs and sandbox_nested_libraries now expect on Linux and FreeBSD what they already expected on macOS and Windows.
  • Docs: emit-lib.md, abi-policy.md and ownership-model.md.

Checked locally on Windows (there is no ELF machine here):

  • ae builds with -Werror;
  • it compiles for x86_64 Linux with zig (-Wall -Wextra -Werror);
  • the scripts parse.

CI shows Linux and FreeBSD.

Closes #3481

…3481)

Main's Linux / GCC leg aborts both Aether-consumer cases of the matrix
since 0.861.0, and the log shows only "Aborted (core dumped)": run_app
sent the program's stderr to app.err and never printed it. A failed case
now prints the last lines of what the program wrote there.
#3481)

Main's Linux / GCC leg failed the cross-version ABI matrix since 0.861.0,
both Aether-consumer cases aborting. The stderr the previous commit
prints:

  aether: the library was made for Aether runtime 0.860.0/abi1 and runs
          on 0.863.0/abi1: rebuild it with the Aether of the runtime it
          runs on
  aether: panic outside any try/catch or actor: ...

An `ae build` program is linked -rdynamic (std.dl and script_gateway
plugins resolve runtime symbols against it), so on ELF it exports its
runtime, and a library's calls into the runtime it carries bound to the
program's instead. The library's code ran on a runtime it was not made
for; across versions the runtime ABI check of #2957 says so and refuses,
and the importer ended on the panic. Equal versions (0.860.0 against
0.860.0) and a library older than the check (against 0.859.0) passed,
which is why it showed only once main moved past the release.
macOS (two-level namespace) and Windows (PE) keep the copies apart and
pass, and docs/abi-policy.md says a self-contained library carries its own
runtime.

The owner chose that model for Linux too. So:
- ae links a library with a runtime of its own -Bsymbolic on ELF: its
  references bind to what it defines, and it still exports them for a C
  host. A --shared-runtime library defines no runtime and is unchanged.
- The import refusal of what needs one runtime (a struct holding strings,
  a builder using its config, #2931) and the warning that a library's
  actors are not drained at exit apply on every platform; both name
  --shared-runtime, as on macOS and Windows.
- A library of another runtime ABI linked before this (no DT_SYMBOLIC or
  DF_SYMBOLIC in its dynamic section, read from the file) is refused at
  import on ELF, naming the rebuild, instead of ending the program on its
  first call. The reader was checked on x86_64, aarch64 and 32-bit ARM
  libraries built with and without -Bsymbolic.

Tests: the ABI matrix checks that this ae links SYMBOLIC on ELF, expects
the refusal for an old library linked without it, and still runs the old
importer with this library (which now keeps its own runtime);
binary_import_actors, binary_import_ownership, binary_import_structs and
sandbox_nested_libraries expect on Linux and FreeBSD what they expected
on macOS and Windows. Docs: emit-lib.md, abi-policy.md and
ownership-model.md.

Checked here: ae builds with -Werror on Windows and compiles for x86_64
Linux with zig (-Wall -Wextra -Werror); the scripts parse. Linux and
FreeBSD behaviour is CI's to show.
@nicolas-maman nicolas-maman changed the title fix: an Aether program and a library of another 0.860+ version abort together on Linux (#3481) fix: a library with a runtime of its own keeps it on Linux and FreeBSD (#3481) Oct 30, 2026
@nicolas-maman

Copy link
Copy Markdown
Collaborator Author

Folded into #3477, which was meant to be the one PR: the same two commits are there (012c9a4, 682c917), and it closes #3481.

@nicolas-maman
nicolas-maman deleted the fix/oct30-abi-matrix branch October 30, 2026 20:56
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.

Linux: an Aether program and a binary library of another 0.860+ version abort together (ABI matrix red on main since 0.861.0)

1 participant