Skip to content

Commit d084c02

Browse files
committed
if an erlang error escapes it causes ReportException to fail and hide the real error
1 parent 5c97c68 commit d084c02

File tree

2 files changed

+105
-1
lines changed

2 files changed

+105
-1
lines changed

lib/grpc/server/adapters/report_exception.ex

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,24 @@ defmodule GRPC.Server.Adapters.ReportException do
55

66
defexception [:kind, :reason, :stack, :adapter_extra]
77

8-
def new(adapter_extra, %{__exception__: _} = exception, stack \\ [], kind \\ :error) do
8+
def new(adapter_extra, exception, stack \\ [], kind \\ :error)
9+
10+
def new(adapter_extra, %{__exception__: _} = exception, stack, kind) do
911
exception(kind: kind, reason: exception, stack: stack, adapter_extra: adapter_extra)
1012
end
1113

14+
def new(adapter_extra, {erl_error, erl_stack}, _stack, kind) do
15+
new(adapter_extra, Exception.normalize(:error, erl_error, erl_stack), erl_stack, kind)
16+
end
17+
18+
def new(adapter_extra, erl_error, stack, kind) do
19+
new(adapter_extra, Exception.normalize(:error, erl_error, stack), stack, kind)
20+
end
21+
22+
def message(%__MODULE__{adapter_extra: [{:req, :ok}], kind: kind, reason: reason, stack: stack}) do
23+
Exception.format_banner(kind, reason, stack)
24+
end
25+
1226
def message(%__MODULE__{adapter_extra: [{:req, req}], kind: kind, reason: reason, stack: stack}) do
1327
# Cowboy adapter message builder
1428
path = :cowboy_req.path(req)
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
defmodule ExceptionServer do
2+
use GenServer
3+
4+
# Callbacks
5+
6+
@impl true
7+
def init(pid) do
8+
{:ok, pid}
9+
end
10+
11+
@impl true
12+
def handle_cast(:case_boom, state) do
13+
a = fn -> :ok end
14+
case a.() do
15+
:error -> :boom
16+
end
17+
18+
{:noreply, state}
19+
end
20+
21+
@impl true
22+
def handle_cast(:bad_arg_boom, state) do
23+
ets = :ets.new(:foo, [])
24+
:ets.delete(ets)
25+
:ets.insert(ets, 1)
26+
27+
{:noreply, state}
28+
end
29+
30+
@impl true
31+
def terminate(reason, state) do
32+
send(state, {:boom, reason})
33+
:ok
34+
end
35+
end
36+
37+
defmodule GRPC.Server.Adapters.ReportExceptionTest do
38+
use ExUnit.Case, async: true
39+
alias GRPC.Server.Adapters.ReportException
40+
41+
describe "new/3" do
42+
test "with runtime error" do
43+
assert %GRPC.Server.Adapters.ReportException{
44+
__exception__: true,
45+
adapter_extra: [req: :ok],
46+
kind: :error,
47+
reason: %RuntimeError{message: "hi", __exception__: true},
48+
stack: []
49+
} == ReportException.new([req: :ok], RuntimeError.exception("hi"))
50+
end
51+
52+
test "with case clause error" do
53+
{:ok, pid} = GenServer.start_link(ExceptionServer, self())
54+
55+
GenServer.cast(pid, :case_boom)
56+
57+
receive do
58+
{:boom, {_reason, stack} = err} ->
59+
assert %GRPC.Server.Adapters.ReportException{
60+
__exception__: true,
61+
adapter_extra: [req: :ok],
62+
kind: :error,
63+
reason: %CaseClauseError{term: :ok},
64+
stack: stack
65+
} == ReportException.new([{:req, :ok}], err)
66+
end
67+
end
68+
69+
test "with badarg error" do
70+
{:ok, pid} = GenServer.start_link(ExceptionServer, self())
71+
72+
GenServer.cast(pid, :bad_arg_boom)
73+
74+
receive do
75+
{:boom, {_reason, stack} = err} ->
76+
assert %GRPC.Server.Adapters.ReportException{
77+
__exception__: true,
78+
adapter_extra: [req: :ok],
79+
kind: :error,
80+
reason: %ArgumentError{
81+
__exception__: true,
82+
message:
83+
"errors were found at the given arguments:\n\n * 1st argument: the table identifier does not refer to an existing ETS table\n * 2nd argument: not a tuple\n"
84+
},
85+
stack: stack
86+
} == ReportException.new([{:req, :ok}], err)
87+
end
88+
end
89+
end
90+
end

0 commit comments

Comments
 (0)