summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Frantzen <71122361+frazze-jobb@users.noreply.github.com>2023-05-11 15:22:38 +0200
committerGitHub <noreply@github.com>2023-05-11 15:22:38 +0200
commit5f892f7b836be7f725d9e2ef13c6444e2aa474b6 (patch)
treed2af9db76c5d99dfcd8ff895eb268d4e9173a2e5
parent3187153fb297fc9b5a0964dff9d08deb93e494ad (diff)
parent911461e585a1ab82857b501ca6c9ffb31c2efd8c (diff)
downloaderlang-5f892f7b836be7f725d9e2ef13c6444e2aa474b6.tar.gz
Merge branch 'master' into frazze/stdlib/multiline_editing
-rw-r--r--erts/etc/common/erlc.c4
-rw-r--r--lib/kernel/src/group.erl35
-rw-r--r--lib/kernel/src/prim_tty.erl5
-rw-r--r--lib/kernel/src/user_drv.erl4
-rw-r--r--lib/ssl/doc/src/ssl.xml64
-rw-r--r--lib/ssl/src/ssl.erl45
-rw-r--r--lib/ssl/src/tls_client_connection_1_3.erl10
-rw-r--r--lib/ssl/src/tls_v1.erl18
-rw-r--r--lib/ssl/test/ssl_reject_SUITE.erl5
-rw-r--r--lib/ssl/test/tls_api_SUITE.erl22
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl45
-rw-r--r--lib/wx/c_src/Makefile.in6
-rwxr-xr-xotp_build10
-rwxr-xr-xscripts/otp_build_check344
-rw-r--r--system/doc/general_info/upcoming_incompatibilities.xml60
15 files changed, 637 insertions, 40 deletions
diff --git a/erts/etc/common/erlc.c b/erts/etc/common/erlc.c
index 3683a47064..1493c6f6ff 100644
--- a/erts/etc/common/erlc.c
+++ b/erts/etc/common/erlc.c
@@ -748,8 +748,10 @@ call_compile_server(char** argv)
ei_x_encode_atom(&args, "command_line");
argc = 0;
while (argv[argc]) {
+ char *arg;
ei_x_encode_list_header(&args, 1);
- ei_x_encode_binary(&args, possibly_unquote(argv[argc]), strlen(argv[argc]));
+ arg = possibly_unquote(argv[argc]);
+ ei_x_encode_binary(&args, arg, strlen(arg));
argc++;
}
ei_x_encode_empty_list(&args); /* End of command_line */
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index 65b39489c4..ca7251d7ec 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -40,6 +40,7 @@ server(Ancestors, Drv, Shell, Options) ->
put(line_buffer, proplists:get_value(line_buffer, Options, group_history:load())),
put(read_mode, list),
put(user_drv, Drv),
+ put(unicode_state, true),
ExpandFun = normalize_expand_fun(Options, fun edlin_expand:expand/2),
put(expand_fun, ExpandFun),
put(echo, proplists:get_value(echo, Options, true)),
@@ -239,17 +240,27 @@ io_request({put_chars,unicode,M,F,As}, Drv, _Shell, From, Buf) ->
end
end;
io_request({put_chars,latin1,Binary}, Drv, _Shell, From, Buf) when is_binary(Binary) ->
- send_drv(Drv, {put_chars_sync, unicode,
- unicode:characters_to_binary(Binary,latin1),
- From}),
+ IsUnicode = get(unicode_state),
+ if IsUnicode ->
+ send_drv(Drv,
+ {put_chars_sync, unicode,
+ unicode:characters_to_binary(Binary,latin1),
+ From});
+ true ->
+ send_drv(Drv, {put_chars_sync, latin1, Binary, From})
+ end,
{noreply,Buf};
io_request({put_chars,latin1,Chars}, Drv, _Shell, From, Buf) ->
- case catch unicode:characters_to_binary(Chars,latin1) of
- Binary when is_binary(Binary) ->
- send_drv(Drv, {put_chars_sync, unicode, Binary, From}),
- {noreply,Buf};
- _ ->
- {error,{error,{put_chars,latin1,Chars}},Buf}
+ IsUnicode = get(unicode_state),
+ if IsUnicode ->
+ case catch unicode:characters_to_binary(Chars,latin1) of
+ Binary when is_binary(Binary) ->
+ send_drv(Drv, {put_chars_sync, unicode, Binary, From}),
+ {noreply,Buf};
+ _ ->
+ {error,{error,{put_chars,latin1,Chars}},Buf}
+ end;
+ true -> send_drv(Drv, {put_chars_sync, latin1, Chars, From})
end;
io_request({put_chars,latin1,M,F,As}, Drv, _Shell, From, Buf) ->
case catch apply(M, F, As) of
@@ -396,9 +407,11 @@ do_setopts(Opts, Drv, Buf) ->
put(echo, proplists:get_value(echo, Opts, get(echo))),
case proplists:get_value(encoding,Opts) of
Valid when Valid =:= unicode; Valid =:= utf8 ->
- set_unicode_state(Drv,true);
+ set_unicode_state(Drv,true),
+ put(unicode_state, true);
latin1 ->
- set_unicode_state(Drv,false);
+ set_unicode_state(Drv,false),
+ put(unicode_state, false);
_ ->
ok
end,
diff --git a/lib/kernel/src/prim_tty.erl b/lib/kernel/src/prim_tty.erl
index 3a70873748..a03e746cc9 100644
--- a/lib/kernel/src/prim_tty.erl
+++ b/lib/kernel/src/prim_tty.erl
@@ -166,6 +166,7 @@
sig => boolean()
}.
-type request() ::
+ {putc_raw, binary()} |
{putc, unicode:unicode_binary()} |
{putc_keep_state, unicode:unicode_binary()} |
{expand, unicode:unicode_binary()} |
@@ -537,6 +538,8 @@ writer_loop(TTY, WriterRef) ->
-spec handle_request(state(), request()) -> {erlang:iovec(), state()}.
handle_request(State = #state{ options = #{ tty := false } }, Request) ->
case Request of
+ {putc_raw, Binary} ->
+ {Binary, State};
{putc, Binary} ->
{encode(Binary, State#state.unicode), State};
beep ->
@@ -613,6 +616,8 @@ handle_request(State = #state{ unicode = U }, {putc, Binary}) ->
{_, _, _, NewBA} = split(NewLength - OldLength, NewState#state.buffer_after, U),
{encode(PutBuffer, U), NewState#state{ buffer_after = NewBA }}
end;
+handle_request(State, {putc_raw, Binary}) ->
+ handle_request(State, {putc, unicode:characters_to_binary(Binary, latin1)});
handle_request(State = #state{}, delete_after_cursor) ->
{[State#state.delete_after_cursor],
State#state{buffer_after = [],
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index b9d879d33c..25ebcbdd68 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -793,6 +793,10 @@ io_request({put_chars_sync, unicode, Chars, Reply}, TTY) ->
{Output, NewTTY} = prim_tty:handle_request(TTY, {putc, unicode:characters_to_binary(Chars)}),
{ok, MonitorRef} = prim_tty:write(NewTTY, Output, self()),
{Reply, MonitorRef, NewTTY};
+io_request({put_chars_sync, latin1, Chars, Reply}, TTY) ->
+ {Output, NewTTY} = prim_tty:handle_request(TTY, {putc_raw, Chars}),
+ {ok, MonitorRef} = prim_tty:write(NewTTY, Output, self()),
+ {Reply, MonitorRef, NewTTY};
io_request({put_expand, unicode, Chars}, TTY) ->
write(prim_tty:handle_request(TTY, {expand_with_trim, unicode:characters_to_binary(Chars)}));
io_request({put_expand_no_trim, unicode, Chars}, TTY) ->
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 700709ed7a..b4a30a68c8 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -477,12 +477,10 @@
{sha384, ecdsa},
{sha384, rsa},
{sha256, ecdsa},
-{sha256, rsa},
-{sha224, ecdsa},
-{sha224, rsa}
+{sha256, rsa}
]</code>
-<p>Support for {md5, rsa} was removed from the the TLS-1.2 default in ssl-8.0 (OTP-22) and support for SHA1 {sha, _} was removed in ssl-11.0 (OTP-26) </p>
+<p>Support for {md5, rsa} was removed from the the TLS-1.2 default in ssl-8.0 (OTP-22) and support for SHA1 {sha, _} and SHA224 {sha224, _} was removed in ssl-11.0 (OTP-26) </p>
<p><c> rsa_pss_schemes =</c></p>
<code>
@@ -521,10 +519,10 @@ rsa_pss_schemes()
<p>EDDSA was made highest priority in ssl-10.8 (OTP-25) </p>
<p>TLS-1.3 default is</p>
-<code>Default_TLS_13_Schemes ++ Legacy_TLS_13_Schemes </code>
+<code>Default_TLS_13_Schemes</code>
<p>If both TLS-1.3 and TLS-1.2 are supported the default will be</p>
-<code>Default_TLS_13_Schemes ++ Default_TLS_12_Alg_Pairs </code>
+<code>Default_TLS_13_Schemes ++ TLS_13_Legacy_Schemes ++ Default_TLS_12_Alg_Pairs (not represented in TLS_13_Legacy_Schemes) </code>
<p>so appropriate algorithms can be chosen for the negotiated
version.
@@ -2175,6 +2173,60 @@ fun(srp, Username :: binary(), UserState :: term()) ->
is useful.</p>
</desc>
</func>
+
+ <func>
+ <name since="OTP @OTP-18572@" name="signature_algs" arity="2" />
+ <fsummary>Returns a list of signature algorithms/schemes </fsummary>
+ <desc>
+ <p>Lists all possible signature algorithms corresponding to
+ <c>Description</c> that are available. The
+ <c>exclusive</c> option will exclusively list
+ algorithms/schemes for that protocol version, whereas the
+ <c>default</c> and <c>all</c> options lists the combined list to support the
+ range of protocols from (D)TLS-1.2, the first version to support
+ configuration of the signature algorithms, to <c>Version</c>.</p>
+
+ <p> Example: <c>
+
+ 1&gt; ssl:signature_algs(default, 'tlsv1.3').
+ [eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512,
+ ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256,
+ rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256,
+ rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256,
+ rsa_pkcs1_sha512,rsa_pkcs1_sha384,rsa_pkcs1_sha256,
+ {sha512,ecdsa},
+ {sha384,ecdsa},
+ {sha256,ecdsa}]
+
+ 2&gt;ssl:signature_algs(all, 'tlsv1.3').
+ [eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512,
+ ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256,
+ rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256,
+ rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256,
+ rsa_pkcs1_sha512,rsa_pkcs1_sha384,rsa_pkcs1_sha256,
+ {sha512,ecdsa},
+ {sha384,ecdsa},
+ {sha256,ecdsa},
+ {sha224,ecdsa},
+ {sha224,rsa},
+ {sha,rsa},
+ {sha,dsa}]
+
+ 3&gt; ssl:signature_algs(exclusive, 'tlsv1.3').
+ [eddsa_ed25519,eddsa_ed448,ecdsa_secp521r1_sha512,
+ ecdsa_secp384r1_sha384,ecdsa_secp256r1_sha256,
+ rsa_pss_pss_sha512,rsa_pss_pss_sha384,rsa_pss_pss_sha256,
+ rsa_pss_rsae_sha512,rsa_pss_rsae_sha384,rsa_pss_rsae_sha256]
+ </c></p>
+
+ <note><p>Some TLS-1-3 scheme names overlap with TLS-1.2
+ algorithm-tuple-pair-names and then TLS-1.3 names will be
+ used, for example <c>rsa_pkcs1_sha256</c> instead of
+ <c>{sha256, rsa}</c> these are legacy algorithms in TLS-1.3
+ that apply only to certificate signatures in this version of
+ the protocol.</p></note>
+ </desc>
+ </func>
<func>
<name since="" name="sockname" arity="1" />
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index c96173e98b..0a1db06804 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -81,6 +81,7 @@
filter_cipher_suites/2,
prepend_cipher_suites/2,
append_cipher_suites/2,
+ signature_algs/2,
eccs/0,
eccs/1,
versions/0,
@@ -183,12 +184,11 @@
-type hash() :: sha2() |
legacy_hash(). % exported
--type sha2() :: sha224 |
- sha256 |
- sha384 |
- sha512.
+-type sha2() :: sha256 |
+ sha384 |
+ sha512.
--type legacy_hash() :: sha | md5.
+-type legacy_hash() :: sha224 | sha | md5.
-type sign_algo() :: rsa | dsa | ecdsa | eddsa. % exported
@@ -1106,6 +1106,41 @@ append_cipher_suites(Filters, Suites) ->
(Suites -- Deferred) ++ Deferred.
%%--------------------------------------------------------------------
+-spec signature_algs(Description, Version) -> [signature_algs()] when
+ Description :: default | all | exclusive,
+ Version :: protocol_version().
+
+%% Description: Returns possible signature algorithms/schemes
+%% for TLS/DTLS version
+%%--------------------------------------------------------------------
+
+signature_algs(default, 'tlsv1.3') ->
+ tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.3'),
+ tls_record:protocol_version_name('tlsv1.2')]);
+signature_algs(default, 'tlsv1.2') ->
+ tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.2')]);
+signature_algs(all, 'tlsv1.3') ->
+ tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.3'),
+ tls_record:protocol_version_name('tlsv1.2')]) ++
+ tls_v1:legacy_signature_algs_pre_13();
+signature_algs(all, 'tlsv1.2') ->
+ tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.2')]) ++
+ tls_v1:legacy_signature_algs_pre_13();
+signature_algs(exclusive, 'tlsv1.3') ->
+ tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.3')]);
+signature_algs(exclusive, 'tlsv1.2') ->
+ Algs = tls_v1:default_signature_algs([tls_record:protocol_version_name('tlsv1.2')]),
+ Algs ++ tls_v1:legacy_signature_algs_pre_13();
+signature_algs(Description, 'dtlsv1.2') ->
+ signature_algs(Description, 'tlsv1.2');
+signature_algs(Description, Version) when Description == default;
+ Description == all;
+ Description == exclusive->
+ {error, {signature_algs_not_supported_in_protocol_version, Version}};
+signature_algs(Description,_) ->
+ {error, {badarg, Description}}.
+
+%%--------------------------------------------------------------------
-spec eccs() -> NamedCurves when
NamedCurves :: [named_curve()].
diff --git a/lib/ssl/src/tls_client_connection_1_3.erl b/lib/ssl/src/tls_client_connection_1_3.erl
index d5742ea390..8f7486d419 100644
--- a/lib/ssl/src/tls_client_connection_1_3.erl
+++ b/lib/ssl/src/tls_client_connection_1_3.erl
@@ -316,6 +316,10 @@ hello_middlebox_assert(enter, _, State) ->
{keep_state, State};
hello_middlebox_assert(internal, #change_cipher_spec{}, State) ->
tls_gen_connection:next_event(wait_ee, no_record, State);
+hello_middlebox_assert(internal = Type, #encrypted_extensions{} = Msg, #state{ssl_options = #{log_level := Level}} = State) ->
+ ssl_logger:log(warning, Level, #{description => "Failed to assert middlebox server message",
+ reason => [{missing, #change_cipher_spec{}}]}, ?LOCATION),
+ ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State);
hello_middlebox_assert(info, Msg, State) ->
tls_gen_connection:handle_info(Msg, ?FUNCTION_NAME, State);
hello_middlebox_assert(Type, Msg, State) ->
@@ -331,8 +335,10 @@ hello_retry_middlebox_assert(enter, _, State) ->
{keep_state, State};
hello_retry_middlebox_assert(internal, #change_cipher_spec{}, State) ->
tls_gen_connection:next_event(wait_sh, no_record, State);
-hello_retry_middlebox_assert(internal, #server_hello{}, State) ->
- tls_gen_connection:next_event(?FUNCTION_NAME, no_record, State, [postpone]);
+hello_retry_middlebox_assert(internal = Type, #server_hello{} = Msg, #state{ssl_options = #{log_level := Level}} = State) ->
+ ssl_logger:log(warning, Level, #{description => "Failed to assert middlebox server message",
+ reason => [{missing, #change_cipher_spec{}}]}, ?LOCATION),
+ ssl_gen_statem:handle_common_event(Type, Msg, ?FUNCTION_NAME, State);
hello_retry_middlebox_assert(info, Msg, State) ->
tls_gen_connection:handle_info(Msg, ?FUNCTION_NAME, State);
hello_retry_middlebox_assert(Type, Msg, State) ->
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 7404365520..8eda30506a 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -55,6 +55,7 @@
oid_to_enum/1,
enum_to_oid/1,
default_signature_algs/1,
+ legacy_signature_algs_pre_13/0,
signature_algs/2,
signature_schemes/2,
rsa_schemes/0,
@@ -885,7 +886,8 @@ signature_algs(?TLS_1_2, HashSigns) ->
default_signature_algs([?TLS_1_3]) ->
default_signature_schemes(?TLS_1_3) ++ legacy_signature_schemes(?TLS_1_3);
default_signature_algs([?TLS_1_3, ?TLS_1_2 | _]) ->
- default_signature_schemes(?TLS_1_3) ++ default_pre_1_3_signature_algs_only();
+ default_signature_schemes(?TLS_1_3) ++ legacy_signature_schemes(?TLS_1_3)
+ ++ default_pre_1_3_signature_algs_only();
default_signature_algs([?TLS_1_2 = Version |_]) ->
Default = [%% SHA2 ++ PSS
{sha512, ecdsa},
@@ -899,9 +901,7 @@ default_signature_algs([?TLS_1_2 = Version |_]) ->
{sha256, ecdsa},
rsa_pss_pss_sha256,
rsa_pss_rsae_sha256,
- {sha256, rsa},
- {sha224, ecdsa},
- {sha224, rsa}
+ {sha256, rsa}
],
signature_algs(Version, Default);
default_signature_algs(_) ->
@@ -910,16 +910,14 @@ default_signature_algs(_) ->
default_pre_1_3_signature_algs_only() ->
Default = [%% SHA2
{sha512, ecdsa},
- {sha512, rsa},
{sha384, ecdsa},
- {sha384, rsa},
- {sha256, ecdsa},
- {sha256, rsa},
- {sha224, ecdsa},
- {sha224, rsa}
+ {sha256, ecdsa}
],
signature_algs(?TLS_1_2, Default).
+legacy_signature_algs_pre_13() ->
+ [{sha224, ecdsa}, {sha224, rsa}, {sha, rsa}, {sha, dsa}].
+
signature_schemes(Version, [_|_] =SignatureSchemes) when is_tuple(Version)
andalso ?TLS_GTE(Version, ?TLS_1_2) ->
CryptoSupports = crypto:supports(),
diff --git a/lib/ssl/test/ssl_reject_SUITE.erl b/lib/ssl/test/ssl_reject_SUITE.erl
index cc24ffbcfe..be79e0543b 100644
--- a/lib/ssl/test/ssl_reject_SUITE.erl
+++ b/lib/ssl/test/ssl_reject_SUITE.erl
@@ -184,9 +184,12 @@ accept_sslv3_record_hello(Config) when is_list(Config) ->
Allversions = all_versions(),
+ AllSigAlgs = ssl:signature_algs(all, 'tlsv1.3'),
+
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {options, [{versions, Allversions} | ServerOpts]}]),
+ {options, [{versions, Allversions},
+ {signature_algs, AllSigAlgs} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
%% TLS-1.X Hello with SSL-3.0 record version
diff --git a/lib/ssl/test/tls_api_SUITE.erl b/lib/ssl/test/tls_api_SUITE.erl
index 405bb74b2d..74b4e76566 100644
--- a/lib/ssl/test/tls_api_SUITE.erl
+++ b/lib/ssl/test/tls_api_SUITE.erl
@@ -109,7 +109,9 @@
accept_pool/0,
accept_pool/1,
reuseaddr/0,
- reuseaddr/1
+ reuseaddr/1,
+ signature_algs/0,
+ signature_algs/1
]).
%% Apply export
@@ -1307,6 +1309,24 @@ tls_password_badarg(Config) when is_list(Config) ->
{error, {keyfile,badarg}}).
%%--------------------------------------------------------------------
+signature_algs() ->
+ [{doc, "Check that listing of signature algorithms for different version and configure combinations"}].
+signature_algs(Config) when is_list(Config) ->
+ true = [] =/= [Alg || Alg <- ssl:signature_algs(default, 'tlsv1.3'), is_tuple(Alg)],
+ true = [] == [Alg || Alg <- ssl:signature_algs(exclusive, 'tlsv1.3'), is_tuple(Alg)],
+ true = ssl:signature_algs(exclusive, 'tlsv1.3') =/= ssl:signature_algs(exclusive, 'tlsv1.2'),
+ true = length(ssl:signature_algs(defalt, 'tlsv1.2')) <
+ length(ssl:signature_algs(all, 'tlsv1.2')),
+ TLS_1_3_All = ssl:signature_algs(all, 'tlsv1.3'),
+ true = lists:member(rsa_pkcs1_sha512, TLS_1_3_All) andalso (not lists:member({sha512, rsa}, TLS_1_3_All)),
+ true = lists:member(rsa_pkcs1_sha384, TLS_1_3_All) andalso (not lists:member({sha384, rsa}, TLS_1_3_All)),
+ true = lists:member(rsa_pkcs1_sha256, TLS_1_3_All) andalso (not lists:member({sha256, rsa}, TLS_1_3_All)),
+ TLS_1_2_All = ssl:signature_algs(all, 'tlsv1.2'),
+ true = (not lists:member(rsa_pkcs1_sha512, TLS_1_2_All)) andalso lists:member({sha512, rsa}, TLS_1_2_All),
+ true = (not lists:member(rsa_pkcs1_sha384, TLS_1_2_All)) andalso lists:member({sha384, rsa}, TLS_1_2_All),
+ true = (not lists:member(rsa_pkcs1_sha256, TLS_1_2_All)) andalso lists:member({sha256, rsa}, TLS_1_2_All).
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index bc96992ce2..0260b3251c 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -25,7 +25,7 @@
-export([setopts_getopts/1,unicode_options/1,unicode_options_gen/1,
binary_options/1, read_modes_gl/1,
read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1,
- unicode_prompt/1, shell_slogan/1]).
+ unicode_prompt/1, shell_slogan/1, raw_stdout/1, raw_stdout_isatty/1]).
-export([io_server_proxy/1,start_io_server_proxy/0, proxy_getall/1,
@@ -35,6 +35,8 @@
-export([uprompt/1, slogan/0, session_slogan/0]).
+-export([write_raw_to_stdout/0]).
+
%%-define(debug, true).
-ifdef(debug).
@@ -51,7 +53,7 @@ all() ->
[setopts_getopts, unicode_options, unicode_options_gen,
binary_options, read_modes_gl, read_modes_ogl,
broken_unicode, eof_on_pipe, unicode_prompt,
- shell_slogan].
+ shell_slogan, raw_stdout, raw_stdout_isatty].
groups() ->
[].
@@ -1091,6 +1093,45 @@ eof_on_pipe(Config) when is_list(Config) ->
{skipped,"Only on linux"}
end.
+raw_stdout(Config) when is_list(Config) ->
+ Cmd = lists:append(
+ [ct:get_progname(),
+ " -noshell -noinput",
+ " -pa ", filename:dirname(code:which(?MODULE)),
+ " -s ", atom_to_list(?MODULE), " write_raw_to_stdout"]),
+ ct:log("~p~n", [Cmd]),
+ Port = open_port({spawn, Cmd}, [stream, eof]),
+ Expected = lists:seq(0,255),
+ Expected = get_all_port_data(Port, []),
+ Port ! {self(), close},
+ ok.
+
+get_all_port_data(Port, Acc) ->
+ receive
+ {Port, {data, Data}} ->
+ get_all_port_data(Port, [Acc|Data]);
+ {Port, eof} ->
+ lists:flatten(Acc)
+ end.
+
+write_raw_to_stdout() ->
+ try
+ ok = io:setopts(standard_io, [{encoding, latin1}]),
+ ok = file:write(standard_io, lists:seq(0,255)),
+ halt(0)
+ catch
+ Class:Reason:StackTrace ->
+ io:format(standard_error, "~p~p~p", [Class, Reason, StackTrace]),
+ halt(17)
+ end.
+
+raw_stdout_isatty(Config) when is_list(Config) ->
+ rtnode:run(
+ [{putline,"io:setopts(group_leader(), [{encoding, latin1}])."},
+ {putline,"file:write(group_leader(),[90, 127, 128, 255, 131, 90, 10])."},%
+ {expect, "\\QZ^?\\200\\377\\203Z\\E"}
+ ],[]),
+ ok.
%%
%% Test I/O-server
%%
diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in
index 87fc0354b6..6371f401c0 100644
--- a/lib/wx/c_src/Makefile.in
+++ b/lib/wx/c_src/Makefile.in
@@ -199,7 +199,11 @@ release_spec: opt
$(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver$(SO_EXT) "$(RELSYSDIR)/priv/"
$(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl$(SO_EXT) "$(RELSYSDIR)/priv/"
ifneq ($(WEBVIEW_LOADER_DLL_ORIG),)
- $(INSTALL_PROGRAM) $(WEBVIEW_LOADER_DLL_DEST) "$(RELSYSDIR)/priv/"
+ $(INSTALL_PROGRAM) $(WEBVIEW_LOADER_DLL_DEST) "$(RELSYSDIR)/priv/"
+endif
+ifeq ($(SYS_TYPE),win32)
+ $(INSTALL_PROGRAM) $(TARGET_DIR)/wxe_driver.pdb "$(RELSYSDIR)/priv/"
+ $(INSTALL_PROGRAM) $(TARGET_DIR)/erl_gl.pdb "$(RELSYSDIR)/priv/"
endif
release_docs_spec:
diff --git a/otp_build b/otp_build
index 5fec5b2551..c9d118c2a4 100755
--- a/otp_build
+++ b/otp_build
@@ -56,6 +56,8 @@ usage ()
echo " release <target_dir> - creates a small release to <target_dir>"
echo " release [-a|-s|-t] <target_dir> - creates full release to <target_dir>"
echo " tests <dir> - Build testsuites to <dir>"
+ echo " check [--help|...] - Perform various build checks. See --help for more info"
+ echo " and options."
echo ""
echo "-a builds all applications"
echo "-s builds a small system (default)"
@@ -998,6 +1000,11 @@ do_tests ()
fi
}
+do_check ()
+{
+ exec $ERL_TOP/scripts/otp_build_check "$@"
+}
+
do_debuginfo_win32 ()
{
setup_make
@@ -1294,6 +1301,9 @@ case "$1" in
echo_env_cross "$2";;
env_bootstrap)
echo_env_bootstrap;;
+ check)
+ shift;
+ do_check "$@";;
*)
usage;;
esac
diff --git a/scripts/otp_build_check b/scripts/otp_build_check
new file mode 100755
index 0000000000..ee6e656cdf
--- /dev/null
+++ b/scripts/otp_build_check
@@ -0,0 +1,344 @@
+#!/bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2023. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+# Performs a lot of (but not always all) build checking that you want to do...
+#
+
+docs=yes
+dialyzer=yes
+tests=all
+opt_only=no
+format_check=yes
+
+have_printf=no
+
+print_error() {
+ if [ $have_printf = yes ]; then
+ printf "\033[31mERROR: %s\033[0m\n" "$1" 1>&2
+ else
+ echo "ERROR: $1" 1>&2
+ fi
+}
+
+progress() {
+ if [ $have_printf = yes ]; then
+ printf "\n\033[33m*** %s ***\033[0m\n\n" "$1" 1>&2
+ else
+ echo "\n*** $1 ***\n" 1>&2
+ fi
+}
+
+print_usage() {
+ cat <<EOF
+Usage:
+ otp_build check [--help|-h] [--only-opt|-o] [--no-docs|-d] \\
+ [--no-dialyzer|-y] [--no-tests|-n] [--no-format-check|-f] \\
+ [--tests|-t <App0> ... <AppN>]
+
+
+By default all currently implemented checks will be performed. If any of the
+currently used tools are missing, checking will fail. If libraries or tools
+needed to support certain conditional features are missing, those features
+will not be checked.
+
+If any of these checks do not pass, the code is *not* ready for testing in OTP
+daily builds. Note that this script does not check all requirements for testing
+in OTP daily builds. These checks are the bare minimum for even considering
+testing in OTP daily builds. Currently the following will be performed by
+default:
+
+ * Build all applications in optimized mode. If configure already has been run,
+ it wont be run again.
+ * Debug compile C-code in all applications.
+ * Format checking of JIT code.
+ * Run dialyzer on all applications.
+ * Build all documentation.
+ * Run xmllint on all documentation.
+ * Run html link check on all documentation.
+ * Build all test suites.
+
+Certain build checking can be disabled using the following options:
+* [--only-opt|-o] - Only build optimized system. No debug, etc.
+* [--no-format-check|-f] - No JIT format checking.
+* [--no-docs|-d] - No documentation checking.
+* [--no-dialyzer|-y] - No dialyzer checking.
+* [--no-tests|-n] - No build checking of test suites.
+* [--tests|-t <App0> ... <AppN>] - Only build checking of test suites for
+ listed applications.
+
+Only disable build checking for parts of the system that you are certain your
+changes wont effect. Note that even though you've made no changes in
+documentation source files, documentation build is effected by type changes
+in code.
+
+Environment variables used:
+* CONFIG_FLAGS - Arguments to pass to configure if it is executed.
+
+Build results will be placed under the \$ERL_TOP/release/<TARGET> directory
+
+EOF
+}
+
+usage () {
+ print_error "$1"
+ print_usage >&2
+ exit 1
+}
+
+fail () {
+ print_error "$1"
+ exit 1
+}
+
+type printf >/dev/null 2>&1
+if [ $? -eq 0 ]; then
+ have_printf=yes
+fi
+
+[ "$ERL_TOP" != "" ] || fail "ERL_TOP needs to be set"
+
+cd "$ERL_TOP" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $ERL_TOP"
+}
+
+[ -f "$ERL_TOP/OTP_VERSION" ] || fail "ERL_TOP not valid"
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ --help|-h)
+ print_usage
+ exit 0;;
+ --only-opt|-o)
+ opt_only=yes;;
+ --no-docs|-d)
+ docs=no;;
+ --no-dialyzer|-y)
+ dialyzer=no;;
+ --no-format-check|-f)
+ format_check=no;;
+ --no-tests|-n)
+ tests=none;;
+ --tests|-t)
+ shift
+ while [ $# -gt 0 ]; do
+ case $1 in
+ -*)
+ break;;
+ test_server|emulator|system|epmd)
+ ;;
+ *)
+ [ -d "$ERL_TOP/lib/$1/test" ] || {
+ fail "Invalid application: $1"
+ }
+ ;;
+ esac
+ tapps="$1 $tapps"
+ shift
+ done
+ [ "$tapps" != "" ] || usage "No test apps given"
+ tests="$tapps"
+ continue;;
+ *)
+ usage "Invalid option: $1"
+ esac
+ shift
+done
+
+[ -f "$ERL_TOP/make/config.status" ] || {
+ ./configure $CONFIG_FLAGS || fail "configure failed"
+}
+
+type gmake >/dev/null 2>&1
+if [ $? -eq 0 ]; then
+ export MAKE="gmake"
+else
+ type make >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ export MAKE="make"
+ fi
+fi
+
+target=`$MAKE target_configured` || fail "Failed to determine target directory"
+
+unset TESTROOT
+unset RELEASE_ROOT
+unset ERL_LIBS
+unset OTP_SMALL_BUILD
+unset OTP_TINY_BUILD
+unset TARGET
+
+progress "Building OTP in $ERL_TOP"
+$MAKE || fail "OTP build failed"
+progress "Booting optimized runtime"
+$ERL_TOP/bin/cerl -eval "erlang:halt()" || {
+ fail "Failed to boot runtime"
+}
+
+[ $opt_only = yes ] || {
+ progress "Building debug OTP in $ERL_TOP"
+ $MAKE TYPE=debug || fail "OTP debug build failed"
+ progress "Booting debug runtime"
+ $ERL_TOP/bin/cerl -debug -eval "erlang:halt()" || {
+ fail "Failed to boot debug runtime"
+ }
+}
+
+[ $format_check = no ] || {
+ clang-format --help 2>&1 >/dev/null || {
+ fail "clang-format not installed. Use --no-format-check option to skip."
+ }
+
+ progress "Checking C & C++ code formatting"
+ $MAKE format-check || {
+ fail "Failed to format C & C++ code"
+ }
+}
+
+progress "Releasing OTP"
+$MAKE release || fail "Releasing OTP failed"
+
+cd "$ERL_TOP/release/$target" 2>&1 >/dev/null || {
+ fail "Failed to change directory into release directory: $ERL_TOP/release/$target"
+}
+
+progress "Installing OTP"
+./Install -minimal `pwd` || fail "Failed to install release"
+
+progress "Booting optimized installed runtime"
+./bin/erl -eval "erlang:halt()" || {
+ fail "Failed to boot installed runtime"
+}
+
+cd "$ERL_TOP" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $ERL_TOP"
+}
+
+export PATH="$ERL_TOP/release/$target/bin:$PATH"
+
+[ $docs = no ] || {
+ progress "Building OTP documentation"
+ $MAKE docs || fail "Building documentation failed"
+ progress "Releasing OTP documentation"
+ $MAKE release_docs || fail "Releasing documentation failed"
+ progress "Running xmllint on OTP documentation"
+ $MAKE xmllint || fail "xmllint of documentation failed"
+ progress "Running HTML check on OTP documentation"
+ ./scripts/otp_html_check "$ERL_TOP/release/$target/" doc/index.html || {
+ fail "HTML check of documentation failed"
+ }
+}
+
+[ $dialyzer = no ] || {
+ progress "Running dialyzer on OTP"
+ $MAKE dialyzer || fail "Dialyzing OTP failed"
+}
+
+[ "$tests" = none ] || {
+ test_dir="$ERL_TOP/release/$target/test"
+ [ -d "$test_dir" ] || mkdir "$test_dir" 2>&1 >/dev/null || {
+ fail "Failed to create $test_dir directory"
+ }
+ if [ "$tests" = all ]; then
+ progress "Releasing all OTP tests"
+ ./otp_build tests "$test_dir" || fail "Release of tests failed"
+ else
+ for tapp in $tests; do
+ case $tapp in
+ test_server)
+ tapp_dir="$ERL_TOP/lib/test_server"
+ if [ ! -d "$tapp_dir" ]; then
+ tapp_dir="$ERL_TOP/lib/common_test/test_server"
+ fi
+ ;;
+ emulator) tapp_dir="$ERL_TOP/erts/emulator/test";;
+ system) tapp_dir="$ERL_TOP/erts/test";;
+ epmd) tapp_dir="$ERL_TOP/erts/epmd/test";;
+ *) tapp_dir="$ERL_TOP/lib/$tapp/test";;
+ esac
+ cd "$tapp_dir" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $tapp_dir"
+ }
+ progress "Releasing $tapp tests"
+ $MAKE "TESTROOT=$test_dir" release_tests || {
+ fail "Release of $tapp tests failed"
+ }
+ done
+
+ fi
+
+ cd "$test_dir" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $test_dir"
+ }
+
+ for dir in *; do
+
+ [ -d "$test_dir/$dir" ] || continue
+
+ progress "Building $dir tests"
+
+ cd "$test_dir/$dir" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $test_dir/$dir"
+ }
+
+ for mfile in *_data/Makefile.first; do
+
+ [ "$mfile" != '*_data/Makefile.first' ] || continue
+
+ ddir=`dirname $mfile` || fail "dirname on $test_dir/$dir/$mfile failed"
+
+ cd "$test_dir/$dir/$ddir" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $test_dir/$dir/$ddir"
+ }
+
+ $MAKE -f Makefile.first || {
+ fail "Make of $test_dir/$dir/$ddir/Makefile.first failed"
+ }
+
+ done
+
+ cd "$test_dir/$dir" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $test_dir/$dir"
+ }
+
+ if [ -f Emakefile ]; then
+ erl -noshell -eval 'case make:all() of error -> erlang:halt(1); _ -> init:stop() end.' || {
+ fail "Build of $dir failed"
+ }
+ else
+ erlc -I `erl -noshell -eval 'io:format("~ts",[code:lib_dir(common_test)]),init:stop()'`/include -I . *.erl || {
+ fail "Build of $dir failed"
+ }
+ fi
+
+ done
+
+ cd "$ERL_TOP" 2>&1 >/dev/null || {
+ fail "Failed to change directory into $ERL_TOP"
+ }
+}
+
+if [ $have_printf = yes ]; then
+ printf "\n\033[32m*** Success! ***\033[0m\n\n"
+else
+ echo "\n*** Success! ***\n"
+fi
+exit 0
diff --git a/system/doc/general_info/upcoming_incompatibilities.xml b/system/doc/general_info/upcoming_incompatibilities.xml
index 04ab4459c0..8538067b57 100644
--- a/system/doc/general_info/upcoming_incompatibilities.xml
+++ b/system/doc/general_info/upcoming_incompatibilities.xml
@@ -53,6 +53,7 @@
</section>
<section>
+ <marker id="maybe_expr"/>
<title>Feature maybe_expr will be enabled by default</title>
<p>
As of OTP 27, the <c>maybe_expr</c> feature will be approved
@@ -119,6 +120,65 @@
the regular expression before matching with it.</p></item>
</list>
</section>
+
+ <section>
+ <marker id="float_matching"/>
+ <title>0.0 and -0.0 will no longer be exactly equal</title>
+
+ <p>Currently, the floating point numbers <c>0.0</c> and <c>-0.0</c>
+ have distinct internal representations. That can be seen if they are
+ converted to binaries:</p>
+ <pre>
+1&gt; <input>&lt;&lt;0.0/float&gt;&gt;.</input>
+&lt;&lt;0,0,0,0,0,0,0,0&gt;&gt;
+2&gt; <input>&lt;&lt;-0.0/float&gt;>.</input>
+&lt;&lt;128,0,0,0,0,0,0,0>></pre>
+
+ <p>However, when they are matched against each other or compared
+ using the <c>=:=</c> operator, they are considered to be
+ equal. Thus, <c>0.0 =:= -0.0</c> currently returns
+ <c>true</c>.</p>
+
+ <p>In Erlang/OTP 27, <c>0.0 =:= -0.0</c> will return <c>false</c>, and matching
+ <c>0.0</c> against <c>-0.0</c> will fail. When used as map keys, <c>0.0</c> and
+ <c>-0.0</c> will be considered to be distinct.</p>
+
+ <p>The <c>==</c> operator will continue to return <c>true</c>
+ for <c>0.0 == -0.0</c>.</p>
+
+ <p>To help to find code that might need to be revised, in OTP 27
+ there will be a new compiler warning when matching against
+ <c>0.0</c> or comparing to that value using the <c>=:=</c>
+ operator. The warning can be suppressed by matching against
+ <c>+0.0</c> instead of <c>0.0</c>.</p>
+
+ <p>We plan to introduce the same warning in OTP 26.1, but by default it
+ will be disabled.</p>
+ </section>
+
+ <section>
+ <marker id="singleton_typevars"/>
+ <title>Singleton type variables will become a compile-time error</title>
+
+ <p>Before Erlang/OTP 26, the compiler would silenty accept the
+ following spec:</p>
+
+ <pre>
+-spec f(Opts) -> term() when
+ Opts :: {ok, Unknown} | {error, Unknown}.
+f(_) -> error.</pre>
+
+ <p>In OTP 26, the compiler emits a warning pointing out that the type variable
+ <c>Unknown</c> is unbound:</p>
+
+ <pre>
+t.erl:6:18: Warning: type variable 'Unknown' is only used once (is unbound)
+% 6| Opts :: {ok, Unknown} | {error, Unknown}.
+% | ^</pre>
+
+ <p>In OTP 27, that warning will become an error.</p>
+ </section>
+
</section>
<section>