diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl index 8827a1064701..fc4899719538 100644 --- a/lib/tools/src/cover.erl +++ b/lib/tools/src/cover.erl @@ -2364,8 +2364,17 @@ standard_move(Mod) -> end. native_move(Mod) -> - Coverage = maps:from_list(code:get_coverage(cover_id_line, Mod)), - _ = code:reset_coverage(Mod), + Coverage0 = + try + code:get_coverage(cover_id_line, Mod) + catch + error:badarg -> + log_native_move_error(Mod), + [] + end, + _ = catch code:reset_coverage(Mod), + Coverage = maps:from_list(Coverage0), + fun({#bump{}=Key,Index}) -> case Coverage of #{Index := false} -> @@ -2379,6 +2388,21 @@ native_move(Mod) -> end end. +log_native_move_error(Mod) -> + S = "Module ~tp: Failed to collect coverage information. " + "Has it been reloaded or unloaded?", + F = fun(#{node := Node}) -> + case Node of + nonode@nohost -> + {S,[Mod]}; + _ -> + {"On node ~tp: " ++ S,[Node,Mod]} + end + end, + logger:warning(#{coverage_collection_failed => Mod, + node => node()}, + #{report_cb => F}). + %% Reset counters (set counters to 0). reset_counters(Mod) -> case has_native_coverage() of diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl index 489c35d24d1a..d9e77cd65181 100644 --- a/lib/tools/test/cover_SUITE.erl +++ b/lib/tools/test/cover_SUITE.erl @@ -35,7 +35,7 @@ all() -> otp_13277, otp_13289, guard_in_lc, gh_4796, eep49, gh_8159], StartStop = [start, compile, analyse, misc, stop, - distribution, reconnect, die_and_reconnect, + distribution, distribution_export, reconnect, die_and_reconnect, dont_reconnect_after_stop, stop_node_after_disconnect, export_import, otp_5031, otp_6115, otp_8270, otp_10979_hanging_node, otp_14817, @@ -539,6 +539,30 @@ distribution(Config) when is_list(Config) -> peer:stop(P1), peer:stop(P2). +%% GH-8661. An attempt to export cover data on a remote node could +%% hang if the module had been reloaded. +distribution_export(Config) when is_list(Config) -> + ct:timetrap({seconds, 30}), + + DataDir = proplists:get_value(data_dir, Config), + + ok = file:set_cwd(DataDir), + + {ok,P1,N1} = ?CT_PEER(), + + {ok,f} = cover:compile(f), + {ok,[_]} = cover:start([N1]), + ok = cover:export("f.coverdata"), + + {ok,f} = compile:file(f, [debug_info]), + {module, f} = erpc:call(N1, code, load_file, [f]), + + ok = cover:export("f.coverdata"), + + %% Cleanup + peer:stop(P1), + ok. + %% Test that a lost node is reconnected reconnect(Config) -> DataDir = proplists:get_value(data_dir, Config),