From 3f7d4324c7b99f93a6ad36015071276692534fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 15 Feb 2017 14:23:59 +0100 Subject: encode/decode: Include the stack trace in error returns The generated encode/2 and decode/2 functions can return cryptic error messages. Consider this ASN.1 spec: T DEFINITIONS AUTOMATIC TAGS ::= BEGIN S ::= SEQUENCE { b BOOLEAN, i INTEGER (1..100), j INTEGER (0..7), s OCTET STRING } END In OTP 19, the error terms will look like this: Eshell V8.2 (abort with ^G) 1> asn1ct:compile('T', [ber]). ok 2> rr('T'). ['S'] 3> 'T':encode('S', #'S'{}). {error,{asn1,{encode_boolean,undefined}}} 4> 'T':encode('S', #'S'{b=false}). {error,{asn1,{encode_integer,undefined}}} 5> 'T':encode('S', #'S'{b=false,i=7,j=0}). {error,{asn1,function_clause}} Some error terms are clearer than other. In the first error term, it is clear that the error refers to the 'b' field, since there is only one BOOLEAN in 'S'. The second error term could refer to either 'i' or 'j'. The last error term... well... in this case we can infer that it must refer to 's'. The easiest way to provide more information is to include the stack trace with line numbers in the error term: 3> 'T':encode('S', #'S'{b=false}). {error,{asn1,{{encode_integer,undefined}, [{'T',encode_integer,2,[{file,"T.erl"},{line,240}]}, {'T',enc_S,2,[{file,"T.erl"},{line,102}]}, {'T',encode,2,[{file,"T.erl"},{line,36}]}, {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]}, {shell,exprs,7,[{file,"shell.erl"},{line,686}]}, {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]}, {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}}} By looking at the generated Erlang code, we can see that encoding failed for 'i'. This is an compatible change. All that the documentation says is that the format of the error tuple is: {error,{asn1,Description}} With this change, Description is always a tuple: {ErrorDescription,StackTrace} Alternatives considered: Providing more information in the error term itself and make sure there can be no 'function_clause', 'badarg', or 'badmatch' exceptions. That would be possible, but it would require a lot of work and it would increase the size of the generated code and make it slower. Therefore, this solution was rejected. --- lib/asn1/src/asn1ct_gen.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib/asn1/src/asn1ct_gen.erl') diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index 9943bd056a..9f628c7b04 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -802,11 +802,12 @@ result_line_1(Items) -> try_catch() -> [" catch",nl, " Class:Exception when Class =:= error; Class =:= exit ->",nl, + " Stk = erlang:get_stacktrace(),",nl, " case Exception of",nl, - " {error,Reason}=Error ->",nl, - " Error;",nl, + " {error,{asn1,Reason}} ->",nl, + " {error,{asn1,{Reason,Stk}}};",nl, " Reason ->",nl, - " {error,{asn1,Reason}}",nl, + " {error,{asn1,{Reason,Stk}}}",nl, " end",nl, "end."]. -- cgit v1.2.1