File 0515-erts-Fix-bug-in-ets-delete_all_objects.patch of Package erlang
From c9f7575e9f92ccd49a73e5f39eba3e847227eb83 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Tue, 11 Oct 2022 18:42:53 +0200
Subject: [PATCH 1/2] erts: Fix bug in ets:delete_all_objects
This bug does not seem to cause any problem in practice
other than the debug ASSERT(fixdel->all) in the same function.
---
erts/emulator/beam/erl_db_hash.c | 2 +-
erts/emulator/beam/erl_db_hash.h | 5 ++-
lib/stdlib/test/ets_SUITE.erl | 61 +++++++++++++++++++++++++++++++-
3 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 6eb7bde1b4..716b3a0485 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -2728,7 +2728,7 @@ static SWord db_mark_all_deleted_hash(DbTable *tbl, SWord reds)
if (i < NACTIVE(tb)) {
/* Yield */
fixdel->slot = i;
- fixdel->all = 0;
+ fixdel->all = 1;
fixdel->trap = 1;
return -1;
}
diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h
index 830dc77114..cba7163479 100644
--- a/erts/emulator/beam/erl_db_hash.h
+++ b/erts/emulator/beam/erl_db_hash.h
@@ -25,8 +25,11 @@
typedef struct fixed_deletion {
UWord slot : sizeof(UWord)*8 - 2;
- UWord all : 1;
+
+ /* Used by delete_all_objects: */
+ UWord all : 1; /* marks [0 -> slot] */
UWord trap : 1;
+
struct fixed_deletion *next;
} FixedDeletion;
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 588096301d..a1542247c3 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -42,6 +42,7 @@
-export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]).
-export([t_delete_object/1, t_init_table/1, t_whitebox/1,
select_bound_chunk/1, t_delete_all_objects/1, t_test_ms/1,
+ t_delete_all_objects_trap_unfix/1,
t_select_delete/1,t_select_replace/1,t_select_replace_next_bug/1,
t_select_pam_stack_overflow_bug/1,
t_select_flatmap_term_copy_bug/1,
@@ -149,6 +150,7 @@ all() ->
match_heavy, {group, fold}, member, t_delete_object,
select_bound_chunk,
t_init_table, t_whitebox, t_delete_all_objects,
+ t_delete_all_objects_trap_unfix,
t_test_ms, t_select_delete, t_select_replace,
t_select_replace_next_bug,
t_select_pam_stack_overflow_bug,
@@ -960,7 +962,7 @@ get_kept_objects(T) ->
end.
t_delete_all_objects_do(Opts) ->
- KeyRange = 4000,
+ KeyRange = 40_000,
T=ets_new(x, Opts, KeyRange),
filltabint(T,KeyRange),
O=ets:first(T),
@@ -1039,6 +1041,63 @@ inserter(T, Next, Papa) ->
end.
+%% Test unfix during delete_all_objects
+t_delete_all_objects_trap_unfix(Config) when is_list(Config) ->
+ EtsMem = etsmem(),
+ repeat_for_opts_all_set_table_types(
+ fun(Opts) ->
+ delete_all_objects_trap_unfix(Opts, unfix),
+ delete_all_objects_trap_unfix(Opts, exit)
+ end),
+ verify_etsmem(EtsMem),
+ ok.
+
+delete_all_objects_trap_unfix(Opts, Mode) ->
+ io:format("Opts = ~p\nMode = ~p\n", [Opts, Mode]),
+ Tester = self(),
+ KeyRange = 50_000,
+ T=ets_new(x, Opts, KeyRange),
+ filltabint(T, KeyRange),
+ KeyRange = ets:info(T,size),
+ FixerFun =
+ fun() ->
+ erlang:trace(Tester, true, [running]),
+ ets:safe_fixtable(T, true),
+ io:format("Wait for ets:delete_all_objects/1 to yield...\n", []),
+ Tester ! {safe_fixtable, self()},
+ repeat_while(
+ fun() ->
+ case receive_any() of
+ {trace, Tester, out, {ets,internal_delete_all,2}} ->
+ false;
+ "delete_all_objects done" ->
+ ct:fail("No trap detected");
+ M ->
+ %%io:format("Ignored msg: ~p\n", [M]),
+ true
+ end
+ end),
+ case Mode of
+ unfix ->
+ io:format("Unfix table and then exit...\n",[]),
+ ets:safe_fixtable(T, false);
+ exit ->
+ %%io:format("Exit and do auto-unfix...\n",[]),
+ exit
+ end
+ end,
+ {Fixer, Mon} = spawn_opt(FixerFun, [link, monitor]),
+ {safe_fixtable, Fixer} = receive_any(),
+ true = ets:delete_all_objects(T),
+ Fixer ! "delete_all_objects done",
+ 0 = ets:info(T,size),
+ {'DOWN', Mon, process, Fixer, normal} = receive_any(),
+ 0 = get_kept_objects(T),
+ false = ets:info(T,safe_fixed),
+ ets:delete(T),
+ ok.
+
+
%% Test ets:delete_object/2.
t_delete_object(Config) when is_list(Config) ->
EtsMem = etsmem(),
--
2.35.3