File 2921-erts-Implement-erlang-display_string-2-used-for-test.patch of Package erlang

From 3e4baaee6543befa35e604b9d40391c719d0d752 Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas@erlang.org>
Date: Thu, 12 May 2022 13:55:12 +0200
Subject: [PATCH 01/34] erts: Implement erlang:display_string/2 used for
 testing

---
 erts/emulator/beam/bif.c               |  83 ++++++++++++++++++++-----
 erts/emulator/beam/bif.tab             |   2 +-
 erts/emulator/beam/erl_dirty_bif.tab   |   1 +
 erts/emulator/beam/sys.h               |   2 +-
 erts/emulator/test/exception_SUITE.erl |   2 +
 erts/preloaded/ebin/erlang.beam        | Bin 132536 -> 132836 bytes
 erts/preloaded/src/erlang.erl          |  15 ++++-
 lib/kernel/src/erl_erts_errors.erl     |  30 ++++++++-
 8 files changed, 116 insertions(+), 19 deletions(-)

diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 1d0a145f3f..c8e7caac15 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -23,6 +23,10 @@
 #endif
 
 #include <stddef.h> /* offsetof() */
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#define WANT_NONBLOCKING
 #include "sys.h"
 #include "erl_vm.h"
 #include "erl_sys_driver.h"
@@ -4180,27 +4184,78 @@ BIF_RETTYPE erts_debug_display_1(BIF_ALIST_1)
     BIF_RET(res);
 }
 
-
-BIF_RETTYPE display_string_1(BIF_ALIST_1)
+BIF_RETTYPE display_string_2(BIF_ALIST_2)
 {
     Process* p = BIF_P;
-    Eterm string = BIF_ARG_1;
-    Sint len = erts_unicode_list_to_buf_len(string);
+    Eterm string = BIF_ARG_2;
+    Sint len;
     Sint written;
     byte *str;
-    int res;
+    int res, fd;
+    byte *temp_alloc = NULL;
+
+    if (ERTS_IS_ATOM_STR("stdout", BIF_ARG_1)) {
+        fd = fileno(stdout);
+    } else if (ERTS_IS_ATOM_STR("stderr", BIF_ARG_1)) {
+        fd = fileno(stderr);
+#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCSTI)
+    } else if (ERTS_IS_ATOM_STR("stdin", BIF_ARG_1)) {
+        fd = open("/proc/self/fd/0",0);
+#endif
+    } else {
+        BIF_ERROR(p, BADARG);
+    }
+    if (is_list(string) || is_nil(string)) {
+        len = erts_unicode_list_to_buf_len(string);
+        if (len < 0) BIF_ERROR(p, BADARG);
+        str = temp_alloc = (byte *) erts_alloc(ERTS_ALC_T_TMP, sizeof(char)*len);
+        res = erts_unicode_list_to_buf(string, str, len, &written);
+        if (res != 0 || written != len)
+            erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error (%d)\n", __FILE__, __LINE__, res);
+    } else if (is_binary(string)) {
+        Uint bitoffs, bitsize;
+        ERTS_GET_BINARY_BYTES(string, str, bitoffs, bitsize);
+        if (bitsize % 8 != 0) BIF_ERROR(p, BADARG);
+        len = binary_size(string);
+        if (bitoffs != 0) {
+            str = erts_get_aligned_binary_bytes(string, &temp_alloc);
+        }
+    } else {
+        BIF_ERROR(p, BADARG);
+    }
 
-    if (len < 0) {
-	BIF_ERROR(p, BADARG);
+#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCSTI)
+    if (ERTS_IS_ATOM_STR("stdin", BIF_ARG_1)) {
+        for (int i = 0; i < len; i++) {
+            if (ioctl(fd, TIOCSTI, str+i) < 0) {
+                fprintf(stderr,"failed to write to %s (%s)\r\n", "/proc/self/fd/0",
+                        strerror(errno));
+                close(fd);
+                goto error;
+            }
+        }
+        close(fd);
+    } else
+#endif
+    {
+        written = 0;
+        do {
+            res = write(fd, str+written, len-written);
+            if (res < 0 && errno != ERRNO_BLOCK && errno != EINTR)
+                goto error;
+            written += res;
+        } while (written < len);
     }
-    str = (byte *) erts_alloc(ERTS_ALC_T_TMP, sizeof(char)*(len + 1));
-    res = erts_unicode_list_to_buf(string, str, len, &written);
-    if (res != 0 || written != len)
-	erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error (%d)\n", __FILE__, __LINE__, res);
-    str[len] = '\0';
-    erts_fprintf(stderr, "%s", str);
-    erts_free(ERTS_ALC_T_TMP, (void *) str);
+    if (temp_alloc)
+        erts_free(ERTS_ALC_T_TMP, (void *) temp_alloc);
     BIF_RET(am_true);
+
+error: {
+        char *errnostr = erl_errno_id(errno);
+        BIF_P->fvalue = am_atom_put(errnostr, strlen(errnostr));
+        erts_free(ERTS_ALC_T_TMP, (void *) str);
+        BIF_ERROR(p, BADARG | EXF_HAS_EXT_INFO);
+    }
 }
 
 BIF_RETTYPE display_nl_0(BIF_ALIST_0)
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index dffe3963b5..17f35a1bc7 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -56,7 +56,7 @@ bif erlang:crc32_combine/3
 bif erlang:date/0
 bif erlang:delete_module/1
 bif erlang:display/1
-bif erlang:display_string/1
+bif erlang:display_string/2
 bif erlang:display_nl/0
 ubif erlang:element/2
 bif erlang:erase/0
diff --git a/erts/emulator/beam/erl_dirty_bif.tab b/erts/emulator/beam/erl_dirty_bif.tab
index 3f16f3e0f3..9245a19be6 100644
--- a/erts/emulator/beam/erl_dirty_bif.tab
+++ b/erts/emulator/beam/erl_dirty_bif.tab
@@ -50,6 +50,7 @@ dirty-io erts_debug:dirty_io/2
 dirty-cpu erts_debug:lcnt_control/2
 dirty-cpu erts_debug:lcnt_collect/0
 dirty-cpu erts_debug:lcnt_clear/0
+dirty-cpu erlang:display_string/2
 
 # --- TEST of Dirty BIF functionality ---
 #  Functions below will execute on dirty schedulers when emulator has
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 20b0571e43..b57cfd6952 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -608,7 +608,7 @@ extern erts_tsd_key_t erts_is_crash_dumping_key;
 static unsigned long zero_value = 0, one_value = 1;
 #    define SET_BLOCKING(fd)	{ if (ioctlsocket((fd), FIONBIO, &zero_value) != 0) fprintf(stderr, "Error setting socket to non-blocking: %d\n", WSAGetLastError()); }
 #    define SET_NONBLOCKING(fd)	ioctlsocket((fd), FIONBIO, &one_value)
-
+#    define ERRNO_BLOCK EAGAIN /* We use the posix way for windows */
 #  else
 #    ifdef NB_FIONBIO		/* Old BSD */
 #      include <sys/ioctl.h>
diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl
index 5cce5d1491..dfec2a28dc 100644
--- a/erts/emulator/test/exception_SUITE.erl
+++ b/erts/emulator/test/exception_SUITE.erl
@@ -851,6 +851,8 @@ error_info(_Config) ->
 
          {display, ["test erlang:display/1"], [no_fail]},
          {display_string, [{a,b,c}]},
+         {display_string, [standard_out,"test erlang:display/2"]},
+         {display_string, [stdout,{a,b,c}]},
 
          %% Internal undcoumented BIFs.
          {dist_ctrl_get_data, 1},
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 8afcfd37ad..7c6d2376f4 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -216,7 +216,7 @@
 -export([crc32/2, crc32_combine/3, date/0, decode_packet/3]).
 -export([delete_element/2]).
 -export([delete_module/1, demonitor/1, demonitor/2, display/1]).
--export([display_nl/0, display_string/1, erase/0, erase/1]).
+-export([display_nl/0, display_string/1, display_string/2, erase/0, erase/1]).
 -export([error/1, error/2, error/3, exit/1, exit/2, exit_signal/2, external_size/1]).
 -export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]).
 -export([float_to_binary/1, float_to_binary/2,
@@ -850,8 +850,19 @@ display_nl() ->
 
 %% display_string/1
 -spec erlang:display_string(P1) -> true when
+      P1 :: string() | binary().
+display_string(String) ->
+    try erlang:display_string(stderr, String)
+    catch error:badarg:ST ->
+            [{erlang, display_string, _, [ErrorInfo]}|_] = ST,
+            erlang:error(badarg, [String], [ErrorInfo])
+    end.
+
+%% display_string/2
+-spec erlang:display_string(Device, P1) -> true when
+      Device :: stdin | stdout | stderr,
       P1 :: string().
-display_string(_P1) ->
+display_string(_Stream,_P1) ->
     erlang:nif_error(undefined).
 
 %% dt_append_vm_tag_data/1
diff --git a/lib/kernel/src/erl_erts_errors.erl b/lib/kernel/src/erl_erts_errors.erl
index 4d23112b83..fe7758dae0 100644
--- a/lib/kernel/src/erl_erts_errors.erl
+++ b/lib/kernel/src/erl_erts_errors.erl
@@ -352,8 +352,19 @@ format_erlang_error(demonitor, [_], _) ->
 format_erlang_error(demonitor, [Ref,Options], _) ->
     Arg1 = must_be_ref(Ref),
     [Arg1,maybe_option_list_error(Options, Arg1)];
-format_erlang_error(display_string, [_], _) ->
+format_erlang_error(display_string, [_], none) ->
     [not_string];
+format_erlang_error(display_string, [_], Cause) ->
+    maybe_posix_message(Cause, false);
+format_erlang_error(display_string, [Device, _], none) ->
+    case lists:member(Device,[stdin,stdout,stderr]) of
+        true ->
+            [[],not_string];
+        false ->
+            [not_device,[]]
+    end;
+format_erlang_error(display_string, [_, _], Cause) ->
+    maybe_posix_message(Cause, true);
 format_erlang_error(element, [Index, Tuple], _) ->
     [if
          not is_integer(Index) ->
@@ -1430,8 +1441,23 @@ is_flat_char_list([H|T]) ->
 is_flat_char_list([]) -> true;
 is_flat_char_list(_) -> false.
 
+maybe_posix_message(Cause, HasDevice) ->
+    case erl_posix_msg:message(Cause) of
+        "unknown POSIX error" ->
+            unknown;
+        PosixStr when HasDevice ->
+            [unicode:characters_to_binary(
+               io_lib:format("~ts (~tp)",[PosixStr, Cause]))];
+        PosixStr when not HasDevice ->
+            [{general,
+              unicode:characters_to_binary(
+                io_lib:format("~ts (~tp)",[PosixStr, Cause]))}]
+    end.
+
 format_error_map([""|Es], ArgNum, Map) ->
     format_error_map(Es, ArgNum + 1, Map);
+format_error_map([{general, E}|Es], ArgNum, Map) ->
+    format_error_map(Es, ArgNum, Map#{ general => expand_error(E)});
 format_error_map([E|Es], ArgNum, Map) ->
     format_error_map(Es, ArgNum + 1, Map#{ArgNum => expand_error(E)});
 format_error_map([], _, Map) ->
@@ -1519,6 +1545,8 @@ expand_error(not_ref) ->
     <<"not a reference">>;
 expand_error(not_string) ->
     <<"not a list of characters">>;
+expand_error(not_device) ->
+    <<"not a valid device type">>;
 expand_error(not_tuple) ->
     <<"not a tuple">>;
 expand_error(range) ->
-- 
2.35.3

openSUSE Build Service is sponsored by