diff options
author | José Valim <jose.valim@dashbit.co> | 2021-11-26 23:00:04 +0100 |
---|---|---|
committer | José Valim <jose.valim@dashbit.co> | 2021-11-26 23:00:18 +0100 |
commit | b131f874640775fdf08707d5b2fbbc1e91722cd0 (patch) | |
tree | b59fee681abef0d88bea4e5fc781e7702152beea | |
parent | def1b2bd1a43784f969f9d0dbf1e10e119d904a4 (diff) | |
download | elixir-b131f874640775fdf08707d5b2fbbc1e91722cd0.tar.gz |
Warn if an outdated lexical tracker is given on eval
-rw-r--r-- | lib/elixir/lib/macro/env.ex | 13 | ||||
-rw-r--r-- | lib/elixir/src/elixir.erl | 19 | ||||
-rw-r--r-- | lib/elixir/test/elixir/code_test.exs | 10 | ||||
-rw-r--r-- | lib/elixir/test/elixir/macro_test.exs | 5 |
4 files changed, 43 insertions, 4 deletions
diff --git a/lib/elixir/lib/macro/env.ex b/lib/elixir/lib/macro/env.ex index 122d1025c..3c23c2aac 100644 --- a/lib/elixir/lib/macro/env.ex +++ b/lib/elixir/lib/macro/env.ex @@ -107,6 +107,19 @@ defmodule Macro.Env do end @doc """ + Prunes compile information from the environment. + + This happens when the environment is captured at compilation + time, for example, in the module body, and then used to + evaluate code after the module has been defined. + """ + @doc since: "1.14.0" + @spec prune_compile_info(t) :: t + def prune_compile_info(env) do + %{env | lexical_tracker: nil, tracers: []} + end + + @doc """ Returns a list of variables in the current environment. Each variable is identified by a tuple of two elements, diff --git a/lib/elixir/src/elixir.erl b/lib/elixir/src/elixir.erl index 55e7b95c7..bbd03bb9c 100644 --- a/lib/elixir/src/elixir.erl +++ b/lib/elixir/src/elixir.erl @@ -170,11 +170,22 @@ env_for_eval(#{lexical_tracker := Pid} = Env) -> versioned_vars := #{} }, - case is_pid(Pid) andalso is_process_alive(Pid) of - true -> NewEnv; - false -> NewEnv#{lexical_tracker := nil, tracers := []} + case is_pid(Pid) of + true -> + case is_process_alive(Pid) of + true -> + NewEnv; + false -> + 'Elixir.IO':warn( + <<"an __ENV__ with outdated compilation information was given to eval, " + "call Macro.Env.prune_compile_info/1 to prune it">> + ), + NewEnv#{lexical_tracker := nil, tracers := []} + end; + false -> + NewEnv#{tracers := []} end; -%% TODO: Deprecate all options except line and file. +%% TODO: Deprecate all options except line and file on v1.15. env_for_eval(Opts) when is_list(Opts) -> Env = elixir_env:new(), diff --git a/lib/elixir/test/elixir/code_test.exs b/lib/elixir/test/elixir/code_test.exs index 997fc5d5c..958a3e4e3 100644 --- a/lib/elixir/test/elixir/code_test.exs +++ b/lib/elixir/test/elixir/code_test.exs @@ -88,6 +88,16 @@ defmodule CodeTest do ~r"argument error while evaluating example.ex between lines 1 and 2", fn -> Code.eval_string("a <>\nb", [a: :a, b: :b], file: "example.ex") end end + + test "warns when lexical tracker process is dead" do + {pid, ref} = spawn_monitor(fn -> :ok end) + assert_receive {:DOWN, ^ref, _, _, _} + env = %{__ENV__ | lexical_tracker: pid} + + assert ExUnit.CaptureIO.capture_io(:stderr, fn -> + assert Code.eval_string("1 + 2", [], env) == {3, []} + end) =~ "an __ENV__ with outdated compilation information was given to eval" + end end test "eval_quoted/1" do diff --git a/lib/elixir/test/elixir/macro_test.exs b/lib/elixir/test/elixir/macro_test.exs index 430f81e7f..f01168ca9 100644 --- a/lib/elixir/test/elixir/macro_test.exs +++ b/lib/elixir/test/elixir/macro_test.exs @@ -791,6 +791,11 @@ defmodule MacroTest do describe "env" do doctest Macro.Env + test "prune_compile_info" do + assert %Macro.Env{lexical_tracker: nil, tracers: []} = + Macro.Env.prune_compile_info(%{__ENV__ | lexical_tracker: self(), tracers: [Foo]}) + end + test "stacktrace" do env = %{__ENV__ | file: "foo", line: 12} |