summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@dashbit.co>2021-11-26 23:00:04 +0100
committerJosé Valim <jose.valim@dashbit.co>2021-11-26 23:00:18 +0100
commitb131f874640775fdf08707d5b2fbbc1e91722cd0 (patch)
treeb59fee681abef0d88bea4e5fc781e7702152beea
parentdef1b2bd1a43784f969f9d0dbf1e10e119d904a4 (diff)
downloadelixir-b131f874640775fdf08707d5b2fbbc1e91722cd0.tar.gz
Warn if an outdated lexical tracker is given on eval
-rw-r--r--lib/elixir/lib/macro/env.ex13
-rw-r--r--lib/elixir/src/elixir.erl19
-rw-r--r--lib/elixir/test/elixir/code_test.exs10
-rw-r--r--lib/elixir/test/elixir/macro_test.exs5
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}