From 7b169140b2d37f43996b9d1a94877926a471d97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 2 May 2017 05:41:17 +0200 Subject: Warn for potentially unsafe use of get_stacktrace/0 erlang:get_stacktrace/0 returns the stacktrace for the latest exception. The problem is that the stacktrace is kept until the next exception occurs. If the last exception was a 'function_clause' or a 'badarg', the arguments for the call are also kept forever. The arguments can be terms of any size (potentially huge). In a future release, we would like to only allow erlang:get_stacktrace/0 from within a 'try' expression. That would make it possible to clear the stacktrace when the 'try' expression is exited. The 'catch' expression has no natural end where the stacktrace could be cleared. The stacktrace could be cleared at the end of the function that the 'catch' occurs in, but that would cause problems in the following scenario (from real life, but simplified): try ... catch _:_ -> io:format(...), io:format("~p\n", [erlang:get_stacktrace()]) end. %% In io.erl. format(Fmt, Args) -> Res = case ... of SomePattern -> catch... ...; SomeOtherPattern -> %% Output the formatted string here ... end, clear_stacktrace(), %% Inserted by compiler. Res. The call to io:format() would always clear the stacktrace before it could be retrieved. That problem could be solved by tightning the scope in which the stacktrace is kept, but the rules for how long erlang:get_stacktrace/0 would work would become complicated. Therefore, the solution we suggest for a future major release of OTP is that erlang:get_stacktrace/0 will return [] if it is called outside the 'catch' part of a 'try' expression. To help users prepare, introduce a warning when it is likely that erlang:get_stacktrace/0 will always return an empty list, for example in this code: catch error(foo), Stk = erlang:get_stacktrace() or in this code: try Expr catch _:_ -> ok end, Stk = erlang:get_stacktrace() --- erts/doc/src/erlang.xml | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'erts/doc/src/erlang.xml') diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 6f70ae4a52..6d165e9eff 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -1813,8 +1813,9 @@ true Get the call stack back-trace of the last exception. -

Gets the call stack back-trace (stacktrace) of the - last exception in the calling process as a list of +

Gets the call stack back-trace (stacktrace) for an + exception that has just been caught + in the calling process as a list of {Module,Function,Arity,Location} tuples. Field Arity in the first tuple can be the argument list of that function call instead of an arity integer, @@ -1822,6 +1823,29 @@ true

If there has not been any exceptions in a process, the stacktrace is []. After a code change for the process, the stacktrace can also be reset to [].

+

erlang:get_stacktrace/0 is only guaranteed to return + a stacktrace if called (directly or indirectly) from within the + scope of a try expression. That is, the following call works:

+
+try Expr
+catch
+  C:R ->
+   {C,R,erlang:get_stacktrace()}
+end
+

As does this call:

+
+try Expr
+catch
+  C:R ->
+   {C,R,helper()}
+end
+
+helper() ->
+  erlang:get_stacktrace().
+ +

In a future release, + erlang:get_stacktrace/0 will return [] if called + from outside a try expression.

The stacktrace is the same data as operator catch returns, for example:

-- 
cgit v1.2.3