File 7341-erts-Fix-init-crash-slogan.patch of Package erlang
From ede8830346fd553707ccb2d0290d3a4029b9497b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Fri, 2 Jun 2023 11:36:43 +0200
Subject: [PATCH 1/2] erts: Fix 'init' crash slogan
Use the internal routine powering erlang:display/1 instead of
trying to wing it, which left references, maps, and funs invisible
since we apparently hadn't updated this part of the code since
those were added.
---
erts/emulator/beam/bif.c | 40 +++++++++++++++-----
erts/emulator/beam/bif.tab | 2 +-
erts/emulator/test/map_SUITE.erl | 2 +-
erts/preloaded/src/erts_internal.erl | 14 +++++++
erts/preloaded/src/init.erl | 55 +---------------------------
erts/test/erl_print_SUITE.erl | 4 +-
lib/kernel/src/erts_debug.erl | 8 +---
7 files changed, 52 insertions(+), 73 deletions(-)
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 80eb260153..d0f9976a32 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4193,22 +4193,44 @@ BIF_RETTYPE display_1(BIF_ALIST_1)
}
/*
- * erts_debug:display/1 is for debugging erlang:display/1
+ * erts_internal:term_to_string/2 is an internal and undocumented function for
+ * formatting terms during init or other times when io_lib is unavailable.
+ * It can also be used to debug functions that rely on the internal term
+ * printing such as erlang:display/1
*/
-BIF_RETTYPE erts_debug_display_1(BIF_ALIST_1)
+BIF_RETTYPE erts_internal_term_to_string_2(BIF_ALIST_2)
{
+ erts_dsprintf_buf_t *dsbufp;
+ int limit;
int pres;
Eterm res;
Eterm *hp;
- erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64);
- pres = erts_dsprintf(dsbufp, "%.*T\n", INT_MAX, BIF_ARG_1);
- if (pres < 0)
- erts_exit(ERTS_ERROR_EXIT, "Failed to convert term to string: %d (%s)\n",
- -pres, erl_errno_id(-pres));
- hp = HAlloc(BIF_P, 2*dsbufp->str_len); /* we need length * 2 heap words */
+
+ if (is_small(BIF_ARG_2) &&
+ (signed_val(BIF_ARG_2) > 1 &&
+ signed_val(BIF_ARG_2) < INT_MAX)) {
+ limit = signed_val(BIF_ARG_2);
+ } else if (BIF_ARG_2 == am_undefined) {
+ limit = INT_MAX;
+ } else {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ dsbufp = erts_create_tmp_dsbuf(64);
+ pres = erts_dsprintf(dsbufp, "%.*T", limit, BIF_ARG_1);
+
+ if (pres < 0) {
+ erts_exit(ERTS_ERROR_EXIT,
+ "Failed to convert term to string: %d (%s)\n",
+ -pres,
+ erl_errno_id(-pres));
+ }
+
+ hp = HAlloc(BIF_P, 2 * dsbufp->str_len);
res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL);
- erts_printf("%s", dsbufp->str);
+
erts_destroy_tmp_dsbuf(dsbufp);
+
BIF_RET(res);
}
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index e1ca5a961b..74ab523a9b 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -446,7 +446,6 @@ bif erts_debug:same/2
bif erts_debug:flat_size/1
bif erts_debug:get_internal_state/1
bif erts_debug:set_internal_state/2
-bif erts_debug:display/1
bif erts_debug:dist_ext_to_term/2
bif erts_debug:instructions/0
bif erts_debug:interpreter_size/0
@@ -784,3 +783,4 @@ bif maps:from_keys/2
#
ubif erlang:min/2
ubif erlang:max/2
+bif erts_internal:term_to_string/2
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index 5d7546c1a4..ffb10b9285 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -3786,7 +3786,7 @@ make_nontrivial_map(N, Effort) ->
maps:from_list(L).
verify_map_term(Term) ->
- Printed = string:chomp(erts_debug:display(Term)),
+ Printed = string:chomp(erts_internal:term_to_string(Term)),
{ok,Tokens,1} = erl_scan:string(Printed ++ "."),
{ok,ParsedTerm} = erl_parse:parse_term(Tokens),
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index 6688bbfe67..ef1bf2f472 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -119,6 +119,8 @@
-export([dynamic_node_name/0, dynamic_node_name/1]).
+-export([term_to_string/1, term_to_string/2]).
+
%%
%% Await result of send to port
%%
@@ -1060,3 +1062,15 @@ dynamic_node_name(false) ->
false -> ok;
_ -> _ = persistent_term:erase({?MODULE, dynamic_node_name}), ok
end.
+
+-spec term_to_string(T :: term()) -> string().
+
+term_to_string(T) ->
+ term_to_string(T, undefined).
+
+-spec term_to_string(T, Limit) -> string() when
+ T :: term(),
+ Limit :: undefined | pos_integer().
+
+term_to_string(_T, _Limit) ->
+ erlang:nif_error(undefined).
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 7933cfaa34..1f7ef28085 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -315,60 +315,9 @@ boot(Start,Flags,Args) ->
bootpid = BootPid},
boot_loop(BootPid,State).
-%%% Convert a term to a printable string, if possible.
-to_string(X, D) when is_list(X), D < 4 -> % assume string
- F = flatten(X, []),
- case printable_list(F) of
- true when length(F) > 0 -> F;
- _false ->
- List = [to_string(E, D+1) || E <- X],
- flatten(["[",join(List),"]"], [])
- end;
-to_string(X, _D) when is_list(X) ->
- "[_]";
-to_string(X, _D) when is_atom(X) ->
- atom_to_list(X);
-to_string(X, _D) when is_pid(X) ->
- pid_to_list(X);
-to_string(X, _D) when is_float(X) ->
- float_to_list(X);
-to_string(X, _D) when is_integer(X) ->
- integer_to_list(X);
-to_string(X, D) when is_tuple(X), D < 4 ->
- List = [to_string(E, D+1) || E <- tuple_to_list(X)],
- flatten(["{",join(List),"}"], []);
-to_string(X, _D) when is_tuple(X) ->
- "{_}";
-to_string(_X, _D) ->
- "". % can't do anything with it
-
-%% This is an incorrect and narrow definition of printable characters.
-%% The correct one is in io_lib:printable_list/1
-%%
-printable_list([H|T]) when is_integer(H), H >= 32, H =< 126 ->
- printable_list(T);
-printable_list([$\n|T]) -> printable_list(T);
-printable_list([$\r|T]) -> printable_list(T);
-printable_list([$\t|T]) -> printable_list(T);
-printable_list([]) -> true;
-printable_list(_) -> false.
-
-join([] = T) ->
- T;
-join([_Elem] = T) ->
- T;
-join([Elem|T]) ->
- [Elem,","|join(T)].
-
-flatten([H|T], Tail) when is_list(H) ->
- flatten(H, flatten(T, Tail));
-flatten([H|T], Tail) ->
- [H|flatten(T, Tail)];
-flatten([], Tail) ->
- Tail.
-
things_to_string([X|Rest]) ->
- " (" ++ to_string(X, 0) ++ ")" ++ things_to_string(Rest);
+ " (" ++ erts_internal:term_to_string(X, 32768) ++ ")" ++
+ things_to_string(Rest);
things_to_string([]) ->
"".
diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl
index 2c3cae64c1..49f9f03945 100644
--- a/erts/test/erl_print_SUITE.erl
+++ b/erts/test/erl_print_SUITE.erl
@@ -174,8 +174,8 @@ get_chnl_no(NodeName) when is_atom(NodeName) ->
erts_debug:get_internal_state({channel_number, NodeName}).
chk_display(Term, Expect) when is_list(Expect) ->
- Dstr = erts_debug:display(Term),
- case Expect ++ io_lib:nl() of
+ Dstr = erts_internal:term_to_string(Term),
+ case Expect of
Dstr ->
io:format("Test of \"~p\" succeeded.~n"
" Expected and got: ~s~n",
diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl
index 6cf3e211e8..9b939e39d1 100644
--- a/lib/kernel/src/erts_debug.erl
+++ b/lib/kernel/src/erts_debug.erl
@@ -31,7 +31,7 @@
%%% BIFs
--export([breakpoint/2, disassemble/1, display/1, dist_ext_to_term/2,
+-export([breakpoint/2, disassemble/1, dist_ext_to_term/2,
flat_size/1, get_internal_state/1, instructions/0,
interpreter_size/0,
map_info/1, same/2, set_internal_state/2,
@@ -69,12 +69,6 @@ breakpoint(_, _) ->
disassemble(_) ->
erlang:nif_error(undef).
--spec display(Term) -> string() when
- Term :: term().
-
-display(_) ->
- erlang:nif_error(undef).
-
-spec dist_ext_to_term(Tuple, Binary) -> term() when
Tuple :: tuple(),
Binary :: binary().
--
2.35.3