File 0516-erts-Fix-ets-rename-during-ets-delete_all_objects.patch of Package erlang

From 423690db5488fb1c08ea29c2017109edcab76266 Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Tue, 11 Oct 2022 20:27:58 +0200
Subject: [PATCH 2/2] erts: Fix ets:rename during ets:delete_all_objects

Concurrent ets:rename could cause ets:delete_all_objects
to fail halfway through with badarg

"the table identifier does not refer to an existing ETS table"
---
 erts/emulator/beam/erl_db.c      | 10 ++++++-
 erts/emulator/beam/erl_db_util.h |  2 +-
 lib/stdlib/test/ets_SUITE.erl    | 48 +++++++++++++++++++++-----------
 3 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 05b21c53e2..db4eb95034 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -2832,15 +2832,23 @@ BIF_RETTYPE ets_internal_delete_all_2(BIF_ALIST_2)
              * the table and instead pitch in deleting objects
              * (in delete_all_objects_continue) and then trap to self.
              */
+            Eterm tid;
             ASSERT((tb->common.status & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC))
                    ==
                    (tb->common.type & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC)));
             tb->common.status &= ~(DB_PRIVATE|DB_PROTECTED|DB_PUBLIC);
             tb->common.status |= DB_BUSY;
             db_unlock(tb, LCK_WRITE);
+
+            if (is_atom(BIF_ARG_1)) {
+                ASSERT(is_table_named(tb));
+                tid = make_tid(BIF_P, tb);
+            } else {
+                tid = BIF_ARG_1;
+            }
             BUMP_ALL_REDS(BIF_P);
             BIF_TRAP2(BIF_TRAP_EXPORT(BIF_ets_internal_delete_all_2), BIF_P,
-                      BIF_ARG_1, nitems_holder);
+                      tid, nitems_holder);
         }
         else {
             /* Done, no trapping needed */
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 6ed1e15104..a57febffdb 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -302,7 +302,7 @@ typedef struct db_table_common {
     UWord heir_data;          /* To send in ETS-TRANSFER (is_immed or (DbTerm*) */
     Uint64 heir_started_interval;  /* To further identify the heir */
     Eterm the_name;           /* an atom */
-    Binary *btid;
+    Binary *btid;             /* table magic ref, read only after creation */
     DbTableMethod* meth;      /* table methods */
     /* The ErtsFlxCtr below contains:
      * - Total number of items in table
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index a1542247c3..615511471a 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -42,7 +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_delete_all_objects_trap/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,
@@ -150,7 +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_delete_all_objects_trap,
      t_test_ms, t_select_delete, t_select_replace,
      t_select_replace_next_bug,
      t_select_pam_stack_overflow_bug,
@@ -1041,30 +1041,43 @@ inserter(T, Next, Papa) ->
     end.
 
 
-%% Test unfix during delete_all_objects
-t_delete_all_objects_trap_unfix(Config) when is_list(Config) ->
+%% Poke table during delete_all_objects
+t_delete_all_objects_trap(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)
+              delete_all_objects_trap(Opts, unfix),
+              delete_all_objects_trap(Opts, exit),
+              delete_all_objects_trap(Opts, rename)
       end),
     verify_etsmem(EtsMem),
     ok.
 
-delete_all_objects_trap_unfix(Opts, Mode) ->
+delete_all_objects_trap(Opts, Mode) ->
     io:format("Opts = ~p\nMode = ~p\n", [Opts, Mode]),
     Tester = self(),
     KeyRange = 50_000,
-    T=ets_new(x, Opts, KeyRange),
+    TableName = delete_all_objects_trap,
+    {Tref,T} =
+        case Mode of
+            rename ->
+                TableName = ets_new(TableName, [named_table,public|Opts], KeyRange),
+                {ets:whereis(TableName), TableName};
+            _ ->
+                Tid = ets_new(x, Opts, KeyRange),
+                {Tid,Tid}
+        end,
     filltabint(T, KeyRange),
     KeyRange = ets:info(T,size),
     FixerFun =
         fun() ->
                 erlang:trace(Tester, true, [running]),
-                ets:safe_fixtable(T, true),
+                case Mode of
+                    rename -> ok;
+                    _ -> ets:safe_fixtable(T, true)
+                end,
                 io:format("Wait for ets:delete_all_objects/1 to yield...\n", []),
-                Tester ! {safe_fixtable, self()},
+                Tester ! {ready, self()},
                 repeat_while(
                   fun() ->
                           case receive_any() of
@@ -1083,18 +1096,21 @@ delete_all_objects_trap_unfix(Opts, Mode) ->
                         ets:safe_fixtable(T, false);
                     exit ->
                         %%io:format("Exit and do auto-unfix...\n",[]),
-                        exit
+                        exit;
+                    rename ->
+                        %%io:format("Rename table...\n",[]),
+                        renamed = ets:rename(T, renamed)
                 end
         end,
     {Fixer, Mon} = spawn_opt(FixerFun, [link, monitor]),
-    {safe_fixtable, Fixer} = receive_any(),
+    {ready, Fixer} = receive_any(),
     true = ets:delete_all_objects(T),
     Fixer ! "delete_all_objects done",
-    0 = ets:info(T,size),
+    0 = ets:info(Tref,size),
     {'DOWN', Mon, process, Fixer, normal} = receive_any(),
-    0 = get_kept_objects(T),
-    false = ets:info(T,safe_fixed),
-    ets:delete(T),
+    0 = get_kept_objects(Tref),
+    false = ets:info(Tref,safe_fixed),
+    ets:delete(Tref),
     ok.
 
 
-- 
2.35.3

openSUSE Build Service is sponsored by