aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/tty.xml4
-rw-r--r--erts/emulator/beam/beam_emu.c15
-rw-r--r--erts/emulator/beam/erl_utils.h1
-rw-r--r--erts/emulator/beam/msg_instrs.tab1
-rw-r--r--erts/emulator/beam/utils.c8
-rw-r--r--erts/emulator/test/map_SUITE.erl92
-rw-r--r--erts/emulator/test/process_SUITE.erl42
-rw-r--r--lib/kernel/src/raw_file_io_inflate.erl2
-rw-r--r--lib/ssl/src/tls_connection.erl4
-rw-r--r--lib/stdlib/src/erl_tar.erl4
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl12
11 files changed, 160 insertions, 25 deletions
diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml
index 51db1ba8e2..c33e082f4f 100644
--- a/erts/doc/src/tty.xml
+++ b/erts/doc/src/tty.xml
@@ -165,6 +165,10 @@ erl</pre>
<cell align="left" valign="middle">C-y</cell>
<cell align="left" valign="middle">Insert previously killed text</cell>
</row>
+ <row>
+ <cell align="left" valign="middle">C-]</cell>
+ <cell align="left" valign="middle">Insert matching closing bracket</cell>
+ </row>
<tcaption>tty Text Editing</tcaption>
</table>
</section>
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index f1d8609066..ea01ce597d 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3267,20 +3267,23 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity)
/*
- * Return the current number of reductions for the given process.
+ * Return the current number of reductions consumed by the given process.
* To get the total number of reductions, p->reds must be added.
*/
Uint
-erts_current_reductions(Process *current, Process *p)
+erts_current_reductions(Process *c_p, Process *p)
{
- if (current != p) {
+ Sint reds_left;
+ if (c_p != p || !(erts_atomic32_read_nob(&c_p->state)
+ & ERTS_PSFLG_RUNNING)) {
return 0;
- } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) {
- return current->fcalls + CONTEXT_REDS;
+ } else if (c_p->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
+ reds_left = c_p->fcalls + CONTEXT_REDS;
} else {
- return REDS_IN(current) - current->fcalls;
+ reds_left = c_p->fcalls;
}
+ return REDS_IN(c_p) - reds_left;
}
int
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index 880febba8b..430ac305c5 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -69,7 +69,6 @@ int erts_fit_in_bits_int32(Sint32);
int erts_fit_in_bits_uint(Uint);
Sint erts_list_length(Eterm);
int erts_is_builtin(Eterm, Eterm, int);
-Uint32 block_hash(byte *, unsigned, Uint32);
Uint32 make_hash2(Eterm);
Uint32 make_hash(Eterm);
Uint32 make_internal_hash(Eterm, Uint32 salt);
diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab
index 6f8d1469ef..b08466c830 100644
--- a/erts/emulator/beam/msg_instrs.tab
+++ b/erts/emulator/beam/msg_instrs.tab
@@ -105,6 +105,7 @@ i_loop_rec(Dest) {
$SET_CP_I_ABS(I);
c_p->arity = 0;
c_p->current = NULL;
+ c_p->fcalls = FCALLS;
FCALLS -= erts_proc_sig_receive_helper(c_p, FCALLS, neg_o_reds,
&msgp, &get_out);
SWAPIN;
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 36cfe0548e..0bbae65e28 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1069,11 +1069,11 @@ do { \
#define HCONST 0x9e3779b9UL /* the golden ratio; an arbitrary value */
-Uint32
-block_hash(byte *k, unsigned length, Uint32 initval)
+static Uint32
+block_hash(byte *k, Uint length, Uint32 initval)
{
Uint32 a,b,c;
- unsigned len;
+ Uint len;
/* Set up the internal state */
len = length;
@@ -1749,7 +1749,7 @@ make_internal_hash(Eterm term, Uint32 salt)
case SUB_BINARY_SUBTAG:
{
byte* bptr;
- unsigned sz = binary_size(term);
+ Uint sz = binary_size(term);
Uint32 con = HCONST_13 + hash;
Uint bitoffs;
Uint bitsize;
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index d0a6763fe5..9ea59e1084 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -17,7 +17,7 @@
%% %CopyrightEnd%
%%
-module(map_SUITE).
--export([all/0, suite/0]).
+-export([all/0, suite/0, init_per_suite/1, end_per_suite/1]).
-export([t_build_and_match_literals/1, t_build_and_match_literals_large/1,
t_update_literals/1, t_update_literals_large/1,
@@ -84,7 +84,10 @@
%% instruction-level tests
t_has_map_fields/1,
y_regs/1,
- badmap_17/1]).
+ badmap_17/1,
+
+ %%Bugs
+ t_large_unequal_bins_same_hash_bug/1]).
-include_lib("stdlib/include/ms_transform.hrl").
@@ -149,7 +152,26 @@ all() -> [t_build_and_match_literals, t_build_and_match_literals_large,
%% instruction-level tests
t_has_map_fields,
y_regs,
- badmap_17].
+ badmap_17,
+
+ %% Bugs
+ t_large_unequal_bins_same_hash_bug].
+
+init_per_suite(Config) ->
+ A0 = case application:start(sasl) of
+ ok -> [sasl];
+ _ -> []
+ end,
+ A = case application:start(os_mon) of
+ ok -> [os_mon|A0];
+ _ -> A0
+ end,
+ [{started_apps, A}|Config].
+
+end_per_suite(Config) ->
+ As = proplists:get_value(started_apps, Config),
+ lists:foreach(fun (A) -> application:stop(A) end, As),
+ Config.
%% tests
@@ -3374,3 +3396,67 @@ fannerl() ->
104,2,97,9,97,16,70,63,184,100,97,32,0,0,0,104,2,97,10,97,16,70,63,169,174,
254,64,0,0,0,104,2,97,11,97,16,70,191,119,121,234,0,0,0,0,104,2,97,12,97,
16,70,63,149,12,170,128,0,0,0,104,2,97,13,97,16,70,191,144,193,191,0,0,0,0>>.
+
+%% This test case checks that the bug with ticket number OTP-15707 is
+%% fixed. The bug could cause a crash or memory usage to grow until
+%% the machine ran out of memory.
+t_large_unequal_bins_same_hash_bug(Config) when is_list(Config) ->
+ run_when_enough_resources(
+ fun() ->
+ K1 = get_4GB_bin(1),
+ K2 = get_4GB_bin(2),
+ Map = make_map(500),
+ Map2 = maps:put(K1, 42, Map),
+ %% The map needed to contain at least 32 key-value pairs
+ %% at this point to get the crash or out of memory
+ %% problem on the next line
+ Map3 = maps:put(K2, 43, Map2),
+ %% The following line should avoid that the compiler
+ %% optimizes away the above
+ io:format("~p ~p~n", [erlang:phash2(Map3), maps:size(Map3)])
+ end).
+
+make_map(0) ->
+ #{};
+make_map(Size) ->
+ maps:put(Size, Size, make_map(Size-1)).
+
+get_4GB_bin(Value) ->
+ List = lists:duplicate(65536, Value),
+ Bin = erlang:iolist_to_binary(List),
+ IOList4GB = duplicate_iolist(Bin, 16),
+ Bin4GB = erlang:iolist_to_binary(IOList4GB),
+ 4294967296 = size(Bin4GB),
+ Bin4GB.
+
+duplicate_iolist(IOList, 0) ->
+ IOList;
+duplicate_iolist(IOList, NrOfTimes) ->
+ duplicate_iolist([IOList, IOList], NrOfTimes - 1).
+
+run_when_enough_resources(Fun) ->
+ case {total_memory(), erlang:system_info(wordsize)} of
+ {Mem, 8} when is_integer(Mem) andalso Mem >= 31 ->
+ Fun();
+ {Mem, WordSize} ->
+ {skipped,
+ io_lib:format("Not enough resources (System Memory >= ~p, Word Size = ~p)",
+ [Mem, WordSize])}
+ end.
+
+total_memory() ->
+ %% Total memory in GB.
+ try
+ MemoryData = memsup:get_system_memory_data(),
+ case lists:keysearch(total_memory, 1, MemoryData) of
+ {value, {total_memory, TM}} ->
+ TM div (1024*1024*1024);
+ false ->
+ {value, {system_total_memory, STM}} =
+ lists:keysearch(system_total_memory, 1, MemoryData),
+ STM div (1024*1024*1024)
+ end
+ catch
+ _ : _ ->
+ undefined
+ end.
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index c698220013..b530ced566 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -44,6 +44,7 @@
process_info_garbage_collection/1,
process_info_smoke_all/1,
process_info_status_handled_signal/1,
+ process_info_reductions/1,
bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1,
otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1,
process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1,
@@ -84,6 +85,7 @@ all() ->
process_info_garbage_collection,
process_info_smoke_all,
process_info_status_handled_signal,
+ process_info_reductions,
bump_reductions, low_prio, yield, yield2, otp_4725,
bad_register, garbage_collect, process_info_messages,
process_flag_badarg, process_flag_heap_size,
@@ -1093,6 +1095,46 @@ process_info_status_handled_signal(Config) when is_list(Config) ->
false = erlang:is_process_alive(P),
ok.
+%% OTP-15709
+%% Provoke a bug where process_info(reductions) returned wrong result
+%% because REDS_IN (def_arg_reg[5]) is read when the process in not running.
+process_info_reductions(Config) when is_list(Config) ->
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)),
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)),
+ ok.
+
+pi_reductions_tester(Pid) ->
+ {_, DiffList} =
+ lists:foldl(fun(_, {Prev, Acc}) ->
+ %% Add another item that force sending the request
+ %% as a signal, like 'current_function'.
+ PI = process_info(Pid, [reductions, current_function]),
+ [{reductions,Reds}, {current_function,_}] = PI,
+ Diff = Reds - Prev,
+ {Diff, true} = {Diff, (Diff >= 0)},
+ {Diff, true} = {Diff, (Diff =< 1000*1000)},
+ {Reds, [Diff | Acc]}
+ end,
+ {0, []},
+ lists:seq(1,10)),
+ unlink(Pid),
+ exit(Pid,kill),
+ io:format("Reduction diffs: ~p\n", [DiffList]),
+ ok.
+
+pi_reductions_spinnloop() ->
+ %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN
+ pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14).
+
+pi_reductions_spinnloop(A,B,C,D,E,F) ->
+ pi_reductions_spinnloop(B,C,D,E,F,A).
+
+pi_reductions_recvloop() ->
+ receive
+ "a free lunch" -> false
+ end.
+
+
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
erlang:garbage_collect(),
diff --git a/lib/kernel/src/raw_file_io_inflate.erl b/lib/kernel/src/raw_file_io_inflate.erl
index 7e9780310c..d3ed02dd03 100644
--- a/lib/kernel/src/raw_file_io_inflate.erl
+++ b/lib/kernel/src/raw_file_io_inflate.erl
@@ -26,7 +26,7 @@
-include("file_int.hrl").
--define(INFLATE_CHUNK_SIZE, (1 bsl 10)).
+-define(INFLATE_CHUNK_SIZE, (8 bsl 10)).
-define(GZIP_WBITS, (16 + 15)).
callback_mode() -> state_functions.
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index fde73cdef1..a05858221a 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -934,7 +934,7 @@ wait_sh(Type, Event, State) ->
callback_mode() ->
state_functions.
-terminate({shutdown, sender_died, Reason}, _StateName,
+terminate({shutdown, {sender_died, Reason}}, _StateName,
#state{static_env = #static_env{socket = Socket,
transport_cb = Transport}}
= State) ->
@@ -1119,7 +1119,7 @@ handle_info({CloseTag, Socket}, StateName,
end;
handle_info({'EXIT', Sender, Reason}, _,
#state{protocol_specific = #{sender := Sender}} = State) ->
- {stop, {shutdown, sender_died, Reason}, State};
+ {stop, {shutdown, {sender_died, Reason}}, State};
handle_info(Msg, StateName, State) ->
ssl_connection:StateName(info, Msg, State, ?MODULE).
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index d8b8f466b1..7064fcacfa 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -324,7 +324,7 @@ do_open(Name, Mode) when is_list(Mode) ->
open1({binary,Bin}, read, _Raw, Opts) when is_binary(Bin) ->
case file:open(Bin, [ram,binary,read]) of
{ok,File} ->
- _ = [ram_file:uncompress(File) || Opts =:= [compressed]],
+ _ = [ram_file:uncompress(File) || lists:member(compressed, Opts)],
{ok, #reader{handle=File,access=read,func=fun file_op/2}};
Error ->
Error
@@ -357,7 +357,7 @@ open_mode([read|Rest], false, Raw, Opts) ->
open_mode([write|Rest], false, Raw, Opts) ->
open_mode(Rest, write, Raw, Opts);
open_mode([compressed|Rest], Access, Raw, Opts) ->
- open_mode(Rest, Access, Raw, [compressed|Opts]);
+ open_mode(Rest, Access, Raw, [compressed,read_ahead|Opts]);
open_mode([cooked|Rest], Access, _Raw, Opts) ->
open_mode(Rest, Access, [], Opts);
open_mode([], Access, Raw, Opts) ->
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index 6b42f7a0a1..e1dd1bd73b 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -74,7 +74,7 @@ smoke_test_file(File) ->
[print_error_markers(F, File) || F <- Forms],
ok;
{error,Reason} ->
- io:format("~s: ~p\n", [File,Reason]),
+ io:format("~ts: ~p\n", [File,Reason]),
error
end.
@@ -82,7 +82,7 @@ print_error_markers(F, File) ->
case erl_syntax:type(F) of
error_marker ->
{L,M,Info} = erl_syntax:error_marker_info(F),
- io:format("~ts:~p: ~s", [File,L,M:format_error(Info)]);
+ io:format("~ts:~p: ~ts", [File,L,M:format_error(Info)]);
_ ->
ok
end.
@@ -362,7 +362,7 @@ test_comment_scan([File|Files],DataDir) ->
end,
Fs1 = erl_recomment:recomment_forms(Fs0, Comments),
Fs2 = erl_syntax_lib:map(Fun, Fs1),
- io:format("File: ~s~n", [Filename]),
+ io:format("File: ~ts~n", [Filename]),
io:put_chars(erl_prettypr:format(Fs2, [{paper, 120},
{ribbon, 110}])),
test_comment_scan(Files,DataDir).
@@ -377,8 +377,8 @@ test_prettypr([File|Files],DataDir,PrivDir) ->
PP = erl_prettypr:format(Fs, [{paper, 120}, {ribbon, 110}]),
io:put_chars(PP),
OutFile = filename:join(PrivDir, File),
- ok = file:write_file(OutFile,iolist_to_binary(PP)),
- io:format("Parsing OutFile: ~s~n", [OutFile]),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
+ io:format("Parsing OutFile: ~ts~n", [OutFile]),
{ok, Fs2} = epp:parse_file(OutFile, [], []),
case [Error || {error, _} = Error <- Fs2] of
[] ->
@@ -445,7 +445,7 @@ pretty_print_parse_forms([{Fs0,Type}|FsForms],PrivDir,Filename) ->
{Fs2,{CC,CT}} = erl_syntax_lib:mapfold(Comment,{0,0}, Fs1),
io:format("Commented on ~w cases and ~w tries~n", [CC,CT]),
PP = erl_prettypr:format(Fs2),
- ok = file:write_file(OutFile,iolist_to_binary(PP)),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
pretty_print_parse_forms(FsForms,PrivDir,Filename).