From a22b5ba19193e3f39129fadd20d375f6cc3f8529 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Tue, 1 Sep 2015 19:53:40 +0200
Subject: erts: Fix bug when tracing with 'process_dump'

If the process stack contained a match state
the print function would crash the vm as it was not
recognized by tag_val_def().

Add new MATCHSTATE_DEF returned by tag_val_def().
All other callers either ignore it or has a default
clause to handle invalid terms.
---
 erts/emulator/beam/erl_debug.c       | 3 +++
 erts/emulator/beam/erl_printf_term.c | 9 ++++-----
 erts/emulator/beam/erl_term.c        | 1 +
 erts/emulator/beam/erl_term.h        | 3 +++
 erts/emulator/beam/utils.c           | 9 ++++-----
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index 50bdc79506..b6c131a43e 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -188,6 +188,9 @@ pdisplay1(int to, void *to_arg, Process* p, Eterm obj)
     case BINARY_DEF:
 	erts_print(to, to_arg, "#Bin");
 	break;
+    case MATCHSTATE_DEF:
+        erts_print(to, to_arg, "#Matchstate");
+        break;
     default:
 	erts_print(to, to_arg, "unknown object %x", obj);
     }
diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c
index d18760dc43..ba9a174fdf 100644
--- a/erts/emulator/beam/erl_printf_term.c
+++ b/erts/emulator/beam/erl_printf_term.c
@@ -441,11 +441,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
 	    PRINT_DOUBLE(res, fn, arg, 'e', 6, 0, ff.fd);
 	}
 	    break;
-	case BINARY_DEF:
-	    if (header_is_bin_matchstate(*boxed_val(wobj))) {
-		PRINT_STRING(res, fn, arg, "#MatchState");
-	    }
-	    else {
+	case BINARY_DEF: {
 		ProcBin* pb = (ProcBin *) binary_val(wobj);
 		if (pb->size == 1)
 		    PRINT_STRING(res, fn, arg, "<<1 byte>>");
@@ -519,6 +515,9 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount,
 		}
 	    }
 	    break;
+        case MATCHSTATE_DEF:
+            PRINT_STRING(res, fn, arg, "#MatchState");
+            break;
 	default:
 	    PRINT_STRING(res, fn, arg, "<unknown:");
 	    PRINT_POINTER(res, fn, arg, wobj);
diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c
index 28cbe7004f..07818472ec 100644
--- a/erts/emulator/beam/erl_term.c
+++ b/erts/emulator/beam/erl_term.c
@@ -90,6 +90,7 @@ unsigned tag_val_def(Wterm x)
 	    case (_TAG_HEADER_HEAP_BIN >> _TAG_PRIMARY_SIZE):	return BINARY_DEF;
 	    case (_TAG_HEADER_SUB_BIN >> _TAG_PRIMARY_SIZE):	return BINARY_DEF;
 	    case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE):	return MAP_DEF;
+	    case (_TAG_HEADER_BIN_MATCHSTATE >> _TAG_PRIMARY_SIZE): return MATCHSTATE_DEF;
 	  }
 	  break;
       }
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index 37014ccf94..1b6bb27395 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -1095,6 +1095,9 @@ _ET_DECLARE_CHECKED(Uint,y_reg_index,Uint)
 #define FLOAT_DEF		0xe
 #define BIG_DEF			0xf
 #define SMALL_DEF		0x10
+#define MATCHSTATE_DEF          0x11   /* not a "real" term */
+
+#define FIRST_VACANT_TAG_DEF    0x12
 
 #if ET_DEBUG
 extern unsigned tag_val_def_debug(Wterm, const char*, unsigned);
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index f810fca9a4..a8bbdb9354 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -788,11 +788,10 @@ Uint32 make_hash(Eterm term_arg)
     Eterm hash = 0;
     unsigned op;
 
-    /* Must not collide with the real tag_val_def's: */
-#define MAKE_HASH_TUPLE_OP 0x11
-#define MAKE_HASH_TERM_ARRAY_OP 0x12
-#define MAKE_HASH_CDR_PRE_OP 0x13
-#define	MAKE_HASH_CDR_POST_OP 0x14
+#define MAKE_HASH_TUPLE_OP      (FIRST_VACANT_TAG_DEF)
+#define MAKE_HASH_TERM_ARRAY_OP (FIRST_VACANT_TAG_DEF+1)
+#define MAKE_HASH_CDR_PRE_OP    (FIRST_VACANT_TAG_DEF+2)
+#define MAKE_HASH_CDR_POST_OP   (FIRST_VACANT_TAG_DEF+3)
 
     /* 
     ** Convenience macro for calculating a bytewise hash on an unsigned 32 bit 
-- 
cgit v1.2.3


From 0c52e3c18da16dbb896871865b71093b8c5617c4 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Tue, 1 Sep 2015 19:09:39 +0200
Subject: erts: Add testcase for tracing whith 'process_dump'

of a process with a matchstate on the stack.
---
 erts/emulator/test/match_spec_SUITE.erl | 60 +++++++++++++++++++++------------
 1 file changed, 39 insertions(+), 21 deletions(-)

diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index fdce157abc..bfa09c625f 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -167,12 +167,11 @@ test_1(Config) when is_list(Config) ->
 	     [{['$1','$1'],[{is_atom, '$1'}],[kakalorum]}],
 	     [{call, {?MODULE, f2, [a, a]}}]),
 
-%    case tr0(fun() -> ?MODULE:f2(a, a) end,
-%	     {?MODULE, f2, 2},
-%	     [{['$1','$1'],[{is_atom, '$1'}],[{message, {process_dump}}]}]) of
-%	[{trace, _, call, {?MODULE, f2, [a, a]}, Bin}] ->
-%	    erlang:display(binary_to_list(Bin))
-%    end,
+    %% Verify that 'process_dump' can handle a matchstate on the stack.
+    tr(fun() -> fbinmatch(<<0>>, 0) end,
+       {?MODULE, f1, 1},
+       [{['_'],[],[{message, {process_dump}}]}],
+       [fun({trace, _, call, {?MODULE, f1, [0]}, _Bin}) -> true end]),
 
 % Error cases
     ?line errchk([{['$1','$1'],[{is_atom, '$1'}],[{banka, kanin}]}]),
@@ -928,14 +927,14 @@ tr(Fun, MFA, TraceFlags, Pat, PatFlags, Expected0) ->
 	       erlang:trace(P, true, TraceFlags),
 	       erlang:trace_pattern(MFA, Pat, PatFlags),
 	       lists:map(
-		 fun(X) -> 
-			 list_to_tuple([trace, P | tuple_to_list(X)])
+		 fun(X) when is_function(X,1) -> X;
+		    (X) -> list_to_tuple([trace, P | tuple_to_list(X)])
 		 end,
 		 Expected0)
        end).
 
 tr(RunFun, ControlFun) ->
-    P = spawn(?MODULE, runner, [self(), RunFun]),
+    P = spawn_link(?MODULE, runner, [self(), RunFun]),
     collect(P, ControlFun(P)).
 
 collect(P, TMs) ->
@@ -954,18 +953,33 @@ collect([]) ->
 collect([TM | TMs]) ->
     ?t:format(        "Expecting:      ~p~n", [TM]),
     receive
-	M ->
-	    case if element(1, M) == trace_ts ->
-			 list_to_tuple(lists:reverse(
-					 tl(lists:reverse(tuple_to_list(M)))));
-		    true -> M
-		 end of
-		TM ->
-		    ?t:format("Got:            ~p~n", [M]),
-		    collect(TMs);
-		_ ->
-		    ?t:format("Got unexpected: ~p~n", [M]),
-		    flush({got_unexpected,M})
+	M0 ->
+	    M = case element(1, M0) of
+		    trace_ts ->
+			list_to_tuple(lists:reverse(
+					tl(lists:reverse(tuple_to_list(M0)))));
+		    _ -> M0
+		end,
+	    case is_function(TM,1) of
+		true ->
+		    case (catch TM(M)) of
+			true ->
+			    ?t:format("Got:            ~p~n", [M]),
+			    collect(TMs);
+			_ ->
+			    ?t:format("Got unexpected: ~p~n", [M]),
+			    flush({got_unexpected,M})
+		    end;
+
+		false ->
+		    case M of
+			TM ->
+			    ?t:format("Got:            ~p~n", [M]),
+			    collect(TMs);
+			_ ->
+			    ?t:format("Got unexpected: ~p~n", [M]),
+			    flush({got_unexpected,M})
+		    end
 	    end
     end.
 
@@ -1045,6 +1059,10 @@ fn(X, Y) ->
 fn(X, Y, Z) ->
     [X, Y, Z].
 
+fbinmatch(<<Int, Rest/binary>>, Acc) ->
+    fbinmatch(Rest, [?MODULE:f1(Int) | Acc]);
+fbinmatch(<<>>, Acc) -> Acc.
+
 id(X) ->
     X.
 
-- 
cgit v1.2.3