diff options
45 files changed, 827 insertions, 454 deletions
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 1b973cd60e..984072076c 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -2068,8 +2068,15 @@ end</pre> Typically, this is used when a process started from a certain shell is to have another group leader than <c>init</c>.</p> + <p>The group leader should be rarely changed in + applications with a supervision tree, because OTP + assumes the group leader of their processes is + their application master.</p> <p>See also - <seealso marker="#group_leader/0"><c>group_leader/0</c></seealso>.</p> + <seealso marker="#group_leader/0"><c>group_leader/0</c></seealso> + and <seealso marker="doc/design_principles:applications#stopping">OTP + design principles</seealso> related to starting and stopping + applications.</p> </desc> </func> diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index f7f86084a9..b9de00a8af 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -31,6 +31,26 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 9.3.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug in <c>ets</c> that could cause VM crash if + process A terminates after fixating a table and process B + deletes the table at "the same time". The table fixation + could be done with <c>ets:safe_fixtable</c> or if process + A terminates in the middle of a long running + <c>select</c> or <c>match</c> call.</p> + <p> + Own Id: OTP-15109</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 9.3.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/test/monitor_SUITE.erl b/erts/emulator/test/monitor_SUITE.erl index c7250a9d26..27351dc5c1 100644 --- a/erts/emulator/test/monitor_SUITE.erl +++ b/erts/emulator/test/monitor_SUITE.erl @@ -314,7 +314,7 @@ local_remove_monitor(Config) when is_list(Config) -> remote_remove_monitor(Config) when is_list(Config) -> {ok, N} = test_server:start_node(demonitor_flush, slave, []), - Gs = generate(fun () -> start_remove_monitor_group(node()) end, + Gs = generate(fun () -> start_remove_monitor_group(N) end, ?RM_MON_GROUPS), {True, False} = lists:foldl(fun (G, {T, F}) -> receive diff --git a/erts/vsn.mk b/erts/vsn.mk index 687c62343e..9222b74f81 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 9.3.2 +VSN = 9.3.3 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index e4eb2bc3b6..0a2a235209 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -3068,202 +3068,187 @@ static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ - DH* dh_params = NULL; - int pub_len, prv_len; - unsigned char *pub_ptr, *prv_ptr; - ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail; + DH *dh_params = NULL; int mpint; /* 0 or 4 */ - BIGNUM *priv_key_in = NULL; - BIGNUM *dh_p = NULL, *dh_g = NULL; - unsigned long len = 0; -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *dhkey = NULL, - *params = NULL; -#endif - if (!(get_bn_from_bin(env, argv[0], &priv_key_in) - || argv[0] == atom_undefined) - || !enif_get_list_cell(env, argv[1], &head, &tail) - || !get_bn_from_bin(env, head, &dh_p) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dh_g) - || !enif_is_empty_list(env, tail) - || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4) - || !enif_get_ulong(env, argv[3], &len) - - /* Load dh_params with values to use by the generator. - Mem mgmnt transfered from dh_p etc to dh_params */ - || !(dh_params = DH_new()) - || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in)) - || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g) - ) { - if (priv_key_in) BN_free(priv_key_in); - if (dh_p) BN_free(dh_p); - if (dh_g) BN_free(dh_g); - if (dh_params) DH_free(dh_params); - return enif_make_badarg(env); - } - - if (len) { - if (len < BN_num_bits(dh_p)) - DH_set_length(dh_params, len); - else { + { + ERL_NIF_TERM head, tail; + BIGNUM + *dh_p = NULL, + *dh_g = NULL, + *priv_key_in = NULL; + unsigned long + len = 0; + + if (!(get_bn_from_bin(env, argv[0], &priv_key_in) + || argv[0] == atom_undefined) + || !enif_get_list_cell(env, argv[1], &head, &tail) + || !get_bn_from_bin(env, head, &dh_p) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_bin(env, head, &dh_g) + || !enif_is_empty_list(env, tail) + || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4) + || !enif_get_ulong(env, argv[3], &len) + + /* Load dh_params with values to use by the generator. + Mem mgmnt transfered from dh_p etc to dh_params */ + || !(dh_params = DH_new()) + || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in)) + || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g) + ) { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } + + if (len) { + if (len < BN_num_bits(dh_p)) + DH_set_length(dh_params, len); + else { + if (priv_key_in) BN_free(priv_key_in); + if (dh_p) BN_free(dh_p); + if (dh_g) BN_free(dh_g); + if (dh_params) DH_free(dh_params); + return enif_make_badarg(env); + } + } } #ifdef HAS_EVP_PKEY_CTX - if ((dhkey = EVP_PKEY_new()) - && (params = EVP_PKEY_new()) - && EVP_PKEY_set1_DH(params, dh_params) /* set the key referenced by params to dh_params. - dh_params (and params) must be freed */ - && (ctx = EVP_PKEY_CTX_new(params, NULL)) - && EVP_PKEY_keygen_init(ctx) - && EVP_PKEY_keygen(ctx, &dhkey) /* "performs a key generation operation, the - generated key is written to ppkey." (=last arg) */ - && (dh_params = EVP_PKEY_get1_DH(dhkey)) /* return the referenced key. dh_params and dhkey must be freed */ - ) { + { + EVP_PKEY_CTX *ctx; + EVP_PKEY *dhkey, *params; + int success; + + params = EVP_PKEY_new(); + success = EVP_PKEY_set1_DH(params, dh_params); /* set the key referenced by params to dh_params... */ + DH_free(dh_params); /* ...dh_params (and params) must be freed */ + if (!success) return atom_error; + + ctx = EVP_PKEY_CTX_new(params, NULL); + EVP_PKEY_free(params); + if (!ctx) { + return atom_error; + } + + if (!EVP_PKEY_keygen_init(ctx)) { + /* EVP_PKEY_CTX_free(ctx); */ + return atom_error; + } + + dhkey = EVP_PKEY_new(); + if (!EVP_PKEY_keygen(ctx, &dhkey)) { /* "performs a key generation operation, the ... */ + /*... generated key is written to ppkey." (=last arg) */ + /* EVP_PKEY_CTX_free(ctx); */ + /* EVP_PKEY_free(dhkey); */ + return atom_error; + } + + dh_params = EVP_PKEY_get1_DH(dhkey); /* return the referenced key. dh_params and dhkey must be freed */ + EVP_PKEY_free(dhkey); + if (!dh_params) { + /* EVP_PKEY_CTX_free(ctx); */ + return atom_error; + } + EVP_PKEY_CTX_free(ctx); + } #else - if (DH_generate_key(dh_params)) { -#endif + if (!DH_generate_key(dh_params)) return atom_error; +#endif + { + unsigned char *pub_ptr, *prv_ptr; + int pub_len, prv_len; + ERL_NIF_TERM ret_pub, ret_prv; const BIGNUM *pub_key_gen, *priv_key_gen; - - DH_get0_key(dh_params, - &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen. - "The values point to the internal representation of - the public key and private key values. This memory + + DH_get0_key(dh_params, + &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen. + "The values point to the internal representation of + the public key and private key values. This memory should not be freed directly." says man */ - pub_len = BN_num_bytes(pub_key_gen); - prv_len = BN_num_bytes(priv_key_gen); - pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); - prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); - if (mpint) { - put_int32(pub_ptr, pub_len); pub_ptr += 4; - put_int32(prv_ptr, prv_len); prv_ptr += 4; - } - BN_bn2bin(pub_key_gen, pub_ptr); - BN_bn2bin(priv_key_gen, prv_ptr); - ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); - ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); - ret = enif_make_tuple2(env, ret_pub, ret_prv); - } - else { - ret = atom_error; - } + pub_len = BN_num_bytes(pub_key_gen); + prv_len = BN_num_bytes(priv_key_gen); + pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); + prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); + if (mpint) { + put_int32(pub_ptr, pub_len); pub_ptr += 4; + put_int32(prv_ptr, prv_len); prv_ptr += 4; + } + BN_bn2bin(pub_key_gen, pub_ptr); + BN_bn2bin(priv_key_gen, prv_ptr); + ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); + ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); - DH_free(dh_params); -#ifdef HAS_EVP_PKEY_CTX - if (ctx) EVP_PKEY_CTX_free(ctx); - if (dhkey) EVP_PKEY_free(dhkey); - if (params) EVP_PKEY_free(params); -#endif - return ret; + DH_free(dh_params); + + return enif_make_tuple2(env, ret_pub, ret_prv); + } } static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ - BIGNUM *dummy_pub_key = NULL, - *priv_key = NULL, - *other_pub_key = NULL, + BIGNUM *other_pub_key = NULL, *dh_p = NULL, *dh_g = NULL; - ErlNifBinary ret_bin; - ERL_NIF_TERM ret, head, tail; - DH *dh_priv = DH_new(), *dh_pub = DH_new(); -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *my_priv_key = NULL, *peer_pub_key = NULL; - size_t skeylen; -#else - int i; -#endif + DH *dh_priv = DH_new(); - if (!get_bn_from_bin(env, argv[0], &other_pub_key) - || !get_bn_from_bin(env, argv[1], &priv_key) - || !enif_get_list_cell(env, argv[2], &head, &tail) - || !get_bn_from_bin(env, head, &dh_p) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dh_g) - || !enif_is_empty_list(env, tail) - - /* Note: DH_set0_key() does not allow setting only the - * private key, although DH_compute_key() does not use the - * public key. Work around this limitation by setting - * the public key to a copy of the private key. - */ - || !(dummy_pub_key = BN_dup(priv_key)) - || !DH_set0_key(dh_priv, dummy_pub_key, priv_key) - || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g) - ) { - if (dh_p) BN_free(dh_p); - if (dh_g) BN_free(dh_g); - if (other_pub_key) BN_free(other_pub_key); - if (dummy_pub_key) BN_free(dummy_pub_key); - if (priv_key) BN_free(priv_key); - return enif_make_badarg(env); - } - -#ifdef HAS_EVP_PKEY_CTX - if (!(my_priv_key = EVP_PKEY_new()) - || !EVP_PKEY_set1_DH(my_priv_key, dh_priv) /* set the key referenced by my_priv_key to dh_priv. - dh_priv (and my_priv_key) must be freed by us*/ - - || !(peer_pub_key = EVP_PKEY_new()) - || !DH_set0_key(dh_pub, other_pub_key, NULL) - || !DH_set0_pqg(dh_pub, dh_p, NULL, dh_g) - || !EVP_PKEY_set1_DH(peer_pub_key, dh_pub) - - || !(ctx = EVP_PKEY_CTX_new(my_priv_key, NULL)) - || (EVP_PKEY_derive_init(ctx) <= 0) - || (EVP_PKEY_derive_set_peer(ctx, peer_pub_key) <= 0) - || (EVP_PKEY_derive(ctx, NULL, &skeylen) <= 0)) { + /* Check the arguments and get + my private key (dh_priv), + the peer's public key (other_pub_key), + the parameters p & q + */ - ret = atom_error; - } - else { - enif_alloc_binary(skeylen, &ret_bin); - - if ((EVP_PKEY_derive(ctx, ret_bin.data, &skeylen) > 0) - && (ret_bin.size >= skeylen)) { - /* Derivation succeded */ - if (ret_bin.size > skeylen) enif_realloc_binary(&ret_bin, skeylen); - ret = enif_make_binary(env, &ret_bin); + { + BIGNUM *dummy_pub_key = NULL, + *priv_key = NULL; + ERL_NIF_TERM head, tail; + + if (!get_bn_from_bin(env, argv[0], &other_pub_key) + || !get_bn_from_bin(env, argv[1], &priv_key) + || !enif_get_list_cell(env, argv[2], &head, &tail) + || !get_bn_from_bin(env, head, &dh_p) + || !enif_get_list_cell(env, tail, &head, &tail) + || !get_bn_from_bin(env, head, &dh_g) + || !enif_is_empty_list(env, tail) + + /* Note: DH_set0_key() does not allow setting only the + * private key, although DH_compute_key() does not use the + * public key. Work around this limitation by setting + * the public key to a copy of the private key. + */ + || !(dummy_pub_key = BN_dup(priv_key)) + || !DH_set0_key(dh_priv, dummy_pub_key, priv_key) + || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g) + ) { + if (dh_p) BN_free(dh_p); + if (dh_g) BN_free(dh_g); + if (other_pub_key) BN_free(other_pub_key); + if (dummy_pub_key) BN_free(dummy_pub_key); + if (priv_key) BN_free(priv_key); + return enif_make_badarg(env); } - else { + } + { + ErlNifBinary ret_bin; + int size; + + enif_alloc_binary(DH_size(dh_priv), &ret_bin); + size = DH_compute_key(ret_bin.data, other_pub_key, dh_priv); + BN_free(other_pub_key); + DH_free(dh_priv); + if (size<=0) { enif_release_binary(&ret_bin); - ret = atom_error; + return atom_error; } - } -#else - enif_alloc_binary(DH_size(dh_priv), &ret_bin); - i = DH_compute_key(ret_bin.data, other_pub_key, dh_priv); - if (i > 0) { - if (i != ret_bin.size) enif_realloc_binary(&ret_bin, i); - ret = enif_make_binary(env, &ret_bin); + if (size != ret_bin.size) enif_realloc_binary(&ret_bin, size); + return enif_make_binary(env, &ret_bin); } - else { - enif_release_binary(&ret_bin); - ret = atom_error; - } -#endif - - if (other_pub_key) BN_free(other_pub_key); - if (dh_priv) DH_free(dh_priv); - if (dh_pub) DH_free(dh_pub); -#ifdef HAS_EVP_PKEY_CTX - if (ctx) EVP_PKEY_CTX_free(ctx); - if (my_priv_key) EVP_PKEY_free(my_priv_key); - /* if (peer_pub_key) EVP_PKEY_free(peer_pub_key); */ -#endif - return ret; } + static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Multiplier, Verifier, Generator, Exponent, Prime) */ BIGNUM *bn_verifier = NULL; @@ -3919,13 +3904,6 @@ static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_ } return enif_make_binary(env, &key_bin); - -/* Importing the other side's public key from raw binary format can be done with the EVP_PKEY_new_raw_public_key() function. Man page here: */ -/* https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_public_key.html */ - - -/* You need two EVP_PKEY objects. One containing your private/public key pair (i.e. the one you generated in the EVP_PKEY_keygen() call in your question), and one containing the public key of the peer (e.g. created using EVP_PKEY_new_raw_public_key()). To generate the X25519 shared secret you then call EVP_PKEY_derive(). See the example on the man page: openssl.org/docs/man1.1.1/man3/EVP_PKEY_derive.html – Matt Caswell May 15 at 20:39 */ - #else return atom_notsup; #endif @@ -3951,20 +3929,6 @@ static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF if (!EVP_PKEY_keygen_init(ctx)) return enif_make_atom(env,"EVP_PKEY_keygen_init failed"); if (!EVP_PKEY_keygen(ctx, &pkey)) return enif_make_atom(env,"EVP_PKEY_keygen failed"); - /* - int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv, size_t *len) - int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len) - - +EVP_PKEY_get_raw_private_key() fills the buffer provided by B<priv> with raw - +private key data. The number of bytes written is populated in B<*len>. If the - +buffer B<priv> is NULL then B<*len> is populated with the number of bytes - +required in the buffer. The calling application is responsible for ensuring that - +the buffer is large enough to receive the private key data. This function only - +works for algorithms that support raw private keys. Currently this is: - +B<EVP_PKEY_HMAC>, B<EVP_PKEY_POLY1305>, B<EVP_PKEY_SIPHASH>, B<EVP_PKEY_X25519>, - +B<EVP_PKEY_ED25519>, B<EVP_PKEY_X448> or B<EVP_PKEY_ED448>. - */ - if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len)) return enif_make_atom(env,"EVP_PKEY_get_raw_public_key 1 failed"); if (!EVP_PKEY_get_raw_public_key(pkey, diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc index 3dbd238c19..4d415ece78 100755 --- a/lib/diameter/bin/diameterc +++ b/lib/diameter/bin/diameterc @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -78,8 +78,8 @@ compile(#argv{file = File, options = Opts, output = Out}) -> error_msg(diameter_make:format_error(Reason), []), 1 catch - error: Reason -> - error_msg("ERROR: ~p~n ~p", [Reason, erlang:get_stacktrace()]), + error: Reason: Stack -> + error_msg("ERROR: ~p~n ~p", [Reason, Stack]), 2 end. diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile index 3af856f63e..f78a163591 100644 --- a/lib/diameter/src/Makefile +++ b/lib/diameter/src/Makefile @@ -149,7 +149,7 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl $(ERLC) -Werror -o $(@D) $< # Generate the app file. -$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed +$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk $(gen_verbose) \ M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \ C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \ @@ -160,8 +160,7 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed -e "s;%COMPILER%;$$C;" \ -e "s;%INFO%;$$I;" \ -e "s;%REGISTERED%;$$R;" \ - $< \ - | sed -f app.sed > $@ + $< > $@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk $(vsn_verbose) \ diff --git a/lib/diameter/src/app.sed b/lib/diameter/src/app.sed deleted file mode 100644 index dd3806f5f1..0000000000 --- a/lib/diameter/src/app.sed +++ /dev/null @@ -1,41 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2014-2016. 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% - -# -# Generate runtime_dependencies from applications to avoid having to -# specify the same application more than once. -# - -/{runtime_dependencies,/b v -/{[-a-z]*, "[0-9.]*"}/!b -/{vsn,/b - -/%%/!H -s/{\([^,]*\)[^}]*}/\1/g -s/%%/%,/ -b - -:v - -p -x -s/\n// -s/%//g -s/\n */ /g -s/{\([^,]*\), "\([^"]*"\)}/"\1-\2/g diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 2dd2c906a2..5c0a24cdf6 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -92,8 +92,8 @@ encode(Mod, Opts, #diameter_packet{} = Pkt) -> %% count encode errors. ?LOG(encode_error, {Reason, Stack, H}), exit({?MODULE, encode, T}); - error: Reason -> - T = {Reason, diameter_lib:get_stacktrace()}, + error: Reason: Stack -> + T = {Reason, diameter_lib:stacktrace(Stack)}, ?LOG(encode_error, T), exit({?MODULE, encode, T}) end; @@ -134,8 +134,8 @@ enc(_, Opts, #diameter_packet{msg = [#diameter_header{} = Hdr | As]} Eid:32, Bin/binary>>} catch - error: Reason -> - exit({Reason, diameter_lib:get_stacktrace(), Hdr}) + error: Reason: Stack -> + exit({Reason, diameter_lib:stacktrace(Stack), Hdr}) end; enc(Mod, Opts, #diameter_packet{header = Hdr0, msg = Msg} = Pkt) -> @@ -179,14 +179,14 @@ enc(Mod, Opts, #diameter_packet{header = Hdr0, msg = Msg} = Pkt) -> Eid:32, Bin/binary>>} catch - error: Reason -> + error: Reason: Stack -> Hdr = Hdr0#diameter_header{cmd_code = Code, application_id = Aid, is_request = RB, is_proxiable = PB, is_error = EB, is_retransmitted = TB}, - exit({Reason, diameter_lib:get_stacktrace(), Hdr}) + exit({Reason, diameter_lib:stacktrace(Stack), Hdr}) end. %% values/1 diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index 90a9282349..36ae4c2276 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -633,8 +633,8 @@ opt(service, {K, F}) Nodes -> is_list(Nodes) orelse {error, Nodes} catch - E:R -> - {error, {E, R, ?STACK}} + E:R:Stack -> + {error, {E, R, Stack}} end; opt(service, {sequence, {H,N}}) -> @@ -651,8 +651,8 @@ opt(service = S, {sequence = K, F}) -> V -> {error, V} catch - E:R -> - {error, {E, R, ?STACK}} + E:R:Stack -> + {error, {E, R, Stack}} end; opt(transport, {transport_module, M}) -> @@ -932,8 +932,8 @@ cb(M,F) -> try M:F() of V -> V catch - E: Reason -> - ?THROW({callback, E, Reason, ?STACK}) + E: Reason: Stack -> + ?THROW({callback, E, Reason, Stack}) end. %% call/1 diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl index 93ebe57685..d110a3015e 100644 --- a/lib/diameter/src/base/diameter_gen.erl +++ b/lib/diameter/src/base/diameter_gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -76,8 +76,7 @@ encode_avps(Name, Vals, #{module := Mod} = Opts) -> ?LINE, {Reason, Name, Vals, Mod}), erlang:error(list_to_tuple(Reason ++ [Name])); - error: Reason -> - Stack = erlang:get_stacktrace(), + error: Reason: Stack -> diameter_lib:log({encode, failure}, ?MODULE, ?LINE, @@ -555,8 +554,8 @@ dec(Data, Name, AvpName, Type, Mod, Dict, Fmt, Failed, Opts, Avp) -> catch throw: {?MODULE, T} -> decode_error(Failed, Fmt, T, Avp); - error: Reason -> - decode_error(Failed, Reason, Name, Mod, Opts, Avp) + error: Reason: Stack -> + decode_error(Failed, Reason, Stack, Name, Mod, Opts, Avp) end. %% dec_AVP/7 @@ -623,19 +622,19 @@ set(none, Avp, _Name) -> set(_, Avp, Rec) -> Avp#diameter_avp{value = Rec}. -%% decode_error/6 +%% decode_error/7 %% %% Error when decoding a non-grouped AVP. -decode_error(true, _, _, _, _, Avp) -> +decode_error(true, _, _, _, _, _, Avp) -> Avp; -decode_error(false, Reason, Name, Mod, Opts, Avp) -> - Stack = diameter_lib:get_stacktrace(), +decode_error(false, Reason, Stack, Name, Mod, Opts, Avp) -> + Z = diameter_lib:stacktrace(Stack), diameter_lib:log(decode_error, ?MODULE, ?LINE, - {Reason, Name, Avp#diameter_avp.name, Mod, Stack}), + {Reason, Name, Avp#diameter_avp.name, Mod, Z}), case Reason of {'DIAMETER', 5014 = RC, _} -> %% Length error communicated from diameter_types or a diff --git a/lib/diameter/src/base/diameter_internal.hrl b/lib/diameter/src/base/diameter_internal.hrl index a0f4a8567d..4a678643c2 100644 --- a/lib/diameter/src/base/diameter_internal.hrl +++ b/lib/diameter/src/base/diameter_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -35,9 +35,6 @@ %% A corresponding error when failure is the best option. -define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})). -%% Failure reports always get a stack trace. --define(STACK, erlang:get_stacktrace()). - %% Warning report for unexpected messages in various processes. -define(UNEXPECTED(F,A), diameter_lib:warning_report(unexpected, {?MODULE, F, A})). diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl index 1c1ea42cb5..edd9d5a4ce 100644 --- a/lib/diameter/src/base/diameter_lib.erl +++ b/lib/diameter/src/base/diameter_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -33,7 +33,7 @@ time/1, eval/1, eval_name/1, - get_stacktrace/0, + stacktrace/1, ipaddr/1, spawn_opts/2, wait/1, @@ -42,16 +42,13 @@ log/4]). %% --------------------------------------------------------------------------- -%% # get_stacktrace/0 +%% # stacktrace/1 %% --------------------------------------------------------------------------- %% Return a stacktrace with a leading, potentially large, argument -%% list replaced by an arity. Trace on stacktrace/0 to see the +%% list replaced by an arity. Trace on stacktrace/1 to see the %% original. -get_stacktrace() -> - stacktrace(erlang:get_stacktrace()). - stacktrace([{M,F,A,L} | T]) when is_list(A) -> [{M, F, length(A), L} | T]; stacktrace(L) -> @@ -268,8 +265,8 @@ ipaddr(Addr) -> try ip(Addr) catch - error: _ -> - erlang:error({invalid_address, erlang:get_stacktrace()}) + error: _: Stack -> + erlang:error({invalid_address, Stack}) end. %% Already a tuple: ensure non-negative integers of the right size. diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index cbe66ef27a..77d184cfc7 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -808,8 +808,8 @@ remotes(F) -> error_report(invalid_return, share_peers, F), [] catch - E:R -> - ?LOG(failure, {E, R, F, diameter_lib:get_stacktrace()}), + E:R:S -> + ?LOG(failure, {E, R, F, diameter_lib:stacktrace(S)}), error_report(failure, share_peers, F), [] end. @@ -1146,11 +1146,11 @@ peer_cb(App, F, A) -> mod_state(App#diameter_app.alias, ModS), true catch - E:R -> + E:R:S -> %% Don't include arguments since a #diameter_caps{} strings %% from the peer, which could be anything (especially, large). [Mod|X] = App#diameter_app.module, - ?LOG(failure, {E, R, Mod, F, diameter_lib:get_stacktrace()}), + ?LOG(failure, {E, R, Mod, F, diameter_lib:stacktrace(S)}), error_report(failure, F, {Mod, F, A ++ X}), false end. @@ -1376,9 +1376,9 @@ cm([#diameter_app{alias = Alias} = App], Req, From, Svc) -> ?LOG(invalid_return, {ModX, handle_call, Args, T}), invalid catch - E: Reason -> + E: Reason: S -> ModX = App#diameter_app.module, - Stack = diameter_lib:get_stacktrace(), + Stack = diameter_lib:stacktrace(S), ?LOG(failure, {E, Reason, ModX, handle_call, Stack}), failure end; @@ -1585,10 +1585,10 @@ pick_peer(Local, ?LOG(invalid_return, {ModX, pick_peer, T}), false catch - E: Reason when M -> + E: Reason: Stack when M -> ModX = App#diameter_app.module, - Stack = diameter_lib:get_stacktrace(), - ?LOG(failure, {E, Reason, ModX, pick_peer, Stack}), + Z = diameter_lib:stacktrace(Stack), + ?LOG(failure, {E, Reason, ModX, pick_peer, Z}), false end. diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl index eae40dbafd..03cfc03edc 100644 --- a/lib/diameter/src/compiler/diameter_make.erl +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2016. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -271,6 +271,6 @@ make(File, Opts, Dict, Mode) -> try diameter_codegen:from_dict(File, Dict, Opts, Mode) catch - error: Reason -> - erlang:error({Reason, Mode, erlang:get_stacktrace()}) + error: Reason: Stack -> + erlang:error({Reason, Mode, Stack}) end. diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src index 9a6e47006b..18202f033e 100644 --- a/lib/diameter/src/diameter.app.src +++ b/lib/diameter/src/diameter.app.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -28,14 +28,21 @@ ]}, {registered, [%REGISTERED%]}, {applications, [ - {stdlib, "2.4"}, {kernel, "3.2"}%, {erts, "6.4"} - %% {syntax-tools, "1.6,18"} - %% {runtime-tools, "1.8.16"} - %, {ssl, "6.0"} + stdlib, + kernel + %, ssl + %, syntax-tools + %, runtime-tools ]}, {env, []}, {mod, {diameter_app, []}}, {runtime_dependencies, [ + "erts-10.0", + "stdlib-2.4", + "kernel-3.2", + "ssl-9.0" + %, "syntax-tools-1.6.18" + %, "runtime-tools-1.8.16" ]} %% %% Note that ssl is only required if configured on TCP transports, diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl index a8639baa11..681d273d07 100644 --- a/lib/diameter/src/transport/diameter_tcp.erl +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -716,7 +716,7 @@ tls_handshake(_, false, S) -> tls(connect, Sock, Opts) -> ssl:connect(Sock, Opts); tls(accept, Sock, Opts) -> - ssl:ssl_accept(Sock, Opts). + ssl:handshake(Sock, Opts). %% assume no handshake option %% recv/2 %% @@ -839,7 +839,7 @@ start_fragment_timer(#transport{timeout = Tmo} = S) -> accept(ssl, LSock) -> case ssl:transport_accept(LSock) of {ok, Sock} -> - {ssl:ssl_accept(Sock), Sock}; + ssl:handshake(Sock); {error, _} = No -> No end; diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 71256020f5..ef4a28d3f4 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2015. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -208,9 +208,9 @@ xref(Config) -> CTmods = CTmods -- Mods, %% Ensure that runtime modules only call other runtime modules, or - %% applications declared as in runtime_dependencies in the app - %% file. Note that the declared application versions are ignored - %% since we only know what we can see now. + %% applications declared in runtime_dependencies in the app file. + %% The declared application versions are ignored since we only + %% know what we see now. [] = lists:filter(fun(M) -> not lists:member(app(M), Deps) end, RTdeps -- Mods). @@ -261,8 +261,12 @@ app(Mod) -> case code:which(Mod) of preloaded -> "erts"; + Reason when is_atom(Reason) -> + error({Reason, Mod}); Path -> - unversion(lists:nth(3, lists:reverse(filename:split(Path)))) + %% match to identify an unexpectedly short path + {_, _, [_,_,_|_] = Split} = {Mod, Path, filename:split(Path)}, + unversion(lists:nth(3, lists:reverse(Split))) end. add_application(XRef, App) -> diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index c224f9a27e..434aef01dd 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -1924,8 +1924,8 @@ compile_and_load() -> {module, nas4005} = code:load_binary(nas4005, "nas4005", Bin), true catch - E:R -> - {E, R, erlang:get_stacktrace()} + E:R:Stack -> + {E, R, Stack} end. here() -> diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl index 39c4f051a5..f3f168e671 100644 --- a/lib/diameter/test/diameter_watchdog_SUITE.erl +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2017. All Rights Reserved. +%% Copyright Ericsson AB 2010-2018. 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. @@ -638,10 +638,9 @@ run1([F|A]) -> apply(?MODULE, F, A), ok catch - E:R -> - S = erlang:get_stacktrace(), - ?WARN("~p", [{A, E, R, S}]), - S + E:R:Stack -> + ?WARN("~p", [{A, E, R, Stack}]), + Stack end. %% jitter/2 diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml index fc42ecd97d..4d40db086c 100644 --- a/lib/hipe/doc/src/hipe_app.xml +++ b/lib/hipe/doc/src/hipe_app.xml @@ -35,6 +35,14 @@ <app>HiPE</app> <appsummary>The HiPE Application</appsummary> <description> + <note> + <p> + HiPE and execution of HiPE compiled code only have limited support by + the OTP team at Ericsson. The OTP team only does limited maintenance + of HiPE and does not actively develop HiPE. HiPE is mainly supported + by the HiPE team at Uppsala University. + </p> + </note> <p> The normal way to native-compile an Erlang module using HiPE is to include the atom native in the Erlang compiler options, as in:</p> @@ -108,7 +116,7 @@ queue when the reference was created will be bypassed, as they cannot possibly contain the reference. HiPE currently has an optimization similar this, but it is not guaranteed to - bypass all messages. In the worst case scenario it, cannot + bypass all messages. In the worst case scenario, it cannot bypass any messages at all. </p> <p> @@ -117,21 +125,55 @@ </p> </item> + <tag>Garbage collection after BIFs</tag> + <item> + <p> + The condition for determining whether a garbage collection + is needed or not has changed in later releases. HiPE has not + been updated regarding this which may cause premature garbage + collections after BIF calls. + </p> + </item> + </taglist> </section> <section> <title>Stability Issues</title> <taglist> - <tag>Not yielding in <c>receive</c> statements</tag> + <tag>Not checking reduction count on function returns</tag> <item> - <p>HiPE will not yield in <c>receive</c> statements where - appropriate. If a process have lots of signals in its signal - queue and execute a HiPE compiled <c>receive</c> statement, - the scheduler thread performing the execution may be stuck - in the <c>receive</c> statement for a very long time. This - can in turn cause various severe issues such as for example - prevent the runtime system from being able to release - memory. + <p> + BEAM checks the reduction count and schedules out the executing + process if needed both when calling a function and when returning + from a function call that was not called using a tail call. + HiPE only checks the reduction count when calling a function. + </p> + <p> + The runtime system might need to schedule out a process + in order to reclaim memory. If the process isn't scheduled + out soon after the process has entered this state, memory + consumption will quickly grow. Maintaining this state is also + quite expensive performance wise. + </p> + <p> + Processes executing code that performs large recursions and + produce data after returning from recursive calls may have to + be scheduled out when returning from a function call. Since + HiPE does not check reductions on returns, processes executing + such HiPE compiled code may cause huge peeks in memory + consumption as well as severe performance degradation. + </p> + </item> + + <tag>Not bumping appropriate amount of reductions in <c>receive</c> statements</tag> + <item> + <p> + The process signaling improvements made in ERTS version + 10.0 moved potentially significant amounts of work into the + receive statement from other places. In order to account for + this work, the reduction count should be bumped on the + executing process. Reductions are not bumped when entering + the <c>receive</c> statement from HiPE compiled code. </p> </item> </taglist> diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl index af39c9a0a4..2c8cc80e56 100644 --- a/lib/hipe/rtl/hipe_rtl_lcm.erl +++ b/lib/hipe/rtl/hipe_rtl_lcm.erl @@ -267,14 +267,17 @@ try_insert_expr_last(CFG0, Label, Instr) -> %% with the new code inserted second to last (assuming the last expression %% is a branch operation). insert_expr_last_work(_Instr, [#call{}]) -> - %% Call instructions clobber all expressions; we musn't insert the expression - %% before it + %% Call instructions clobber all expressions; we must not insert the + %% expression before it not_safe; insert_expr_last_work(Instr, [Code1]) -> %% We insert the code next to last. [Instr, Code1]; insert_expr_last_work(Instr, [Code|Codes]) -> - [Code|insert_expr_last_work(Instr, Codes)]. + case insert_expr_last_work(Instr, Codes) of + not_safe -> not_safe; + NewCodes -> [Code|NewCodes] + end. %%============================================================================= %% Inserts expression first in the block for the given label. diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl index e71045bfe2..fc87abb54e 100644 --- a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl +++ b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl @@ -8,8 +8,9 @@ -export([test/0]). -%% functions that need to be exported so that they are retained. --export([auth/4]). +%% functions that need to be exported so that they are retained and/or +%% not specialized away by the compiler. +-export([auth/4, wxSizer_replace/2, parent_class/1]). test() -> ok = test_dominance_trees(), @@ -18,6 +19,7 @@ test() -> ok = test_bif_fails(), ok = test_find_catches(), ok = test_heap_allocate_trim(), + ok = wxSizer_replace(), ok. %%-------------------------------------------------------------------- @@ -151,3 +153,25 @@ get_next_retry(Error, Count) -> end. pair(A, B) -> {A, B}. + +%%-------------------------------------------------------------------- +%% Date: June 11, 2018 +%% +%% Stripped down test case (from `wxSizer') that crashed the lazy code +%% motion pass of the HiPE compiler in a pre-release of Erlang/OTP 21. +%% A similar crash existed in `ssl_correction'. +%%-------------------------------------------------------------------- + +wxSizer_replace() -> + wxSizer_replace(?MODULE, ?MODULE). + +-define(CLASS(Type, Class), ((Type) =:= Class) orelse (Type):parent_class(Class)). + +wxSizer_replace(OldwinT, NewwinT) -> % this function was the culprit + ?CLASS(OldwinT, ?MODULE), + ?CLASS(NewwinT, ?MODULE), + ok. + +parent_class(wxWindow) -> true; +parent_class(wxEvtHandler) -> true; +parent_class(_Class) -> erlang:error({badtype, ?MODULE}). diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml index 886286b76d..be914aee87 100644 --- a/lib/kernel/doc/src/application.xml +++ b/lib/kernel/doc/src/application.xml @@ -318,8 +318,13 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> <c>{error,{not_started,App}}</c> is returned, where <c>App</c> is the name of the missing application.</p> <p>The application controller then creates an <em>application master</em> - for the application. The application master is - the group leader of all the processes in the application. + for the application. The application master becomes the + group leader of all the processes in the application. I/O is + forwarded to the previous group leader, though, this is just + a way to identify processes that belong to the application. + Used for example to find itself from any process, or, + reciprocally, to kill them all when it terminates.</p> + <p> The application master starts the application by calling the application callback function <c>Module:start/2</c> as defined by the application specification key <c>mod</c>.</p> @@ -608,4 +613,3 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> <seealso marker="app">app(4)</seealso></p> </section> </erlref> - diff --git a/lib/kernel/doc/src/config.xml b/lib/kernel/doc/src/config.xml index 8850c1736b..3f01170508 100644 --- a/lib/kernel/doc/src/config.xml +++ b/lib/kernel/doc/src/config.xml @@ -86,8 +86,13 @@ <tag><c>File = string()</c></tag> <item>Name of another <c>.config</c> file. Extension <c>.config</c> can be omitted. It is - recommended to use absolute paths. A relative path is - relative the current working directory of the emulator.</item> + recommended to use absolute paths. If a relative path is used, + <c>File</c> is searched, first, relative from <c>sys.config</c> directory, then relative + to the current working directory of the emulator, for backward compatibility. + This allow to use a <c>sys.config</c> pointing out other <c>.config</c> files in a release + or in a node started manually using <c>-config ...</c> with same result whatever + the current working directory. + </item> </taglist> <p>When traversing the contents of <c>sys.config</c> and a filename is encountered, its contents are read and merged with the result diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index 0dad6ae935..a074d2e74b 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -1814,8 +1814,9 @@ check_conf() -> %% Therefore read and merge contents. if BFName =:= "sys" -> + DName = filename:dirname(FName), {ok, SysEnv, Errors} = - check_conf_sys(NewEnv), + check_conf_sys(NewEnv, [], [], DName), %% Report first error, if any, and %% terminate @@ -1837,20 +1838,31 @@ check_conf() -> end. check_conf_sys(Env) -> - check_conf_sys(Env, [], []). + check_conf_sys(Env, [], [], []). -check_conf_sys([File|T], SysEnv, Errors) when is_list(File) -> +check_conf_sys([File|T], SysEnv, Errors, DName) when is_list(File),is_list(DName) -> BFName = filename:basename(File, ".config"), FName = filename:join(filename:dirname(File), BFName ++ ".config"), - case load_file(FName) of + LName = case filename:pathtype(FName) of + relative when (DName =/= []) -> + % Check if relative to sys.config dir otherwise use legacy mode, + % i.e relative to cwd. + RName = filename:join(DName, FName), + case erl_prim_loader:read_file_info(RName) of + {ok, _} -> RName ; + error -> FName + end; + _ -> FName + end, + case load_file(LName) of {ok, NewEnv} -> - check_conf_sys(T, merge_env(SysEnv, NewEnv), Errors); + check_conf_sys(T, merge_env(SysEnv, NewEnv), Errors, DName); {error, {Line, _Mod, Str}} -> - check_conf_sys(T, SysEnv, [{error, {FName, Line, Str}}|Errors]) + check_conf_sys(T, SysEnv, [{error, {LName, Line, Str}}|Errors], DName) end; -check_conf_sys([Tuple|T], SysEnv, Errors) -> - check_conf_sys(T, merge_env(SysEnv, [Tuple]), Errors); -check_conf_sys([], SysEnv, Errors) -> +check_conf_sys([Tuple|T], SysEnv, Errors, DName) -> + check_conf_sys(T, merge_env(SysEnv, [Tuple]), Errors, DName); +check_conf_sys([], SysEnv, Errors, _) -> {ok, SysEnv, lists:reverse(Errors)}. load_file(File) -> diff --git a/lib/kernel/src/application_master.erl b/lib/kernel/src/application_master.erl index 5da2b0b06c..06991b45e1 100644 --- a/lib/kernel/src/application_master.erl +++ b/lib/kernel/src/application_master.erl @@ -118,6 +118,10 @@ init(Parent, Starter, ApplData, Type) -> link(Parent), process_flag(trap_exit, true), OldGleader = group_leader(), + %% We become the group leader, but forward all I/O to OldGleader. + %% This is just a way to identify processes that belong to the + %% application. Used for example to find ourselves from any + %% process, or, reciprocally, to kill them all when we terminate. group_leader(self(), self()), %% Insert ourselves as master for the process. This ensures that %% the processes in the application can use get_env/1 at startup. diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl index 988f26280f..3d07d6d70d 100644 --- a/lib/kernel/test/application_SUITE.erl +++ b/lib/kernel/test/application_SUITE.erl @@ -37,7 +37,8 @@ -export([config_change/1, persistent_env/1, distr_changed_tc1/1, distr_changed_tc2/1, ensure_started/1, ensure_all_started/1, - shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1]). + shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1, + config_relative_paths/1]). -define(TESTCASE, testcase_name). -define(testcase, proplists:get_value(?TESTCASE, Config)). @@ -55,7 +56,7 @@ all() -> script_start, nodedown_start, permit_false_start_local, permit_false_start_dist, get_key, get_env, ensure_all_started, {group, distr_changed}, config_change, shutdown_func, shutdown_timeout, - shutdown_deadlock, + shutdown_deadlock, config_relative_paths, persistent_env]. groups() -> @@ -2075,6 +2076,42 @@ shutdown_deadlock(Config) when is_list(Config) -> %%----------------------------------------------------------------- +%% Relative paths in sys.config +%%----------------------------------------------------------------- +config_relative_paths(Config) -> + Dir = ?config(priv_dir,Config), + SubDir = filename:join(Dir,"subdir"), + Sys = filename:join(SubDir,"sys.config"), + ok = filelib:ensure_dir(Sys), + ok = file:write_file(Sys,"[\"../up.config\",\"current\"].\n"), + + Up = filename:join(Dir,"up.config"), + ok = file:write_file(Up,"[{app1,[{key1,value}]}].\n"), + + {ok,Cwd} = file:get_cwd(), + Current1 = filename:join(Cwd,"current.config"), + ok = file:write_file(Current1,"[{app1,[{key2,value1}]}].\n"), + + N1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])), + {ok,Node1} = start_node(N1,filename:rootname(Sys)), + ok = rpc:call(Node1, application, load, [app1()]), + {ok, value} = rpc:call(Node1, application, get_env,[app1,key1]), + {ok, value1} = rpc:call(Node1, application, get_env,[app1,key2]), + + Current2 = filename:join(SubDir,"current.config"), + ok = file:write_file(Current2,"[{app1,[{key2,value2}]}].\n"), + + N2 = list_to_atom(lists:concat([?FUNCTION_NAME,"_2"])), + {ok, Node2} = start_node(N2,filename:rootname(Sys)), + ok = rpc:call(Node2, application, load, [app1()]), + {ok, value} = rpc:call(Node2, application, get_env,[app1,key1]), + {ok, value2} = rpc:call(Node2, application, get_env,[app1,key2]), + + stop_node_nice([Node1,Node2]), + + ok. + +%%----------------------------------------------------------------- %% Utility functions %%----------------------------------------------------------------- app0() -> diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 5d57109140..524869df16 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -969,35 +969,76 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </type> <desc> <p>This function checks that the <i>Presented Identifier</i> (e.g hostname) in a peer certificate - is in agreement with the <i>Reference Identifier</i> that the client expects to be connected to. + is in agreement with at least one of the <i>Reference Identifier</i> that the client expects to be connected to. The function is intended to be added as an extra client check of the peer certificate when performing <seealso marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso> </p> <p>See <url href="https://tools.ietf.org/html/rfc6125">RFC 6125</url> for detailed information about hostname verification. - The <seealso marker="using_public_key#verify_hostname">User's Manual</seealso> + The <seealso marker="using_public_key#verify_hostname">User's Guide</seealso> and <seealso marker="using_public_key#verify_hostname_examples">code examples</seealso> describes this function more detailed. </p> <p>The <c>{OtherRefId,term()}</c> is defined by the user and is passed to the <c>match_fun</c>, if defined. - If that term is a binary, it will be converted to a string. + If the term in <c>OtherRefId</c> is a binary, it will be converted to a string. </p> <p>The <c>ip</c> Reference ID takes an <seealso marker="inet:inet#type-ip_address">inet:ip_address()</seealso> or an ip address in string format (E.g "10.0.1.1" or "1234::5678:9012") as second element. </p> - <p>See <seealso marker="#pkix_verify_hostname_match_fun-1">pkix_verify_hostname_match_fun/1</seealso> for a - function that return a fun suitable for this option. - </p> + <p>The options are:</p> + <taglist> + <tag><c>match_fun</c></tag> + <item> + The <c>fun/2</c> in this option replaces the default host name matching rules. The fun should return a + boolean to tell if the Reference ID and Presented ID matches or not. The fun can also return a third + value, the atom <c>default</c>, if the default matching rules shall apply. + This makes it possible to augment the tests with a special case: + <code> +fun(....) -> true; % My special case + (_, _) -> default % all others falls back to the inherit tests +end + </code> + <br/>See <seealso marker="#pkix_verify_hostname_match_fun-1">pkix_verify_hostname_match_fun/1</seealso> for a + function that takes a protocol name as argument and returns a <c>fun/2</c> suitable for this option and + <seealso marker="using_public_key#redefining_match_op">Re-defining the match operation</seealso> + in the User's Guide for an example. + </item> + + <tag><c>fail_callback</c></tag> + <item>If a matching fails, there could be circumstances when the certificate should be accepted anyway. Think for + example of a web browser where you choose to accept an outdated certificate. This option enables implementation + of such a function. This <c>fun/1</c> is called when no <c>ReferenceID</c> matches. The return value of the fun + (a <c>boolean()</c>) decides the outcome. If <c>true</c> the the certificate is accepted otherwise + it is rejected. See + <seealso marker="using_public_key#-pinning--a-certificate">"Pinning" a Certificate</seealso> + in the User's Guide. + </item> + + <tag><c>fqdn_fun</c></tag> + <item>This option augments the host name extraction from URIs and other Reference IDs. It could for example be + a very special URI that is not standardised. The fun takes a Reference ID as argument and returns one of: + <list> + <item>the hostname</item> + <item>the atom <c>default</c>: the default host name extract function will be used</item> + <item>the atom <c>undefined</c>: a host name could not be extracted. The pkix_verify_hostname/3 + will return <c>false</c>.</item> + </list> + <br/>For an example, see + <seealso marker="using_public_key#hostname_extraction">Hostname extraction</seealso> + in the User's Guide. + </item> + </taglist> + </desc> </func> <func> - <name>pkix_verify_hostname_match_fun(Alg) -> fun(RefId | FQDN::string(), PresentedID) -> boolean() | default</name> + <name>pkix_verify_hostname_match_fun(Protcol) -> fun(RefId | FQDN::string(), PresentedID) -> boolean() | default</name> <fsummary>Returns a fun that is intendended as argument to the match_fun option in pkix_verify_hostname/3. </fsummary> <type> - <v>Alg = https</v> + <v>Protocol = https</v> <d>The algorithm for wich the fun should implement the special matching rules</d> <v>RefId</v> <d>See <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.</d> diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml index 417d479da3..b936b7fcb5 100644 --- a/lib/public_key/doc/src/using_public_key.xml +++ b/lib/public_key/doc/src/using_public_key.xml @@ -570,6 +570,7 @@ true = public_key:verify(Digest, none, Signature, PublicKey),</code> <c>fqdn_fun</c> and <c>match_fun</c>. </p> <section> + <marker id="hostname_extraction"></marker> <title>Hostname extraction</title> <p>The <c>fqdn_fun</c> extracts hostnames (Fully Qualified Domain Names) from uri_id or other ReferenceIDs that are not pre-defined in the public_key function. @@ -595,7 +596,8 @@ true = public_key:verify(Digest, none, Signature, PublicKey),</code> </code> </section> <section> - <title>Re-defining the match operations</title> + <marker id="redefining_match_op"></marker> + <title>Re-defining the match operation</title> <p>The default matching handles dns_id and uri_id. In an uri_id the value is tested for equality with a value from the <c>Subject Alternate Name</c>. If som other kind of matching is needed, use the <c>match_fun</c> option. diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 8d48cb911d..f64e0cca97 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -34,7 +34,23 @@ </header> - <section><title>SNMP 5.2.10</title> + <section><title>SNMP 5.2.11</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The Snmp MIB compiler now allows using a + TEXTUAL-CONVENTION type before defining it.</p> + <p> + Own Id: OTP-14196 Aux Id: ERIERL-161 </p> + </item> + </list> + </section> + +</section> + +<section><title>SNMP 5.2.10</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 2c97683625..96123f02f5 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -19,6 +19,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 5.2.10 +SNMP_VSN = 5.2.11 PRE_VSN = APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index adf4fb9ba4..19436b2100 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -896,16 +896,7 @@ fun(srp, Username :: string(), UserState :: term()) -> <v>Type = erlang | openssl | all</v> </type> <desc> - <p>Returns a list of supported cipher suites. - This function will become deprecated in OTP 21, and replaced - by <seealso marker="#cipher_suites-2">ssl:cipher-suites/2</seealso> - <c>cipher_suites()</c> is equivalent to <c>cipher_suites(erlang).</c> - Type <c>openssl</c> is provided for backwards compatibility with the - old SSL, which used OpenSSL. <c>cipher_suites(all)</c> returns - all available cipher suites. The cipher suites not present - in <c>cipher_suites(erlang)</c> but included in - <c>cipher_suites(all)</c> are not used unless explicitly configured - by the user.</p> + <p>Deprecated in OTP 21, use <seealso marker="#cipher_suites-2">ssl:cipher_suites/2</seealso> instead.</p> </desc> </func> @@ -948,7 +939,7 @@ fun(srp, Username :: string(), UserState :: term()) -> <func> <name>connect(Socket, SslOptions) -> </name> - <name>connect(Socket, SslOptions, Timeout) -> {ok, TLSSocket} | {ok, TLSSocket, Ext} + <name>connect(Socket, SslOptions, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason}</name> <fsummary>Upgrades a <c>gen_tcp</c>, or equivalent, connected socket to an TLS socket.</fsummary> @@ -956,7 +947,7 @@ fun(srp, Username :: string(), UserState :: term()) -> <v>Socket = socket()</v> <v>SslOptions = [{handshake, hello| full} | ssl_option()]</v> <v>Timeout = integer() | infinity</v> - <v>TLSSocket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Ext = hello_extensions()</v> <v>Reason = term()</v> </type> @@ -973,8 +964,8 @@ fun(srp, Username :: string(), UserState :: term()) -> <p> If the option <c>{handshake, hello}</c> is used the handshake is paused after receiving the server hello message - and the success response is <c>{ok, TLSSocket, Ext}</c> - instead of <c>{ok, TLSSocket}</c>. Thereafter the handshake is continued or + and the success response is <c>{ok, SslSocket, Ext}</c> + instead of <c>{ok, SslSocket}</c>. Thereafter the handshake is continued or canceled by calling <seealso marker="#handshake_continue-3"> <c>handshake_continue/3</c></seealso> or <seealso marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>. @@ -986,7 +977,7 @@ fun(srp, Username :: string(), UserState :: term()) -> <func> <name>connect(Host, Port, Options) -></name> <name>connect(Host, Port, Options, Timeout) -> - {ok, SslSocket}| {ok, TLSSocket, Ext} | {error, Reason}</name> + {ok, SslSocket}| {ok, SslSocket, Ext} | {error, Reason}</name> <fsummary>Opens an TLS/DTLS connection to <c>Host</c>, <c>Port</c>.</fsummary> <type> <v>Host = host()</v> @@ -1017,8 +1008,8 @@ fun(srp, Username :: string(), UserState :: term()) -> <p> If the option <c>{handshake, hello}</c> is used the handshake is paused after receiving the server hello message - and the success response is <c>{ok, TLSSocket, Ext}</c> - instead of <c>{ok, TLSSocket}</c>. Thereafter the handshake is continued or + and the success response is <c>{ok, SslSocket, Ext}</c> + instead of <c>{ok, SslSocket}</c>. Thereafter the handshake is continued or canceled by calling <seealso marker="#handshake_continue-3"> <c>handshake_continue/3</c></seealso> or <seealso marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>. @@ -1074,6 +1065,7 @@ fun(srp, Username :: string(), UserState :: term()) -> <fsummary>Returns all the connection information. </fsummary> <type> + <v>SslSocket = sslsocket()</v> <v>Item = protocol | cipher_suite | sni_hostname | ecc | session_id | atom()</v> <d>Meaningful atoms, not specified above, are the ssl option names.</d> <v>Result = [{Item::atom(), Value::term()}]</v> @@ -1091,6 +1083,7 @@ fun(srp, Username :: string(), UserState :: term()) -> <fsummary>Returns the requested connection information. </fsummary> <type> + <v>SslSocket = sslsocket()</v> <v>Items = [Item]</v> <v>Item = protocol | cipher_suite | sni_hostname | ecc | session_id | client_random | server_random | master_secret | atom()</v> @@ -1133,7 +1126,7 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>getopts(Socket, OptionNames) -> + <name>getopts(SslSocket, OptionNames) -> {ok, [socketoption()]} | {error, Reason}</name> <fsummary>Gets the values of the specified options.</fsummary> <type> @@ -1147,13 +1140,13 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>getstat(Socket) -> + <name>getstat(SslSocket) -> {ok, OptionValues} | {error, inet:posix()}</name> - <name>getstat(Socket, OptionNames) -> + <name>getstat(SslSocket, OptionNames) -> {ok, OptionValues} | {error, inet:posix()}</name> <fsummary>Get one or more statistic options for a socket</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>OptionNames = [atom()]</v> <v>OptionValues = [{inet:stat_option(), integer()}]</v> </type> @@ -1164,28 +1157,27 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>handshake(Socket) -> </name> - <name>handshake(Socket, Timeout) -> {ok, Socket} | {error, Reason}</name> + <name>handshake(HsSocket) -> </name> + <name>handshake(HsSocket, Timeout) -> {ok, SslSocket} | {error, Reason}</name> <fsummary>Performs server-side SSL/TLS handshake.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>HsSocket = SslSocket = sslsocket()</v> <v>Timeout = integer()</v> <v>Reason = term()</v> </type> <desc> <p>Performs the SSL/TLS/DTLS server-side handshake.</p> - <p><c>Socket</c> is a socket as returned by - <seealso marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso>. - </p> + <p>Returns a new TLS/DTLS socket if the handshake is successful.</p> </desc> </func> <func> <name>handshake(Socket, SslOptions) -> </name> - <name>handshake(Socket, SslOptions, Timeout) -> {ok, Socket} | {ok, Socket, Ext} | {error, Reason}</name> + <name>handshake(Socket, SslOptions, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason}</name> <fsummary>Performs server-side SSL/TLS/DTLS handshake.</fsummary> <type> <v>Socket = socket() | sslsocket() </v> + <v>SslSocket = sslsocket() </v> <v>Ext = hello_extensions()</v> <v>SslOptions = [{handshake, hello| full} | ssl_option()]</v> <v>Timeout = integer()</v> @@ -1194,22 +1186,23 @@ fun(srp, Username :: string(), UserState :: term()) -> <desc> <p>If <c>Socket</c> is a ordinary <c>socket()</c>: upgrades a <c>gen_tcp</c>, or equivalent, socket to an SSL socket, that is, performs - the SSL/TLS server-side handshake and returns the SSL socket.</p> + the SSL/TLS server-side handshake and returns a TLS socket.</p> - <warning><p>The Socket shall be in passive mode ({active, - false}) before calling this function or the handshake can fail - due to a race condition.</p></warning> + <warning><p>The <c>Socket</c> shall be in passive mode ({active, + false}) before calling this function or else the behavior of this function + is undefined. + </p></warning> <p>If <c>Socket</c> is an <c>sslsocket()</c>: provides extra SSL/TLS/DTLS options to those specified in <seealso marker="#listen-2">ssl:listen/2 </seealso> and then performs - the SSL/TLS/DTLS handshake.</p> - + the SSL/TLS/DTLS handshake. Returns a new TLS/DTLS socket if the handshake is successful.</p> + <p> If option <c>{handshake, hello}</c> is specified the handshake is paused after receiving the client hello message and the - sucess response is <c>{ok, TLSSocket, Ext}</c> instead of <c>{ok, - TLSSocket}</c>. Thereafter the handshake is continued or + success response is <c>{ok, SslSocket, Ext}</c> instead of <c>{ok, + SslSocket}</c>. Thereafter the handshake is continued or canceled by calling <seealso marker="#handshake_continue-3"> <c>handshake_continue/3</c></seealso> or <seealso marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>. @@ -1218,10 +1211,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>handshake_cancel(Socket) -> ok </name> + <name>handshake_cancel(SslSocket) -> ok </name> <fsummary>Cancel handshake with a fatal alert</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> </type> <desc> <p>Cancel the handshake with a fatal <c>USER_CANCELED</c> alert.</p> @@ -1229,10 +1222,11 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>handshake_continue(Socket, SSLOptions, Timeout) -> {ok, Socket} | {error, Reason}</name> + <name>handshake_continue(HsSocket, SSLOptions) -> {ok, SslSocket} | {error, Reason}</name> + <name>handshake_continue(HsSocket, SSLOptions, Timeout) -> {ok, SslSocket} | {error, Reason}</name> <fsummary>Continue the SSL/TLS handshake.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>HsSocket = SslSocket = sslsocket()</v> <v>SslOptions = [ssl_option()]</v> <v>Timeout = integer()</v> <v>Reason = term()</v> @@ -1257,10 +1251,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>negotiated_protocol(Socket) -> {ok, Protocol} | {error, protocol_not_negotiated}</name> + <name>negotiated_protocol(SslSocket) -> {ok, Protocol} | {error, protocol_not_negotiated}</name> <fsummary>Returns the protocol negotiated through ALPN or NPN extensions.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Protocol = binary()</v> </type> <desc> @@ -1271,10 +1265,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>peercert(Socket) -> {ok, Cert} | {error, Reason}</name> + <name>peercert(SslSocket) -> {ok, Cert} | {error, Reason}</name> <fsummary>Returns the peer certificate.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Cert = binary()</v> </type> <desc> @@ -1285,11 +1279,11 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>peername(Socket) -> {ok, {Address, Port}} | + <name>peername(SslSocket) -> {ok, {Address, Port}} | {error, Reason}</name> <fsummary>Returns the peer address and port.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Address = ipaddress()</v> <v>Port = integer()</v> </type> @@ -1335,12 +1329,12 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>recv(Socket, Length) -> </name> - <name>recv(Socket, Length, Timeout) -> {ok, Data} | {error, + <name>recv(SslSocket, Length) -> </name> + <name>recv(SslSocket, Length, Timeout) -> {ok, Data} | {error, Reason}</name> <fsummary>Receives data on a socket.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Length = integer()</v> <v>Timeout = integer()</v> <v>Data = [char()] | binary()</v> @@ -1362,10 +1356,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>renegotiate(Socket) -> ok | {error, Reason}</name> + <name>renegotiate(SslSocket) -> ok | {error, Reason}</name> <fsummary>Initiates a new handshake.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> </type> <desc><p>Initiates a new handshake. A notable return value is <c>{error, renegotiation_rejected}</c> indicating that the peer @@ -1375,10 +1369,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>send(Socket, Data) -> ok | {error, Reason}</name> + <name>send(SslSocket, Data) -> ok | {error, Reason}</name> <fsummary>Writes data to a socket.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Data = iodata()</v> </type> <desc> @@ -1389,10 +1383,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>setopts(Socket, Options) -> ok | {error, Reason}</name> + <name>setopts(SslSocket, Options) -> ok | {error, Reason}</name> <fsummary>Sets socket options.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Options = [socketoption]()</v> </type> <desc> @@ -1402,10 +1396,10 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>shutdown(Socket, How) -> ok | {error, Reason}</name> + <name>shutdown(SslSocket, How) -> ok | {error, Reason}</name> <fsummary>Immediately closes a socket.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>How = read | write | read_write</v> <v>Reason = reason()</v> </type> @@ -1420,19 +1414,16 @@ fun(srp, Username :: string(), UserState :: term()) -> </func> <func> - <name>ssl_accept(Socket) -> </name> - <name>ssl_accept(Socket, Timeout) -> ok | {error, Reason}</name> + <name>ssl_accept(SslSocket) -> </name> + <name>ssl_accept(SslSocket, Timeout) -> ok | {error, Reason}</name> <fsummary>Performs server-side SSL/TLS handshake.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Timeout = integer()</v> <v>Reason = term()</v> </type> <desc> - <p>Performs the SSL/TLS/DTLS server-side handshake.</p> - <p><c>Socket</c> is a socket as returned by - <seealso marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso> - </p> + <p>Deprecated in OTP 21, use <seealso marker="#handshake-1">ssl:handshake[1,2]</seealso> instead.</p> </desc> </func> @@ -1447,29 +1438,16 @@ fun(srp, Username :: string(), UserState :: term()) -> <v>Reason = term()</v> </type> <desc> - <p>If <c>Socket</c> is a <c>socket()</c>: upgrades a <c>gen_tcp</c>, - or equivalent, socket to an SSL socket, that is, performs - the SSL/TLS server-side handshake and returns the SSL socket.</p> - - <warning><p>The listen socket is to be in mode <c>{active, false}</c> - before telling the client that the server is ready to upgrade - by calling this function, else the upgrade succeeds or does not - succeed depending on timing.</p></warning> - - <p>If <c>Socket</c> is an <c>sslsocket()</c>: provides extra SSL/TLS/DTLS - options to those specified in - <seealso marker="#listen-2">ssl:listen/2 </seealso> and then performs - the SSL/TLS/DTLS handshake. - </p> + <p>Deprecated in OTP 21, use <seealso marker="#handshake-3">ssl:handshake[2,3]</seealso> instead.</p> </desc> </func> <func> - <name>sockname(Socket) -> {ok, {Address, Port}} | + <name>sockname(SslSocket) -> {ok, {Address, Port}} | {error, Reason}</name> <fsummary>Returns the local address and port.</fsummary> <type> - <v>Socket = sslsocket()</v> + <v>SslSocket = sslsocket()</v> <v>Address = ipaddress()</v> <v>Port = integer()</v> </type> @@ -1515,11 +1493,11 @@ fun(srp, Username :: string(), UserState :: term()) -> <func> <name>transport_accept(ListenSocket) -></name> <name>transport_accept(ListenSocket, Timeout) -> - {ok, NewSocket} | {error, Reason}</name> + {ok, SslSocket} | {error, Reason}</name> <fsummary>Accepts an incoming connection and prepares for <c>ssl_accept</c>.</fsummary> <type> - <v>ListenSocket = NewSocket = sslsocket()</v> + <v>ListenSocket = SslSocket = sslsocket()</v> <v>Timeout = integer()</v> <v>Reason = reason()</v> </type> diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml index 3ef33df719..b2d649042b 100644 --- a/lib/ssl/doc/src/using_ssl.xml +++ b/lib/ssl/doc/src/using_ssl.xml @@ -66,7 +66,7 @@ ssl:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},{reuseaddr, true} {ok,{sslsocket, [...]}}</code> <p><em>Step 3:</em> Do a transport accept on the TLS listen socket:</p> - <code type="erl">3 server> {ok, Socket} = ssl:transport_accept(ListenSocket). + <code type="erl">3 server> {ok, TLSTransportSocket} = ssl:transport_accept(ListenSocket). {ok,{sslsocket, [...]}}</code> <p><em>Step 4:</em> Start the client side: </p> @@ -77,7 +77,7 @@ ok</code> {ok,{sslsocket, [...]}}</code> <p><em>Step 5:</em> Do the TLS handshake:</p> - <code type="erl">4 server> ok = ssl:ssl_accept(Socket). + <code type="erl">4 server> {ok, Socket} = ssl:handshake(TLSTransportSocket). ok</code> <p><em>Step 6:</em> Send a message over TLS:</p> @@ -126,7 +126,7 @@ ok</code> ok</code> <p><em>Step 6:</em> Do the TLS handshake:</p> - <code type="erl">5 server> {ok, TLSSocket} = ssl:ssl_accept(Socket, [{cacertfile, "cacerts.pem"}, + <code type="erl">5 server> {ok, TLSSocket} = ssl:handshake(Socket, [{cacertfile, "cacerts.pem"}, {certfile, "cert.pem"}, {keyfile, "key.pem"}]). {ok,{sslsocket,[...]}}</code> diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index eb5b351dd3..f5e5336f81 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -40,7 +40,7 @@ %% Socket handling -export([connect/3, connect/2, connect/4, listen/2, transport_accept/1, transport_accept/2, - handshake/1, handshake/2, handshake/3, + handshake/1, handshake/2, handshake/3, handshake_continue/2, handshake_continue/3, handshake_cancel/1, ssl_accept/1, ssl_accept/2, ssl_accept/3, controlling_process/2, peername/1, peercert/1, sockname/1, @@ -259,6 +259,16 @@ handshake(Socket, SslOptions, Timeout) when is_port(Socket), Error = {error, _Reason} -> Error end. + +%%-------------------------------------------------------------------- +-spec handshake_continue(#sslsocket{}, [ssl_option()]) -> + {ok, #sslsocket{}} | {error, reason()}. +%% +%% +%% Description: Continues the handshke possible with newly supplied options. +%%-------------------------------------------------------------------- +handshake_continue(Socket, SSLOptions) -> + handshake_continue(Socket, SSLOptions, infinity). %%-------------------------------------------------------------------- -spec handshake_continue(#sslsocket{}, [ssl_option()], timeout()) -> {ok, #sslsocket{}} | {error, reason()}. diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 1e88ca15de..8532b9ac0f 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -309,7 +309,7 @@ client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) -> case rpc:call(Node, Transport, connect, [Host, Port, Options]) of {ok, Socket0, _} -> ct:log("~p:~p~nClient: handshake_continue(~p, ~p, infinity) ~n", [?MODULE, ?LINE, Socket0, ContOpts]), - case rpc:call(Node, Transport, handshake_continue, [Socket0, ContOpts, infinity]) of + case rpc:call(Node, Transport, handshake_continue, [Socket0, ContOpts]) of {ok, Socket} -> Pid ! {connected, Socket}, {Module, Function, Args} = proplists:get_value(mfa, Opts), @@ -1170,13 +1170,13 @@ rsa_suites(CounterPart) -> lists:member(cipher_atom(Cipher), Ciphers); ({ecdhe_rsa, Cipher, _}) when ECC == true -> lists:member(cipher_atom(Cipher), Ciphers); + ({ecdhe_rsa, Cipher, _,_}) when ECC == true -> + lists:member(cipher_atom(Cipher), Ciphers); ({rsa, Cipher, _, _}) -> lists:member(cipher_atom(Cipher), Ciphers); ({dhe_rsa, Cipher, _,_}) -> lists:member(cipher_atom(Cipher), Ciphers); - ({ecdhe_rsa, Cipher, _,_}) when ECC == true -> - lists:member(cipher_atom(Cipher), Ciphers); - (_) -> + (_) -> false end, common_ciphers(CounterPart)). @@ -1530,7 +1530,7 @@ is_sane_ecc(crypto) -> true end; is_sane_ecc(_) -> - true. + sufficient_crypto_support(cipher_ec). is_fips(openssl) -> VersionStr = os:cmd("openssl version"), @@ -1601,11 +1601,7 @@ openssl_sane_dtls() -> false; "OpenSSL 1.0.2k-freebsd" ++ _ -> false; - "OpenSSL 1.0.2d" ++ _ -> - false; - "OpenSSL 1.0.2n" ++ _ -> - false; - "OpenSSL 1.0.2m" ++ _ -> + "OpenSSL 1.0.2" ++ _ -> false; "OpenSSL 1.0.0" ++ _ -> false; diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index 19d22f24f0..faa43fbc1e 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -1448,13 +1448,13 @@ loop_event_done( [?sys_debug( Debug_0, {S#state.name,State}, - {postpone,Event_0,State}), + {postpone,Event_0,NextState}), Event_0|P_0]; false -> [?sys_debug( Debug_0, {S#state.name,State}, - {consume,Event_0,State})|P_0] + {consume,Event_0,NextState})|P_0] end, {Events_2,P_2,Timers_2} = %% Move all postponed events to queue, diff --git a/make/cross_check_erl b/make/cross_check_erl index f8ba73023a..524514a63f 100755 --- a/make/cross_check_erl +++ b/make/cross_check_erl @@ -90,7 +90,7 @@ start() -> EOF erlc cross_check_erl.erl 2>/dev/null \ - && used_otp=`erl -noshell -noinput -pa . -run cross_check_erl 2>/dev/null` + && used_otp=`erl -noshell -noinput -boot start_clean -pa . -run cross_check_erl 2>/dev/null` res=$? diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk index f57116569c..d1fbf6c58f 100644 --- a/make/otp_release_targets.mk +++ b/make/otp_release_targets.mk @@ -41,6 +41,8 @@ _create_xml_dirs := $(shell mkdir -p $(XMLDIR)) endif XML_GEN_FILES+=$(patsubst %.xml,$(XMLDIR)/%.xml,$(XML_FILES)) + +ifeq ($(strip $(NO_GITHUB_DOC_LINKS)),) $(XMLDIR)/%.xml: %.xml $(gen_verbose)escript $(DOCGEN)/priv/bin/github_link.escript $< \ "$(subst $(ERL_TOP)/,,$(CURDIR)/$^)" "NA" $@ @@ -48,6 +50,13 @@ $(XMLDIR)/%.xml: %.xml $(XMLDIR)/%.xmlsrc: %.xmlsrc $(gen_verbose)escript $(DOCGEN)/priv/bin/github_link.escript $< \ "$(subst $(ERL_TOP)/,,$(CURDIR)/$^)" "NA" $@ +else +## Just copy the files if the application does not want github edit links +$(XMLDIR)/%.xml: %.xml + $(gen_verbose)$(CP) $< $@ +$(XMLDIR)/%.xmlsrc: %.xmlsrc + $(gen_verbose)$(CP) $< $@ +endif ifeq ($(TOPDOC),) diff --git a/otp_versions.table b/otp_versions.table index 22762f0691..9f6488b159 100644 --- a/otp_versions.table +++ b/otp_versions.table @@ -1,3 +1,4 @@ +OTP-20.3.8 : erts-9.3.3 snmp-5.2.11 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 inets-6.5.2 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 ssh-4.6.9 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 : OTP-20.3.7 : erl_docgen-0.7.3 erts-9.3.2 inets-6.5.2 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_interface-3.10.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.10 ssh-4.6.9 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 : OTP-20.3.6 : crypto-4.2.2 ssh-4.6.9 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.2 erl_interface-3.10.2 erts-9.3.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 inets-6.5.1 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.10 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 : OTP-20.3.5 : erts-9.3.1 ssl-8.2.6 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.1 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.2 erl_interface-3.10.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 inets-6.5.1 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.10 ssh-4.6.8 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 : diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml index c673fde07e..6e5a2ce6cf 100644 --- a/system/doc/design_principles/applications.xml +++ b/system/doc/design_principles/applications.xml @@ -363,9 +363,13 @@ ok application are running.</p> <marker id="application_master"></marker> <p>The application controller then creates an - <em>application master</em> for the application. The application master - is the group leader of all the processes in the application. - The application master starts the application by calling + <em>application master</em> for the application. The application + master becomes the group leader of all the processes in the + application. I/O is forwarded to the previous group leader, + though, this is just a way to identify processes that belong to + the application. Used for example to find itself from any process, + or, reciprocally, to kill them all when it terminates.</p> + <p>The application master starts the application by calling the application callback function <c>start/2</c> in the module, and with the start argument, defined by the <c>mod</c> key in the <c>.app</c> file.</p> diff --git a/system/doc/system_principles/misc.xml b/system/doc/system_principles/misc.xml new file mode 100644 index 0000000000..dd6c2a1336 --- /dev/null +++ b/system/doc/system_principles/misc.xml @@ -0,0 +1,198 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2018</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>Support, Compatibility, Deprecations, and Removal</title> + <prepared></prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>2018-05-21</date> + <rev></rev> + <file>misc.xml</file> + </header> + + <section> + <marker id="supported_releases"/> + <title>Supported Releases</title> + <p> + In general, bugs are only fixed on the latest + <seealso marker="versions#releases_and_patches">release</seealso>, + and new features are introduced in the upcoming release that is + under development. However, when we, due to internal reasons, fix + bugs on older releases, these will be available and announced as well. + </p> + <p> + Due to the above, pull requests are only accepted on the + <c>maint</c> and the <c>master</c> branches in our + <url href="https://github.com/erlang/otp">git repository</url>. + The <c>maint</c> branch contains changes planned for the next + <seealso marker="versions#releases_and_patches">maintenance patch package</seealso> + on the latest OTP release and the <c>master</c> branch contain + changes planned for the upcoming OTP release. + </p> + </section> + + <section> + <marker id="compatibility"/> + <title>Compatibility</title> + <p> + We always strive to remain as compatible as possible + even in the cases where we give no compatibility guarantees. + </p> + <p> + Different parts of the system will be handled differently + regarding compatibility. The following items describe how + different parts of the system are handled. + </p> + <taglist> + <tag>Erlang Distribution</tag> + <item> + <p> + Erlang nodes can communicate across at least + two preceding and two subsequent releases. + </p> + </item> + <tag>Compiled BEAM Code, NIF Libraries and Drivers</tag> + <item> + <p> + Compiled code can be loaded on at least two + subsequent releases. + </p> + <p> + Loading on previous releases is <em>not</em> supported. + </p> + </item> + <tag>Compiled HiPE Code</tag> + <item> + <p> + Compiled HiPE code can be loaded on the exact same build + of ERTS that was used when compiling the code. It might + however work on other builds, the emulator verifies + checksums in order to determine if it can load the code + or not. Note that HiPE has some limitations. For more + information see the documentation of the + <seealso marker="hipe:HiPE_app">HiPE</seealso> application. + </p> + </item> + <tag>APIs</tag> + <item> + <p>Compatible between releases.</p> + </item> + <tag>Compiler Warnings</tag> + <item> + <p>New warnings may be issued between releases.</p> + </item> + <tag>Command Line Arguments</tag> + <item> + <p>Incompatible changes may occur between releases.</p> + </item> + <tag>OTP Build Procedures</tag> + <item><p>Incompatible changes may occur between releases.</p></item> + </taglist> + <p> + Under certain circumstances incompatible changes might be + introduced even in parts of the system that should be compatible + between releases. Things that might trigger incompatible changes + like this are: + </p> + <taglist> + <tag>Security Issues</tag> + <item> + <p> + It might be necessary to introduce incompatible changes + in order to solve a security issue. This kind of + incompatibility might occur in a patch. + </p> + </item> + <tag>Bug Fixes</tag> + <item> + <p> + We will not be bug-compatible. A bug fix might introduce + incompatible changes. This kind of incompatibility + might occur in a patch. + </p> + </item> + <tag>Severe Previous Design Issues</tag> + <item> + <p> + Some parts of OTP were designed a very long time ago and + did not necessarily take today's computing environments into + account. In some cases the consequences of those design + decisions are too severe. This may be performance wise, + scalability wise, etc. If we deem the consequences too + severe, we might introduce incompatible changes. This kind + of incompatibility will not be introduced in a patch, but + instead in the next release. + </p> + </item> + </taglist> + <p> + Peripheral, trace, and debug functionality is at greater + risk of being changed in an incompatible way than functionality + in the language itself and core libraries used during operation. + </p> + </section> + + <section> + <marker id="deprecation"/> + <title>Deprecation</title> + <p> + Functionality is deprecated when new functionality is + introduced that is preferred to be used instead of the + old functionality that is being deprecated. The deprecation + does <em>not</em> imply removal of the functionality unless + an upcoming removal is explicitly stated in the deprecation. + </p> + <p> + Deprecated functionality will be documented as deprecated, and + compiler warnings will be issued, when appropriate, as + early as possible. That is, the new preferred functionality + will appear at the same time as the deprecation is issued. + A new deprecation will at least be announced in a release + note and the documentation. + </p> + </section> + + <section> + <marker id="removal"/> + <title>Removal</title> + <p> + Legacy solutions may eventually need to be removed. In such + cases, they will be phased out on a long enough time period + to give users the time to adapt. Before removal of + functionality it will be deprecated at least during one + release with an explicit announcement about + the upcoming removal. A new deprecation will at least be + announced in a release note and the documentation. + </p> + <p> + Peripheral, trace, and debug functionality is at greater + risk of removal than functionality in the language itself + and core libraries used during operation. + </p> + </section> + +</chapter> + diff --git a/system/doc/system_principles/part.xml b/system/doc/system_principles/part.xml index 1b87ecd350..9f70f40dfb 100644 --- a/system/doc/system_principles/part.xml +++ b/system/doc/system_principles/part.xml @@ -34,4 +34,5 @@ <xi:include href="create_target.xml"/> <xi:include href="upgrade.xml"/> <xi:include href="versions.xml"/> + <xi:include href="misc.xml"/> </part> diff --git a/system/doc/system_principles/versions.xml b/system/doc/system_principles/versions.xml index b9f7fa4bf6..355c8fd2d5 100644 --- a/system/doc/system_principles/versions.xml +++ b/system/doc/system_principles/versions.xml @@ -32,9 +32,9 @@ <rev></rev> <file>versions.xml</file> </header> - <marker id="versions section"></marker> <section> + <marker id="versions section"></marker> <title>OTP Version</title> <p>As of OTP release 17, the OTP release number corresponds to the major part of the OTP version. The OTP version as a concept was @@ -136,8 +136,8 @@ </section> <section> - <title>Version Scheme</title> <marker id="version_scheme"/> + <title>Version Scheme</title> <note><p>The version scheme was changed as of OTP 17.0. This implies that application versions used prior to OTP 17.0 do not adhere to this version scheme. <seealso marker="#otp_17_0_app_versions">A list of @@ -207,8 +207,41 @@ </section> <section> - <title>OTP 17.0 Application Versions</title> + <marker id="releases_and_patches"/> + <title>Releases and Patches</title> + <p> + When a new OTP release is released it will have an OTP + version on the form <c><Major>.0</c> where the + major OTP version number equals the release number. + The major version number is increased one step since the + last major version. All other OTP versions with the same + major OTP version number are patches on that OTP release. + </p> + <p> + Patches are either released as maintenance patch packages + or emergency patch packages. The only difference is that + maintenance patch packages are planned and usually contain + more changes than emergency patch packages. Emergency patch + packages are released to solve one or more specific issues + when such are discovered. + </p> + <p> + The release of a maintenance patch package usually imply + an increase of the OTP <c><Minor></c> version while + the release of an emergency patch package usually imply an + increase of the OTP <c><Patch></c> version. This is + however not necessarily always the case since changes of + OTP versions are based on the actual changes in the code + and not based on whether the patch was planned or not. + For more information see the + <seealso marker="#version_scheme">Version Scheme</seealso> + section above. + </p> + </section> + + <section> <marker id="otp_17_0_app_versions"/> + <title>OTP 17.0 Application Versions</title> <p>The following list details the application versions that were part of OTP 17.0. If the normal part of an application version number compares diff --git a/system/doc/system_principles/xmlfiles.mk b/system/doc/system_principles/xmlfiles.mk index 77d6747414..353c2c7f7f 100644 --- a/system/doc/system_principles/xmlfiles.mk +++ b/system/doc/system_principles/xmlfiles.mk @@ -21,7 +21,8 @@ SYSTEM_PRINCIPLES_CHAPTER_FILES = \ system_principles.xml \ error_logging.xml \ upgrade.xml \ - versions.xml + versions.xml \ + misc.xml SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES = \ create_target.xml |