diff options
Diffstat (limited to 'erts/emulator/test')
-rw-r--r-- | erts/emulator/test/binary_SUITE.erl | 11 | ||||
-rw-r--r-- | erts/emulator/test/bs_match_misc_SUITE.erl | 21 | ||||
-rw-r--r-- | erts/emulator/test/distribution_SUITE.erl | 38 | ||||
-rw-r--r-- | erts/emulator/test/dump_SUITE.erl | 98 | ||||
-rw-r--r-- | erts/emulator/test/efile_SUITE.erl | 52 | ||||
-rw-r--r-- | erts/emulator/test/erts_test_utils.erl | 1 | ||||
-rw-r--r-- | erts/emulator/test/fun_SUITE.erl | 4 | ||||
-rw-r--r-- | erts/emulator/test/lcnt_SUITE.erl | 3 | ||||
-rw-r--r-- | erts/emulator/test/map_SUITE.erl | 92 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 51 |
10 files changed, 312 insertions, 59 deletions
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index 1406ddc9dc..563d60cc3f 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -1703,13 +1703,16 @@ error_after_yield_bad_ext_term() -> BadAtomExt]). %% Invalid atom at the end cmp_old_impl(Config) when is_list(Config) -> - %% Compare results from new yielding implementations with - %% old non yielding implementations + %% This test was originally a comparison with the non yielding + %% implementation in R16B. Since OTP 22 we can't talk distribution with such + %% old nodes (< 19). The test case it kept but compares with previous major + %% version for semantic regression test. Cookie = atom_to_list(erlang:get_cookie()), - Rel = "r16b_latest", + Rel = (integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 1) + ++ "_latest"), case test_server:is_release_available(Rel) of false -> - {skipped, "No "++Rel++" available"}; + {skipped, "No OTP "++Rel++" available"}; true -> {ok, Node} = test_server:start_node(list_to_atom(atom_to_list(?MODULE)++"_"++Rel), peer, diff --git a/erts/emulator/test/bs_match_misc_SUITE.erl b/erts/emulator/test/bs_match_misc_SUITE.erl index 17759d78f3..cae4eb54d2 100644 --- a/erts/emulator/test/bs_match_misc_SUITE.erl +++ b/erts/emulator/test/bs_match_misc_SUITE.erl @@ -24,7 +24,7 @@ kenneth/1,encode_binary/1,native/1,happi/1, size_var/1,wiger/1,x0_context/1,huge_float_field/1, writable_binary_matched/1,otp_7198/1,unordered_bindings/1, - float_middle_endian/1]). + float_middle_endian/1,unsafe_get_binary_reuse/1]). -include_lib("common_test/include/ct.hrl"). @@ -36,7 +36,8 @@ all() -> [bound_var, bound_tail, t_float, little_float, sean, kenneth, encode_binary, native, happi, size_var, wiger, x0_context, huge_float_field, writable_binary_matched, - otp_7198, unordered_bindings, float_middle_endian]. + otp_7198, unordered_bindings, float_middle_endian, + unsafe_get_binary_reuse]. %% Test matching of bound variables. @@ -556,5 +557,21 @@ unordered_bindings(CompressedLength, HashSize, PadLength, T) -> Padding:PadLength/binary,PadLength>> = T, {Content,Mac,Padding}. +%% ERL-901: A load-time optimization assumed that match contexts had no further +%% uses when a bs_get_binary2 overwrote the match context's register, and +%% figured it would be safe to reuse the match context's memory for the +%% resulting binary. +%% +%% This is no longer safe as of OTP 22, as a match context may be reused after +%% being passed to another function. +unsafe_get_binary_reuse(Config) when is_list(Config) -> + <<_First, Rest/binary>> = <<"hello">>, + ubgr_1(Rest), + <<Second,_/bits>> = Rest, + $e = Second, + ok. + +ubgr_1(<<_CP/utf8, Rest/binary>>) -> id(Rest); +ubgr_1(_) -> false. id(I) -> I. diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index 4f70b51aa0..449821e5ad 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -744,6 +744,7 @@ link_to_dead_new_node(Config) when is_list(Config) -> {'EXIT', Pid, noproc} -> ok; Other -> + stop_node(Node), ct:fail({unexpected_message, Other}) after 5000 -> ct:fail(nothing_received) @@ -1421,7 +1422,7 @@ message_latency_large_exit(Nodename, ReasonFun) -> FlushTrace = fun F() -> receive - {trace, Pid, _, _} = M -> + {trace, Pid, _, _} -> F() after 0 -> ok @@ -1455,8 +1456,14 @@ measure_latency_large_message(Nodename, DataFun) -> Echo = spawn(N, fun F() -> receive {From, Msg} -> From ! Msg, F() end end), - %% Test 32 MB and 320 MB and test the latency difference of sent messages - Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]], + case erlang:system_info(build_type) of + debug -> + %% Test 3.2 MB and 32 MB and test the latency difference of sent messages + Payloads = [{I, <<0:(I * 32 * 1024 * 8)>>} || I <- [1,10]]; + _ -> + %% Test 32 MB and 320 MB and test the latency difference of sent messages + Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]] + end, IndexTimes = [{I, measure_latency(DataFun, Dropper, Echo, P)} || {I, P} <- Payloads], @@ -1465,6 +1472,8 @@ measure_latency_large_message(Nodename, DataFun) -> ct:pal("~p",[IndexTimes]), + stop_node(N), + case {lists:max(Times), lists:min(Times)} of {Max, Min} when Max * 0.25 > Min -> ct:fail({incorrect_latency, IndexTimes}); @@ -1487,7 +1496,7 @@ measure_latency(DataFun, Dropper, Echo, Payload) -> end) || _ <- lists:seq(1,2)], [receive - {monitor, _Sender, busy_dist_port, _Info} = M -> + {monitor, _Sender, busy_dist_port, _Info} -> ok end || _ <- lists:seq(1,10)], @@ -1733,7 +1742,7 @@ bad_dist_fragments(Config) when is_list(Config) -> start_monitor(Offender,P), Exit2Victim = spawn(Victim, fun() -> receive ok -> ok end end), - send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,ExitVictim},2, + send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,Exit2Victim},2, [{hdr, 1, [132]}]), start_monitor(Offender,P), @@ -2428,17 +2437,22 @@ stop_node(Node) -> verify_nc(Node) -> P = self(), Ref = make_ref(), - spawn(Node, - fun() -> - R = erts_test_utils:check_node_dist(fun(E) -> E end), - P ! {Ref, R} - end), + Pid = spawn(Node, + fun() -> + R = erts_test_utils:check_node_dist(fun(E) -> E end), + P ! {Ref, R} + end), + MonRef = monitor(process, Pid), receive {Ref, ok} -> + demonitor(MonRef,[flush]), ok; {Ref, Error} -> - ct:log("~s",[Error]), - ct:fail(failed_nc_refc_check) + ct:log("~p",[Error]), + ct:fail(failed_nc_refc_check); + {'DOWN', MonRef, _, _, _} = Down -> + ct:log("~p",[Down]), + ct:fail(crashed_nc_refc_check) end. freeze_node(Node, MS) -> diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl index d0237b78cc..3b860ebdf6 100644 --- a/erts/emulator/test/dump_SUITE.erl +++ b/erts/emulator/test/dump_SUITE.erl @@ -24,7 +24,7 @@ -export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]). --export([signal_abort/1]). +-export([signal_abort/1, exiting_dump/1, free_dump/1]). -export([load/0]). @@ -35,7 +35,7 @@ suite() -> {timetrap, {minutes, 2}}]. all() -> - [signal_abort]. + [signal_abort, exiting_dump, free_dump]. init_per_testcase(signal_abort, Config) -> SO = erlang:system_info(schedulers_online), @@ -48,7 +48,10 @@ init_per_testcase(signal_abort, Config) -> {skip, "the platform does not support scheduler dump"}; Dump -> Config - end. + end; +init_per_testcase(_, Config) -> + Config. + end_per_testcase(_, Config) -> Config. @@ -79,8 +82,6 @@ signal_abort(Config) -> {ok, Bin} = get_dump_when_done(Dump), - ct:log("~s",[Bin]), - {match, Matches} = re:run(Bin,"Current Process: <",[global]), ct:log("Found ~p",[Matches]), @@ -91,6 +92,85 @@ signal_abort(Config) -> ok. +load() -> + lists:seq(1,10000), + load(). + + +%% Test that crash dumping when a process is in the state EXITING works +exiting_dump(Config) when is_list(Config) -> + Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), + + {ok, Node} = start_node(Config), + + Self = self(), + + Pid = spawn_link(Node, + fun() -> + [begin + T = ets:new(hej,[]), + [ets:insert(T,{I,I}) || I <- lists:seq(1,1000)] + end || _ <- lists:seq(1,1000)], + Self ! ready, + receive ok -> ok end + end), + + true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), + + receive ready -> unlink(Pid), Pid ! ok end, + + rpc:call(Node, erlang, halt, ["dump"]), + + {ok, Bin} = get_dump_when_done(Dump), + + {match, Matches} = re:run(Bin,"^State: Exiting", [global, multiline]), + + ct:log("Found ~p",[Matches]), + + true = length(Matches) == 1, + + file:delete(Dump), + + ok. + +%% Test that crash dumping when a process is in the state FREE works +free_dump(Config) when is_list(Config) -> + Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"), + + {ok, Node} = start_node(Config), + + Self = self(), + + Pid = spawn_link(Node, + fun() -> + Self ! ready, + receive + ok -> + unlink(Self), + exit(lists:duplicate(1000,1000)) + end + end), + + true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]), + + [erlang:monitor(process, Pid) || _ <- lists:seq(1,10000)], + receive ready -> unlink(Pid), Pid ! ok end, + + rpc:call(Node, erlang, halt, ["dump"]), + + {ok, Bin} = get_dump_when_done(Dump), + + {match, Matches} = re:run(Bin,"^State: Non Existing", [global, multiline]), + + ct:log("Found ~p",[Matches]), + + true = length(Matches) == 1, + + file:delete(Dump), + + ok. + + get_dump_when_done(Dump) -> case file:read_file_info(Dump) of {ok, #file_info{ size = Sz }} -> @@ -104,15 +184,13 @@ get_dump_when_done(Dump, Sz) -> timer:sleep(1000), case file:read_file_info(Dump) of {ok, #file_info{ size = Sz }} -> - file:read_file(Dump); + {ok, Bin} = file:read_file(Dump), + ct:log("~s",[Bin]), + {ok, Bin}; {ok, #file_info{ size = NewSz }} -> get_dump_when_done(Dump, NewSz) end. -load() -> - lists:seq(1,10000), - load(). - start_node(Config) when is_list(Config) -> Pa = filename:dirname(code:which(?MODULE)), Name = list_to_atom(atom_to_list(?MODULE) diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl index 7dcf302742..045b351e02 100644 --- a/erts/emulator/test/efile_SUITE.erl +++ b/erts/emulator/test/efile_SUITE.erl @@ -45,7 +45,12 @@ iter_max_files(Config) when is_list(Config) -> iter_max_files_1(Config) -> DataDir = proplists:get_value(data_dir,Config), TestFile = filename:join(DataDir, "existing_file"), - N = 10, + case erlang:system_info(debug_compiled) of + true -> + N = 5; + false -> + N = 10 + end, %% Run on a different node in order to make the test more stable. Dir = filename:dirname(code:which(?MODULE)), {ok,Node} = test_server:start_node(test_iter_max_files,slave, @@ -100,34 +105,27 @@ open_files(Name) -> %% a /proc directory), let's read some zero sized files 500 times each, while %% ensuring that response isn't empty << >> proc_zero_sized_files(Config) when is_list(Config) -> - {Type, Flavor} = os:type(), - %% Some files which exist on Linux but might be missing on other systems - Inputs = ["/proc/cpuinfo", - "/proc/meminfo", - "/proc/partitions", - "/proc/swaps", - "/proc/version", - "/proc/uptime", - %% curproc is present on freebsd - "/proc/curproc/cmdline"], - case filelib:is_dir("/proc") of - false -> {skip, "/proc not found"}; % skip the test if no /proc - _ when Type =:= unix andalso Flavor =:= sunos -> - %% SunOS has a /proc, but no zero sized special files - {skip, "sunos does not have any zero sized special files"}; - true -> - %% Take away files which do not exist in proc - Inputs1 = lists:filter(fun filelib:is_file/1, Inputs), - - %% Fail if none of mentioned files exist in /proc, did we just get - %% a normal /proc directory without any special files? - ?assertNotEqual([], Inputs1), - + TestFiles0 = [%% Some files which exist on Linux but might be missing on + %% other systems + "/proc/cpuinfo", + "/proc/meminfo", + "/proc/partitions", + "/proc/swaps", + "/proc/version", + "/proc/uptime", + %% curproc is present on FreeBSD + "/proc/curproc/cmdline"], + + TestFiles = [F || F <- TestFiles0, filelib:is_file(F)], + + case TestFiles of + [_|_] -> %% For 6 inputs and 500 attempts each this do run anywhere %% between 500 and 3000 function calls. - lists:foreach( - fun(Filename) -> do_proc_zero_sized(Filename, 500) end, - Inputs1) + [do_proc_zero_sized(F, 500) || F <- TestFiles], + ok; + [] -> + {skip, "Failed to find any known zero-sized files"} end. %% @doc Test one file N times to also trigger possible leaking fds and memory diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl index 0c3ef3e0fc..e4e00a0a16 100644 --- a/erts/emulator/test/erts_test_utils.erl +++ b/erts/emulator/test/erts_test_utils.erl @@ -19,6 +19,7 @@ %% -module(erts_test_utils). +-compile(r16). %% %% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl index 4042b58ff2..7f6caa08f1 100644 --- a/erts/emulator/test/fun_SUITE.erl +++ b/erts/emulator/test/fun_SUITE.erl @@ -592,7 +592,8 @@ refc_dist(Config) when is_list(Config) -> 3 = fun_refc(F2), true = erlang:garbage_collect(), 2 = fun_refc(F), - refc_dist_send(Node, F). + refc_dist_send(Node, F), + test_server:stop_node(Node). refc_dist_send(Node, F) -> Pid = spawn_link(Node, fun() -> receive @@ -682,6 +683,7 @@ t_arity(Config) when is_list(Config) -> 43 = spawn_call(Node, fun(X, Y) -> A+X+Y end), 1 = spawn_call(Node, fun(X, Y) -> X+Y end), 45 = spawn_call(Node, fun(X, Y, Z) -> A+X+Y+Z end), + test_server:stop_node(Node), ok. t_is_function2(Config) when is_list(Config) -> diff --git a/erts/emulator/test/lcnt_SUITE.erl b/erts/emulator/test/lcnt_SUITE.erl index 87b97037d6..2dbaec9942 100644 --- a/erts/emulator/test/lcnt_SUITE.erl +++ b/erts/emulator/test/lcnt_SUITE.erl @@ -187,5 +187,8 @@ remove_untoggleable_locks([]) -> []; remove_untoggleable_locks([{resource_monitors, _, _, _} | T]) -> remove_untoggleable_locks(T); +remove_untoggleable_locks([{'socket[gcnt]', _, _, _} | T]) -> + %% Global lock used by socket NIF + remove_untoggleable_locks(T); remove_untoggleable_locks([H | T]) -> [H | remove_untoggleable_locks(T)]. 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 edf08ce0bd..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, @@ -133,6 +135,15 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +init_per_testcase(Func, Config) + when Func =:= processes_default_tab; + Func =:= processes_this_tab -> + case erlang:system_info(debug_compiled) of + true -> + {skip, "Don't run in debug"}; + false -> + [{testcase, Func} | Config] + end; init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> [{testcase, Func}|Config]. @@ -1084,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(), |