Skip to content

Commit 8a1bbb5

Browse files
committed
Warn on errors from orphan compiler modules
1 parent 745ee1d commit 8a1bbb5

3 files changed

Lines changed: 60 additions & 6 deletions

File tree

lib/elixir/lib/task/supervised.ex

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ defmodule Task.Supervised do
123123
args: args,
124124
reason: {log_value(kind, value), __STACKTRACE__},
125125
# using :proc_lib over Process because we want the :undefined default, not nil
126-
process_label: :proc_lib.get_label(self())
126+
process_label: :proc_lib.get_label(self()),
127+
orphan_compiler_module?: orphan_compiler_module?(kind, value)
127128
}
128129
},
129130
%{
@@ -138,6 +139,23 @@ defmodule Task.Supervised do
138139
end
139140
end
140141

142+
defp orphan_compiler_module?(kind, reason) do
143+
with :error <- kind,
144+
:undef <- reason,
145+
{:error_handler, :error_handler} <- :erlang.process_info(self(), :error_handler),
146+
{:parent, parent} <- :erlang.process_info(self(), :parent),
147+
{:error_handler, Kernel.ErrorHandler} <-
148+
(try do
149+
:erlang.process_info(parent, :error_handler)
150+
rescue
151+
_ -> nil
152+
end) do
153+
true
154+
else
155+
_ -> false
156+
end
157+
end
158+
141159
defp exit_reason(:error, reason, stacktrace), do: {reason, stacktrace}
142160
defp exit_reason(:exit, reason, _stacktrace), do: reason
143161
defp exit_reason(:throw, reason, stacktrace), do: {{:nocatch, reason}, stacktrace}

lib/logger/lib/logger/translator.ex

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,30 @@ defmodule Logger.Translator do
106106
starter: starter,
107107
function: function,
108108
args: args,
109-
reason: reason,
109+
reason: report_reason,
110110
process_label: process_label
111-
}}
111+
} = report}
112112
) do
113113
opts = Application.get_env(:logger, :translator_inspect_opts)
114114

115-
{formatted, reason} = format_reason(reason)
115+
{formatted, reason} = format_reason(report_reason)
116116
metadata = [crash_reason: reason] ++ registered_name(name)
117117

118118
msg =
119-
["\nFunction: #{inspect(function, opts)}"] ++
120-
["\n Args: #{inspect(args, opts)}"]
119+
case report do
120+
%{orphan_compiler_module?: true} when elem(report_reason, 0) == :undef ->
121+
[
122+
"\n Hint: if this module is defined somewhere, this error may have happened because processes " <>
123+
"were spawned during Elixir's compilation and these processes are unable to load modules defined " <>
124+
"by the compiler. In such cases, consider using Kernel.ParallelCompiler.pmap/2 instead"
125+
]
126+
127+
_ ->
128+
[]
129+
end
130+
131+
msg =
132+
["\nFunction: #{inspect(function, opts)}\n Args: #{inspect(args, opts)}"] ++ msg
121133

122134
msg =
123135
case process_label do

lib/logger/test/logger/translator_test.exs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,30 @@ defmodule Logger.TranslatorTest do
665665
assert {%UndefinedFunctionError{function: :undef}, [_ | _]} = task_metadata[:crash_reason]
666666
end
667667

668+
test "translates Task undef function crash with orphan compiler module" do
669+
# Start once so all modules are loaded
670+
Task.start(__MODULE__, :undef, [])
671+
672+
assert capture_log(fn ->
673+
try do
674+
:erlang.process_flag(:error_handler, Kernel.ErrorHandler)
675+
{:ok, pid} = Task.start(__MODULE__, :undef, [])
676+
ref = Process.monitor(pid)
677+
receive do: ({:DOWN, ^ref, _, _, _} -> :ok)
678+
after
679+
:erlang.process_flag(:error_handler, :error_handler)
680+
end
681+
end) =~
682+
"Hint: if this module is defined somewhere, this error may have happened because processes were spawned during Elixir's compilation"
683+
684+
assert_receive {:event,
685+
{:report,
686+
%{
687+
label: {Task.Supervisor, :terminating},
688+
report: %{orphan_compiler_module?: true}
689+
}}, _task_metadata}
690+
end
691+
668692
test "translates Task raising ErlangError" do
669693
parent = self()
670694

0 commit comments

Comments
 (0)