kernel: Publish code_server mode before registering#11354
Conversation
error_handler routes lazy loads through code:ensure_loaded/1 (which reads the mode from persistent_term via code_server:get_mode/0) as soon as whereis(code_server) succeeds. code_server:init/3 registered the name first and published the term last, after the full code-path setup, so a process hitting an undefined function inside that window crashed with badarg. When that process is the logger kernel process handling an early-boot event - reliably triggered by, for example, an unreadable cwd making erl_prim_loader emit file_error reports for the "." path entry on every lazy load - logger dies and the whole boot halts with "Kernel pid terminated (logger)". Boot scripts that only primLoad the bootstrap module set (as Elixir mix releases do) are the exposed population; the stock start_clean loads all of kernel+stdlib up front and never lazy-loads in the window. Publish the term before registering. Callers reaching ensure_loaded in the window then block in the gen call until loop/1 serves them, the same semantics as calls arriving just after init completes. Verified against the deterministic reproduction in erlangGH-11353: 5/5 boots pass with the fix where 5/5 crashed without it (OTP 28, x86_64; also reproduced on OTP 27 arm64).
CT Test ResultsTests are running... https://github.com/erlang/otp/actions/runs/29185366275 Results for commit abb3861 To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass. See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally. Artifacts
// Erlang/OTP Github Action Bot |
|
Does this commit in #11326 do anything for this? |
|
@garazdawi that commit fixes the issue too, since it fails with badarg, but I believe this PR is still correct for the reasons outlined here: #11353 (comment) |
|
It does — verified against the reproduction rather than just by So #11326 fixes this symptom at the consumer, and this PR removes the |
Fixes #11353.
error_handlerroutes lazy loads throughcode:ensure_loaded/1(which reads the mode frompersistent_termviacode_server:get_mode/0) as soon aswhereis(code_server)succeeds — butcode_server:init/3registered the name first and published the term last, after the full code-path setup. A process hitting an undefined function inside that window crashes with badarg; when it's the logger kernel process handling an early-boot event, logger dies and boot halts withKernel pid terminated (logger).The issue has a deterministic, Elixir-free reproduction (bootstrap-only boot script + unreadable cwd, flipping crash/pass 5/5 with the cwd bit alone, confirmed on OTP 28 x86_64 and OTP 27 arm64). Boot scripts that only
primLoadthe bootstrap module set — the shapemix releasegenerates, so every Elixir release'seval/migration path — are the exposed population.This change publishes the term before registering, so a caller reaching
ensure_loadedin the window blocks in the gen call untilloop/1serves it — the same semantics as a call arriving just after init completes.Verified against the reproduction in #11353 by interposing the recompiled module into the failing boot: 5/5 boots pass with the fix where 5/5 crashed without it.