diff options
author | Fredrik Frantzen <71122361+frazze-jobb@users.noreply.github.com> | 2023-05-11 15:22:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-11 15:22:38 +0200 |
commit | 5f892f7b836be7f725d9e2ef13c6444e2aa474b6 (patch) | |
tree | d2af9db76c5d99dfcd8ff895eb268d4e9173a2e5 | |
parent | 3187153fb297fc9b5a0964dff9d08deb93e494ad (diff) | |
parent | 911461e585a1ab82857b501ca6c9ffb31c2efd8c (diff) | |
download | erlang-5f892f7b836be7f725d9e2ef13c6444e2aa474b6.tar.gz |
Merge branch 'master' into frazze/stdlib/multiline_editing
-rw-r--r-- | erts/etc/common/erlc.c | 4 | ||||
-rw-r--r-- | lib/kernel/src/group.erl | 35 | ||||
-rw-r--r-- | lib/kernel/src/prim_tty.erl | 5 | ||||
-rw-r--r-- | lib/kernel/src/user_drv.erl | 4 | ||||
-rw-r--r-- | lib/ssl/doc/src/ssl.xml | 64 | ||||
-rw-r--r-- | lib/ssl/src/ssl.erl | 45 | ||||
-rw-r--r-- | lib/ssl/src/tls_client_connection_1_3.erl | 10 | ||||
-rw-r--r-- | lib/ssl/src/tls_v1.erl | 18 | ||||
-rw-r--r-- | lib/ssl/test/ssl_reject_SUITE.erl | 5 | ||||
-rw-r--r-- | lib/ssl/test/tls_api_SUITE.erl | 22 | ||||
-rw-r--r-- | lib/stdlib/test/io_proto_SUITE.erl | 45 | ||||
-rw-r--r-- | lib/wx/c_src/Makefile.in | 6 | ||||
-rwxr-xr-x | otp_build | 10 | ||||
-rwxr-xr-x | scripts/otp_build_check | 344 | ||||
-rw-r--r-- | system/doc/general_info/upcoming_incompatibilities.xml | 60 |
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> 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>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> 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: @@ -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> <input><<0.0/float>>.</input> +<<0,0,0,0,0,0,0,0>> +2> <input><<-0.0/float>>.</input> +<<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> |