aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OTP_VERSION2
-rw-r--r--erts/doc/src/notes.xml24
-rw-r--r--erts/emulator/nifs/common/zlib_nif.c127
-rw-r--r--erts/preloaded/ebin/zlib.beambin19120 -> 19492 bytes
-rw-r--r--erts/preloaded/src/zlib.erl38
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/compiler/doc/src/notes.xml16
-rw-r--r--lib/compiler/src/beam_validator.erl6
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl38
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/kernel/test/zlib_SUITE.erl23
-rw-r--r--lib/ssh/doc/src/notes.xml28
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl10
-rw-r--r--lib/ssh/src/ssh_transport.erl21
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--otp_versions.table1
16 files changed, 231 insertions, 109 deletions
diff --git a/OTP_VERSION b/OTP_VERSION
index 2e73f8d2aa..2a0e5e0a15 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-20.1
+20.1.1
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 1a5bea8820..fa200176e4 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,30 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 9.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The new zlib module returned a data_error when
+ inflating concatenated streams, which was incompatible
+ with the old module's behavior of returning the
+ uncompressed data up to the end of the first stream.</p>
+ <p>
+ Own Id: OTP-14648</p>
+ </item>
+ <item>
+ <p>zlib:gunzip/1 will no longer stop at the end of the
+ first stream when decompressing concatenated gzip
+ files.</p>
+ <p>
+ Own Id: OTP-14649</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 9.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/nifs/common/zlib_nif.c b/erts/emulator/nifs/common/zlib_nif.c
index a1a65e1946..a9c5b05e47 100644
--- a/erts/emulator/nifs/common/zlib_nif.c
+++ b/erts/emulator/nifs/common/zlib_nif.c
@@ -69,11 +69,27 @@ typedef enum {
ST_DEFLATE = 1,
ST_INFLATE = 2,
ST_CLOSED = 3
-} zlib_state;
+} zlib_state_t;
+
+/* Controls what to do when the user attempts to decompress more data after
+ * Z_STREAM_END has been returned:
+ *
+ * - 'cut' wipes all further input and returns empty results until reset by
+ * the user. This is the default behavior, matching that of the old driver.
+ * - 'reset' resets the state without discarding any input, making it possible
+ * to decompress blindly concatenated streams.
+ * - 'error' crashes with a data error. */
+typedef enum {
+ EOS_BEHAVIOR_ERROR = 0,
+ EOS_BEHAVIOR_RESET = 1,
+ EOS_BEHAVIOR_CUT = 2
+} zlib_eos_behavior_t;
typedef struct {
z_stream s;
- zlib_state state;
+ zlib_state_t state;
+
+ zlib_eos_behavior_t eos_behavior;
/* These refer to the plaintext CRC, and are only needed for zlib:crc32/1
* which is deprecated. */
@@ -102,7 +118,6 @@ typedef struct {
static ERL_NIF_TERM zlib_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_close(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_deflateInit(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM zlib_deflateInit2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_deflateSetDictionary(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_deflateReset(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_deflateEnd(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
@@ -110,7 +125,6 @@ static ERL_NIF_TERM zlib_deflateParams(ErlNifEnv *env, int argc, const ERL_NIF_T
static ERL_NIF_TERM zlib_deflate(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_inflateInit(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM zlib_inflateInit2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_inflateSetDictionary(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_inflateGetDictionary(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM zlib_inflateReset(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
@@ -130,8 +144,7 @@ static ERL_NIF_TERM zlib_enqueue_input(ErlNifEnv *env, int argc, const ERL_NIF_T
static ErlNifFunc nif_funcs[] = {
/* deflate */
- {"deflateInit_nif", 2, zlib_deflateInit},
- {"deflateInit_nif", 6, zlib_deflateInit2},
+ {"deflateInit_nif", 6, zlib_deflateInit},
{"deflateSetDictionary_nif", 2, zlib_deflateSetDictionary},
{"deflateReset_nif", 1, zlib_deflateReset},
{"deflateEnd_nif", 1, zlib_deflateEnd},
@@ -139,8 +152,7 @@ static ErlNifFunc nif_funcs[] = {
{"deflate_nif", 4, zlib_deflate},
/* inflate */
- {"inflateInit_nif", 1, zlib_inflateInit},
- {"inflateInit_nif", 2, zlib_inflateInit2},
+ {"inflateInit_nif", 3, zlib_inflateInit},
{"inflateSetDictionary_nif", 2, zlib_inflateSetDictionary},
{"inflateGetDictionary_nif", 1, zlib_inflateGetDictionary},
{"inflateReset_nif", 1, zlib_inflateReset},
@@ -509,9 +521,11 @@ static ERL_NIF_TERM zlib_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[
d->s.opaque = d;
d->s.data_type = Z_BINARY;
- d->state = ST_NONE;
+ d->eos_behavior = EOS_BEHAVIOR_CUT;
d->eos_seen = 0;
+ d->state = ST_NONE;
+
d->want_output_crc = 0;
d->want_input_crc = 0;
d->is_raw_stream = 0;
@@ -551,42 +565,6 @@ static ERL_NIF_TERM zlib_close(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv
static ERL_NIF_TERM zlib_deflateInit(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
zlib_data_t *d;
- int level, res;
-
- if(argc != 2 || !get_zlib_data(env, argv[0], &d) ||
- !enif_get_int(env, argv[1], &level)) {
- return enif_make_badarg(env);
- } else if(!zlib_process_check(env, d)) {
- return enif_raise_exception(env, am_not_on_controlling_process);
- } else if(d->state != ST_NONE) {
- return enif_raise_exception(env, am_already_initialized);
- }
-
- res = deflateInit(&d->s, level);
-
- if(res == Z_OK) {
- d->state = ST_DEFLATE;
- d->eos_seen = 0;
-
- /* FIXME: crc32/1 is documented as returning "the current calculated
- * checksum," but failed to mention that the old implementation only
- * calculated it when WindowBits < 0 (See zlib_deflateInit2).
- *
- * We could fix this behavior by setting d->want_input_crc to 1 here,
- * but we've decided to retain this quirk since the performance hit is
- * quite significant. */
- d->want_output_crc = 0;
- d->want_input_crc = 0;
-
- d->output_crc = crc32(0L, Z_NULL, 0);
- d->input_crc = crc32(0L, Z_NULL, 0);
- }
-
- return zlib_return(env, res);
-}
-
-static ERL_NIF_TERM zlib_deflateInit2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
- zlib_data_t *d;
int level, method, windowBits, memLevel, strategy, res;
if(argc != 6 || !get_zlib_data(env, argv[0], &d)
@@ -741,39 +719,12 @@ static ERL_NIF_TERM zlib_deflate(ErlNifEnv *env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM zlib_inflateInit(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
zlib_data_t *d;
- int res;
- if(argc != 1 || !get_zlib_data(env, argv[0], &d)) {
- return enif_make_badarg(env);
- } else if(!zlib_process_check(env, d)) {
- return enif_raise_exception(env, am_not_on_controlling_process);
- } else if(d->state != ST_NONE) {
- return enif_raise_exception(env, am_already_initialized);
- }
-
- res = inflateInit(&d->s);
-
- if(res == Z_OK) {
- d->state = ST_INFLATE;
- d->eos_seen = 0;
-
- d->want_output_crc = 0;
- d->want_input_crc = 0;
- d->is_raw_stream = 0;
-
- d->output_crc = crc32(0L, Z_NULL, 0);
- d->input_crc = crc32(0L, Z_NULL, 0);
- }
-
- return zlib_return(env, res);
-}
+ int windowBits, eosBehavior, res;
-static ERL_NIF_TERM zlib_inflateInit2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
- zlib_data_t *d;
- int windowBits, res;
-
- if(argc != 2 || !get_zlib_data(env, argv[0], &d)
- || !enif_get_int(env, argv[1], &windowBits)) {
+ if(argc != 3 || !get_zlib_data(env, argv[0], &d)
+ || !enif_get_int(env, argv[1], &windowBits)
+ || !enif_get_int(env, argv[2], &eosBehavior)) {
return enif_make_badarg(env);
} else if(!zlib_process_check(env, d)) {
return enif_raise_exception(env, am_not_on_controlling_process);
@@ -785,6 +736,8 @@ static ERL_NIF_TERM zlib_inflateInit2(ErlNifEnv *env, int argc, const ERL_NIF_TE
if(res == Z_OK) {
d->state = ST_INFLATE;
+
+ d->eos_behavior = eosBehavior;
d->eos_seen = 0;
d->is_raw_stream = (windowBits < 0);
@@ -934,6 +887,28 @@ static ERL_NIF_TERM zlib_inflate(ErlNifEnv *env, int argc, const ERL_NIF_TERM ar
return enif_raise_exception(env, am_not_initialized);
}
+ if(d->eos_seen) {
+ int res;
+
+ switch(d->eos_behavior) {
+ case EOS_BEHAVIOR_ERROR:
+ return zlib_return(env, Z_DATA_ERROR);
+ case EOS_BEHAVIOR_RESET:
+ res = inflateReset(&d->s);
+
+ if(res != Z_OK) {
+ return zlib_return(env, res);
+ }
+
+ d->eos_seen = 0;
+ break;
+ case EOS_BEHAVIOR_CUT:
+ zlib_reset_input(d);
+
+ return enif_make_tuple2(env, am_finished, enif_make_list(env, 0));
+ }
+ }
+
return zlib_codec(&inflate, env, d, input_chunk_size, output_chunk_size, flush);
}
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 267b5cb0a8..5048bdb846 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl
index dca5a42779..3170ab6351 100644
--- a/erts/preloaded/src/zlib.erl
+++ b/erts/preloaded/src/zlib.erl
@@ -23,7 +23,7 @@
-export([open/0,close/1,deflateInit/1,deflateInit/2,deflateInit/6,
deflateSetDictionary/2,deflateReset/1,deflateParams/3,
deflate/2,deflate/3,deflateEnd/1,
- inflateInit/1,inflateInit/2,
+ inflateInit/1,inflateInit/2,inflateInit/3,
inflateSetDictionary/2,inflateGetDictionary/1, inflateReset/1,
inflate/2,inflate/3,inflateEnd/1,
inflateChunk/2,inflateChunk/1,
@@ -68,6 +68,13 @@
-define(MAX_WBITS, 15).
+-define(DEFAULT_MEMLEVEL, 8).
+-define(DEFAULT_WBITS, 15).
+
+-define(EOS_BEHAVIOR_ERROR, 0).
+-define(EOS_BEHAVIOR_RESET, 1).
+-define(EOS_BEHAVIOR_CUT, 2).
+
%% Chunk sizes are hardcoded on account of them screwing with the
%% predictability of the system. zlib is incapable of trapping so we need to
%% ensure that it never operates on any significant amount of data.
@@ -130,10 +137,7 @@ deflateInit(Z) ->
Z :: zstream(),
Level :: zlevel().
deflateInit(Z, Level) ->
- deflateInit_nif(Z, arg_level(Level)).
-
-deflateInit_nif(_Z, _Level) ->
- erlang:nif_error(undef).
+ deflateInit(Z, Level, deflated, ?DEFAULT_WBITS, ?DEFAULT_MEMLEVEL, default).
-spec deflateInit(Z, Level, Method, WindowBits, MemLevel, Strategy) -> 'ok' when
Z :: zstream(),
@@ -225,16 +229,21 @@ deflateEnd_nif(_Z) ->
-spec inflateInit(Z) -> 'ok' when
Z :: zstream().
inflateInit(Z) ->
- inflateInit_nif(Z).
-inflateInit_nif(_Z) ->
- erlang:nif_error(undef).
+ inflateInit(Z, ?DEFAULT_WBITS).
-spec inflateInit(Z, WindowBits) -> 'ok' when
Z :: zstream(),
WindowBits :: zwindowbits().
inflateInit(Z, WindowBits) ->
- inflateInit_nif(Z, WindowBits).
-inflateInit_nif(_Z, _WindowBits) ->
+ inflateInit(Z, WindowBits, cut).
+
+-spec inflateInit(Z, WindowBits, EoSBehavior) -> 'ok' when
+ Z :: zstream(),
+ WindowBits :: zwindowbits(),
+ EoSBehavior :: error | reset | cut.
+inflateInit(Z, WindowBits, EoSBehavior) ->
+ inflateInit_nif(Z, arg_bitsz(WindowBits), arg_eos_behavior(EoSBehavior)).
+inflateInit_nif(_Z, _WindowBits, _EoSBehavior) ->
erlang:nif_error(undef).
-spec inflateSetDictionary(Z, Dictionary) -> 'ok' when
@@ -532,7 +541,7 @@ gzip(Data) ->
gunzip(Data) ->
Z = open(),
Bs = try
- inflateInit(Z, 16+?MAX_WBITS),
+ inflateInit(Z, 16+?MAX_WBITS, reset),
B = inflate(Z, Data),
inflateEnd(Z),
B
@@ -652,6 +661,11 @@ arg_strategy(_) -> erlang:error(bad_compression_strategy).
arg_method(deflated) -> ?Z_DEFLATED;
arg_method(_) -> erlang:error(bad_compression_method).
+arg_eos_behavior(error) -> ?EOS_BEHAVIOR_ERROR;
+arg_eos_behavior(reset) -> ?EOS_BEHAVIOR_RESET;
+arg_eos_behavior(cut) -> ?EOS_BEHAVIOR_CUT;
+arg_eos_behavior(_) -> erlang:error(bad_eos_behavior).
+
-spec arg_bitsz(zwindowbits()) -> zwindowbits().
arg_bitsz(Bits) when is_integer(Bits) andalso
((8 =< Bits andalso Bits < 48) orelse
@@ -678,4 +692,4 @@ enqueue_input_1(Z, IOVec) ->
end.
enqueue_nif(_Z, _IOVec) ->
- erlang:nif_error(undef). \ No newline at end of file
+ erlang:nif_error(undef).
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 380be1b534..1c6472a0ab 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 9.1
+VSN = 9.1.1
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 9b32ec54c4..bd095c422a 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.1.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The compiler could issue an incorrect internal
+ consistency failure diagnostic for some complicated bit
+ syntax maches.</p>
+ <p>
+ Own Id: OTP-14640 Aux Id: ERL-490 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 00901077d3..be8908dd6b 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -1430,13 +1430,13 @@ merge_types(bool, {atom,A}) ->
merge_bool(A);
merge_types({atom,A}, bool) ->
merge_bool(A);
-merge_types(#ms{id=Id1,valid=B0,slots=Slots},
- #ms{id=Id2,valid=B1,slots=Slots}) ->
+merge_types(#ms{id=Id1,valid=B1,slots=Slots1},
+ #ms{id=Id2,valid=B2,slots=Slots2}) ->
Id = if
Id1 =:= Id2 -> Id1;
true -> make_ref()
end,
- #ms{id=Id,valid=B0 band B1,slots=Slots};
+ #ms{id=Id,valid=B1 band B2,slots=min(Slots1, Slots2)};
merge_types(T1, T2) when T1 =/= T2 ->
%% Too different. All we know is that the type is a 'term'.
term.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 0ec05456ec..2fe8cd0cff 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -39,7 +39,7 @@
match_string_opt/1,select_on_integer/1,
map_and_binary/1,unsafe_branch_caching/1,
bad_literals/1,good_literals/1,constant_propagation/1,
- parse_xml/1,get_payload/1]).
+ parse_xml/1,get_payload/1,num_slots_different/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -71,7 +71,7 @@ groups() ->
match_string_opt,select_on_integer,
map_and_binary,unsafe_branch_caching,
bad_literals,good_literals,constant_propagation,parse_xml,
- get_payload]}].
+ get_payload,num_slots_different]}].
init_per_suite(Config) ->
@@ -1524,6 +1524,40 @@ do_get_payload(ExtHdr) ->
<<_:13,_:35>> = ExtHdr#ext_header.ext_hdr_opts,
ExtHdrOptions.
+%% ERL-490
+num_slots_different(_Config) ->
+ Ts = [{<<"de">>, <<"default">>, <<"Remove">>, <<"a">>},
+ {<<"de">>, <<"default">>, <<"Remove from list">>, <<"a">>},
+ {<<"de">>, <<"default">>, <<"Remove from the list">>, <<"a">>},
+ {<<"de">>, <<"default">>, <<"Results">>, <<"Ergebnisse">>},
+ {<<"de">>, <<"default">>, <<"Reservatio">>, <<"a">>},
+ {<<"de">>, <<"navigation">>, <<"Results">>, <<"Ergebnisse">>},
+ {<<"de">>, <<"navigation">>, <<"Resources">>, <<"Ressourcen">>}],
+ _ = [{ok,Res} = lgettext(A, B, C) || {A,B,C,Res} <- Ts],
+
+ {'EXIT',_} = (catch lgettext(<<"d">>, <<"default">>, <<"Remove">>)),
+ {'EXIT',_} = (catch lgettext("", <<"default">>, <<"Remove">>)),
+ {'EXIT',_} = (catch lgettext(<<"de">>, <<"def">>, <<"Remove">>)),
+ {'EXIT',_} = (catch lgettext(<<"de">>, <<"default">>, <<"Res">>)),
+ ok.
+
+
+lgettext(<<"de">>, <<"default">>, <<"Remove">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"default">>, <<"Remove from list">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"default">>, <<"Remove from the list">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"default">>, <<"Results">>) ->
+ {ok, <<"Ergebnisse">>};
+lgettext(<<"de">>, <<"default">>, <<"Reservatio">>) ->
+ {ok, <<"a">>};
+lgettext(<<"de">>, <<"navigation">>, <<"Results">>) ->
+ {ok, <<"Ergebnisse">>};
+lgettext(<<"de">>, <<"navigation">>, <<"Resources">>) ->
+ {ok, <<"Ressourcen">>}.
+
+
check(F, R) ->
R = F().
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 43fe0c8f6d..435a57aac2 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.1.2
+COMPILER_VSN = 7.1.3
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index e246276262..d17eded811 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -276,10 +276,10 @@ api_inflateInit(Config) when is_list(Config) ->
?m(ok,zlib:close(Z12))
end, lists:seq(8,15)),
?m(?EXIT(badarg), zlib:inflateInit(gurka, -15)),
- ?m(?EXIT(already_initialized), zlib:inflateInit(Z1, 7)),
- ?m(?EXIT(already_initialized), zlib:inflateInit(Z1, -7)),
- ?m(?EXIT(already_initialized), zlib:inflateInit(Z1, 48)),
- ?m(?EXIT(already_initialized), zlib:inflateInit(Z1, -16)),
+ ?m(?EXIT(bad_windowbits), zlib:inflateInit(Z1, 7)),
+ ?m(?EXIT(bad_windowbits), zlib:inflateInit(Z1, -7)),
+ ?m(?EXIT(bad_windowbits), zlib:inflateInit(Z1, 48)),
+ ?m(?EXIT(bad_windowbits), zlib:inflateInit(Z1, -16)),
?m(ok, zlib:close(Z1)).
%% Test inflateSetDictionary.
@@ -416,6 +416,9 @@ api_inflateChunk(Config) when is_list(Config) ->
{more, Part1AsIOList} = zlib:inflateChunk(Z1, Compressed),
{more, Part2AsIOList} = zlib:inflateChunk(Z1),
{more, Part3AsIOList} = zlib:inflateChunk(Z1),
+
+ [] = zlib:inflateChunk(Z1),
+ [] = zlib:inflateChunk(Z1),
[] = zlib:inflateChunk(Z1),
?m(Part1, iolist_to_binary(Part1AsIOList)),
@@ -483,7 +486,8 @@ api_safeInflate(Config) when is_list(Config) ->
SafeInflateLoop(zlib:safeInflate(Z1, Compressed), []),
- ?m(?EXIT(data_error), zlib:safeInflate(Z1, Compressed)),
+ ?m({finished, []}, zlib:safeInflate(Z1, Compressed)),
+ ?m({finished, []}, zlib:safeInflate(Z1, Compressed)),
?m(ok, zlib:inflateReset(Z1)),
?m(?EXIT(badarg), zlib:safeInflate(gurka, Compressed)),
@@ -632,6 +636,7 @@ api_g_un_zip(Config) when is_list(Config) ->
?m(?EXIT(badarg),zlib:gzip(not_a_binary)),
Bin = <<1,11,1,23,45>>,
Comp = zlib:gzip(Bin),
+
?m(Comp, zlib:gzip(binary_to_list(Bin))),
?m(?EXIT(badarg), zlib:gunzip(not_a_binary)),
?m(?EXIT(data_error), zlib:gunzip(<<171,171,171,171,171>>)),
@@ -639,6 +644,14 @@ api_g_un_zip(Config) when is_list(Config) ->
?m(Bin, zlib:gunzip(Comp)),
?m(Bin, zlib:gunzip(binary_to_list(Comp))),
+ %% RFC 1952:
+ %%
+ %% "A gzip file consists of a series of "members" (compressed data
+ %% sets). [...] The members simply appear one after another in the file,
+ %% with no additional information before, between, or after them."
+ Concatenated = <<Bin/binary, Bin/binary>>,
+ ?m(Concatenated, zlib:gunzip([Comp, Comp])),
+
%% Bad CRC; bad length.
BadCrc = bad_crc_data(),
?m(?EXIT(data_error),(catch zlib:gunzip(BadCrc))),
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 4ba75b761f..ef3e94a1e1 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,34 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed broken printout</p>
+ <p>
+ Own Id: OTP-14645</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Disable aes_gcm ciphers if peer is OpenSSH 6.2 which is
+ known to have trouble with them in some cases.</p>
+ <p>
+ Own Id: OTP-14638</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 8d3ddb09a4..4158a52a27 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1357,6 +1357,7 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
report ->
Msg = lists:flatten(
io_lib:format(
+ "*** SSH: "
"Unexpected message '~p' received in state '~p'\n"
"Role: ~p\n"
"Peer: ~p\n"
@@ -1365,7 +1366,7 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
StateName,
Ssh#ssh.role,
Ssh#ssh.peer,
- ?GET_INTERNAL_OPT(address, Ssh#ssh.opts)])),
+ ?GET_INTERNAL_OPT(address, Ssh#ssh.opts, undefined)])),
error_logger:info_report(Msg),
keep_state_and_data;
@@ -1374,7 +1375,8 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
Other ->
Msg = lists:flatten(
- io_lib:format("Call to fun in 'unexpectedfun' failed:~n"
+ io_lib:format("*** SSH: "
+ "Call to fun in 'unexpectedfun' failed:~n"
"Return: ~p\n"
"Message: ~p\n"
"Role: ~p\n"
@@ -1383,8 +1385,8 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
[Other,
UnexpectedMessage,
Ssh#ssh.role,
- element(2,Ssh#ssh.peer),
- ?GET_INTERNAL_OPT(address, Ssh#ssh.opts)]
+ Ssh#ssh.peer,
+ ?GET_INTERNAL_OPT(address, Ssh#ssh.opts, undefined)]
)),
error_logger:error_report(Msg),
keep_state_and_data
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index c48c0800e4..0052347912 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -251,9 +251,9 @@ key_exchange_init_msg(Ssh0) ->
{SshPacket, Ssh} = ssh_packet(Msg, Ssh0),
{Msg, SshPacket, Ssh}.
-kex_init(#ssh{role = Role, opts = Opts, available_host_keys = HostKeyAlgs}) ->
+kex_init(#ssh{role = Role, opts = Opts, available_host_keys = HostKeyAlgs} = Ssh) ->
Random = ssh_bits:random(16),
- PrefAlgs = ?GET_OPT(preferred_algorithms, Opts),
+ PrefAlgs = adjust_algs_for_peer_version(Role, ?GET_OPT(preferred_algorithms, Opts), Ssh),
kexinit_message(Role, Random, PrefAlgs, HostKeyAlgs, Opts).
key_init(client, Ssh, Value) ->
@@ -261,7 +261,22 @@ key_init(client, Ssh, Value) ->
key_init(server, Ssh, Value) ->
Ssh#ssh{s_keyinit = Value}.
-
+adjust_algs_for_peer_version(client, PrefAlgs, #ssh{s_version=V}) ->
+ adjust_algs_for_peer_version(V, PrefAlgs);
+adjust_algs_for_peer_version(server, PrefAlgs, #ssh{c_version=V}) ->
+ adjust_algs_for_peer_version(V, PrefAlgs).
+%%
+adjust_algs_for_peer_version("SSH-2.0-OpenSSH_6.2"++_, PrefAlgs) ->
+ C0 = proplists:get_value(cipher, PrefAlgs, same([])),
+ C = [{D,L} || D <- [client2server, server2client],
+ L <- [[K || K <- proplists:get_value(D, C0, []),
+ K =/= '[email protected]']]
+ ],
+ lists:keyreplace(cipher, 1, PrefAlgs, {cipher,C});
+adjust_algs_for_peer_version(_, PrefAlgs) ->
+ PrefAlgs.
+
kexinit_message(Role, Random, Algs, HostKeyAlgs, Opts) ->
#ssh_msg_kexinit{
cookie = Random,
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index c201e70d82..5154658e8a 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.6
+SSH_VSN = 4.6.1
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/otp_versions.table b/otp_versions.table
index c70a2c44d3..6580a6e127 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,4 @@
+OTP-20.1.1 : compiler-7.1.3 erts-9.1.1 ssh-4.6.1 # asn1-5.0.3 common_test-1.15.2 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 crypto-4.1 debugger-4.2.3 dialyzer-3.2.2 diameter-2.1 edoc-0.9.1 eldap-1.2.2 erl_docgen-0.7.1 erl_interface-3.10 et-1.6.1 eunit-2.3.4 hipe-3.16.1 ic-4.4.2 inets-6.4.2 jinterface-1.8 kernel-5.4 megaco-3.18.2 mnesia-4.15.1 observer-2.5 odbc-2.12 orber-3.8.3 os_mon-2.4.3 otp_mibs-1.1.1 parsetools-2.1.5 public_key-1.5 reltool-0.7.5 runtime_tools-1.12.2 sasl-3.1 snmp-5.2.7 ssl-8.2.1 stdlib-3.4.2 syntax_tools-2.1.3 tools-2.11 wx-1.8.2 xmerl-1.3.15 :
OTP-20.1 : asn1-5.0.3 common_test-1.15.2 compiler-7.1.2 crypto-4.1 debugger-4.2.3 dialyzer-3.2.2 diameter-2.1 edoc-0.9.1 erl_docgen-0.7.1 erts-9.1 et-1.6.1 eunit-2.3.4 hipe-3.16.1 inets-6.4.2 kernel-5.4 mnesia-4.15.1 observer-2.5 os_mon-2.4.3 public_key-1.5 reltool-0.7.5 runtime_tools-1.12.2 sasl-3.1 snmp-5.2.7 ssh-4.6 ssl-8.2.1 stdlib-3.4.2 syntax_tools-2.1.3 tools-2.11 wx-1.8.2 # cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 eldap-1.2.2 erl_interface-3.10 ic-4.4.2 jinterface-1.8 megaco-3.18.2 odbc-2.12 orber-3.8.3 otp_mibs-1.1.1 parsetools-2.1.5 xmerl-1.3.15 :
OTP-20.0.5 : erts-9.0.5 inets-6.4.1 # asn1-5.0.2 common_test-1.15.1 compiler-7.1.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 crypto-4.0 debugger-4.2.2 dialyzer-3.2.1 diameter-2.0 edoc-0.9 eldap-1.2.2 erl_docgen-0.7 erl_interface-3.10 et-1.6 eunit-2.3.3 hipe-3.16 ic-4.4.2 jinterface-1.8 kernel-5.3.1 megaco-3.18.2 mnesia-4.15 observer-2.4 odbc-2.12 orber-3.8.3 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 runtime_tools-1.12.1 sasl-3.0.4 snmp-5.2.6 ssh-4.5.1 ssl-8.2 stdlib-3.4.1 syntax_tools-2.1.2 tools-2.10.1 wx-1.8.1 xmerl-1.3.15 :
OTP-20.0.4 : dialyzer-3.2.1 erts-9.0.4 # asn1-5.0.2 common_test-1.15.1 compiler-7.1.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 crypto-4.0 debugger-4.2.2 diameter-2.0 edoc-0.9 eldap-1.2.2 erl_docgen-0.7 erl_interface-3.10 et-1.6 eunit-2.3.3 hipe-3.16 ic-4.4.2 inets-6.4 jinterface-1.8 kernel-5.3.1 megaco-3.18.2 mnesia-4.15 observer-2.4 odbc-2.12 orber-3.8.3 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 runtime_tools-1.12.1 sasl-3.0.4 snmp-5.2.6 ssh-4.5.1 ssl-8.2 stdlib-3.4.1 syntax_tools-2.1.2 tools-2.10.1 wx-1.8.1 xmerl-1.3.15 :