Skip to content

Fix reentrancy of Code.eval_*#15306

Merged
josevalim merged 2 commits intoelixir-lang:mainfrom
lukaszsamson:ls-eval-reentrant
Apr 28, 2026
Merged

Fix reentrancy of Code.eval_*#15306
josevalim merged 2 commits intoelixir-lang:mainfrom
lukaszsamson:ls-eval-reentrant

Conversation

@lukaszsamson
Copy link
Copy Markdown
Contributor

Keep env and dbg callbacks on stacks in process dict

Fixes #15303

Keep env and dbg callbacks on stacks in process dict

Fixes elixir-lang#15303
Comment thread lib/elixir/test/elixir/code_test.exs Outdated
Code.eval_string(
"""
Code.eval_string("1 + 1")
dbg(1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This already works, because the dbg is expanded using the dbg_callback before Code.eval_string runs. So to actually test it we need this:

Suggested change
dbg(1)
Code.eval_string("dbg(1)")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, fixed

Comment thread lib/elixir/src/elixir.erl Outdated
%%
%% We keep a stack of envs in the process dictionary so nested eval calls
%% in the same process do not clobber the outer env.
push_pdict(?elixir_eval_env, Env),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if we need the push and pop into the direct, because the try-block already captures the state. I'd do this:

PreviousEvalEnv = erlang:get(?elixir_eval_env),
try

after
  case PreviousEvalEnv of
    undefined -> erlang:delete(?elixir_eval_env);
    _ -> erlang:put(?elixir_eval_env, PreviousEvalEnv)
  end
end

The same for dbg_callback. WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I was too fixated on stack model

- Replace process-dict stack with direct save/restore via local
  variables in eval_forms/4 and erl_eval/3 (per @josevalim).
- Fix nested dbg_callback test to actually exercise the path
  via Code.eval_string("dbg(1)") (per @jonatanklosko).
@josevalim josevalim merged commit 007efde into elixir-lang:main Apr 28, 2026
15 checks passed
@josevalim
Copy link
Copy Markdown
Member

💚 💙 💜 💛 ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Code.eval_* functions are not reentrant

3 participants