Commit 586a96a853bced025fda73f62c3bb5e8cd83526c

Thomas de Grivel 2024-06-27T14:56:25

make test_ic3_asan: fix memory leaks in defmodule test

diff --git a/libc3/env.c b/libc3/env.c
index 80982a5..e07c93c 100644
--- a/libc3/env.c
+++ b/libc3/env.c
@@ -34,6 +34,7 @@
 #include "error_handler.h"
 #include "facts.h"
 #include "facts_cursor.h"
+#include "facts_transaction.h"
 #include "facts_with.h"
 #include "facts_with_cursor.h"
 #include "file.h"
@@ -1070,8 +1071,11 @@ bool env_eval_ident (s_env *env, const s_ident *ident, s_tag *dest)
   s_ident tmp_ident;
   assert(env);
   assert(ident);
-  if (! (tag = env_frames_get(env, ident->sym)) &&
-      env_ident_resolve_module(env, ident, &tmp_ident) &&
+  if ((tag = env_frames_get(env, ident->sym))) {
+    tag_init_copy(dest, tag);
+    return true;
+  }
+  if (env_ident_resolve_module(env, ident, &tmp_ident) &&
       ! (tag = env_ident_get(env, &tmp_ident, &tmp))) {
     err_write_1("env_eval_ident: unbound ident: ");
     err_inspect_ident(ident);
@@ -1079,7 +1083,7 @@ bool env_eval_ident (s_env *env, const s_ident *ident, s_tag *dest)
     assert(! "env_eval_ident: unbound ident");
     return false;
   }
-  tag_init_copy(dest, tag);
+  *dest = *tag;
   return true;
 }
 
@@ -2164,8 +2168,10 @@ bool env_module_load (s_env *env, const s_sym *module)
     goto rollback;
   tag_clean(&tag_time);
   env_module_is_loading_set(env, module, false);
+  facts_transaction_end(&env->facts, &transaction);
   return true;
  rollback:
+  str_clean(&path);
   if (! facts_transaction_rollback(&env->facts, &transaction)) {
     abort();
     return false;
diff --git a/libc3/facts.c b/libc3/facts.c
index a0962ec..9e61ad4 100644
--- a/libc3/facts.c
+++ b/libc3/facts.c
@@ -286,21 +286,22 @@ s_facts * facts_init (s_facts *facts)
 {
   const u8 max_height = 10;
   const double spacing = 2.7;
+  s_facts tmp = {0};
   assert(facts);
-  set_init__tag(&facts->tags, 1024);
-  set_init__fact(&facts->facts, 1024);
-  facts->index_spo = skiplist_new__fact(max_height, spacing);
-  assert(facts->index_spo);
-  facts->index_spo->compare = compare_fact;
-  facts->index_pos = skiplist_new__fact(max_height, spacing);
-  assert(facts->index_pos);
-  facts->index_pos->compare = compare_fact_pos;
-  facts->index_osp = skiplist_new__fact(max_height, spacing);
-  assert(facts->index_osp);
-  facts->index_osp->compare = compare_fact_osp;
-  facts->log = NULL;
+  set_init__tag(&tmp.tags, 1024);
+  set_init__fact(&tmp.facts, 1024);
+  tmp.index_spo = skiplist_new__fact(max_height, spacing);
+  assert(tmp.index_spo);
+  tmp.index_spo->compare = compare_fact;
+  tmp.index_pos = skiplist_new__fact(max_height, spacing);
+  assert(tmp.index_pos);
+  tmp.index_pos->compare = compare_fact_pos;
+  tmp.index_osp = skiplist_new__fact(max_height, spacing);
+  assert(tmp.index_osp);
+  tmp.index_osp->compare = compare_fact_osp;
   facts_lock_init(facts);
-  facts->next_id = 1;
+  tmp.next_id = 1;
+  *facts = tmp;
   return facts;
 }
 
@@ -812,7 +813,7 @@ const s_fact * facts_replace_tags (s_facts *facts, const s_tag *subject,
   }
   facts_cursor_clean(&cursor);
   fact = facts_add_tags(facts, subject, predicate, object);
-  facts_transaction_clean(&transaction);
+  facts_transaction_end(facts, &transaction);
   facts_lock_unlock_w(facts);
   return fact;
 }
diff --git a/libc3/facts_transaction.c b/libc3/facts_transaction.c
index 7e663a0..70adcef 100644
--- a/libc3/facts_transaction.c
+++ b/libc3/facts_transaction.c
@@ -12,10 +12,12 @@
  */
 #include <stdlib.h>
 #include "assert.h"
+#include "fact.h"
 #include "fact_action.h"
 #include "facts.h"
 #include "facts_transaction.h"
 #include "list.h"
+#include "types.h"
 
 s_facts_transaction * facts_transaction_clean
 (s_facts_transaction *transaction)
@@ -25,43 +27,89 @@ s_facts_transaction * facts_transaction_clean
   return transaction->next;
 }
 
-s_facts * facts_transaction_rollback
-(s_facts *facts, const s_facts_transaction *transaction)
+void facts_transaction_end (s_facts *facts,
+			    s_facts_transaction *transaction)
+{
+  assert(facts);
+  assert(transaction);
+  if (facts->transaction != transaction) {
+    err_puts("facts_transaction_end: transaction mismatch");
+    assert(! "facts_transaction_end: transaction mismatch");
+    abort();
+  }
+  facts->transaction = facts_transaction_clean(transaction);
+}
+
+bool facts_transaction_find (s_facts *facts,
+			     const s_facts_transaction *transaction)
 {
-  bool b;
-  s_fact_action *log;
   const s_facts_transaction *t;
   t = facts->transaction;
   while (t) {
     if (t == transaction)
-      goto rollback;
+      return true;
     t = t->next;
   }
-  err_puts("facts_transaction_rollback: transaction not found");
-  assert(! "facts_transaction_rollback: transaction not found");
-  return NULL;
- rollback:
+  err_puts("facts_transaction_find: transaction not found");
+  assert(! "facts_transaction_find: transaction not found");
+  return false;
+}
+
+s_facts_transaction * facts_transaction_init
+(s_facts_transaction *transaction)
+{
+  s_facts_transaction tmp = {0};
+  *transaction = tmp;
+  return transaction;
+}
+
+s_facts * facts_transaction_rollback
+(s_facts *facts, const s_facts_transaction *transaction)
+{
+  bool b;
+  s_fact fact;
+  s_fact_action *log;
+  s_facts_transaction *t;
+  if (! facts_transaction_find(facts, transaction))
+    return NULL;
+  t = facts->transaction;
   while (t) {
     log = t->log;
     while (log) {
-      if (log->remove) {
-        if (! facts_add_fact(facts, &log->fact))
-          return NULL;
-      }
-      else {
+      switch (log->action) {
+      case FACT_ACTION_ADD:
         if (! facts_remove_fact(facts, &log->fact, &b) ||
-            ! b)
-          return NULL;
+            ! b) {
+	  abort();
+	  return NULL;
+	}
+	break;
+      case FACT_ACTION_REMOVE:
+        if (! facts_add_fact(facts, &log->fact)) {
+	  abort();
+	  return NULL;
+	}
+	break;
+      case FACT_ACTION_REPLACE:
+	fact_init(&fact, log->fact.subject, log->fact.predicate,
+		  &log->object);
+	if (! facts_replace_fact(facts, &fact)) {
+	  abort();
+	  return NULL;
+	}
       }
       log = log->next;
     }
-    if (t == transaction)
+    if (t == transaction) {
+      facts_transaction_end(facts, t);
       return facts;
-    t = t->next;
+    }
+    facts_transaction_end(facts, t);
+    t = facts->transaction;
   }
-  err_puts("facts_transaction_rollback: unknown error");
-  assert(! "facts_transaction_rollback: unknown error");
-  exit(1);
+  err_puts("facts_transaction_rollback: no transaction in facts");
+  assert(! "facts_transaction_rollback: no transaction in facts");
+  abort();
   return NULL;
 }
 
diff --git a/libc3/facts_transaction.h b/libc3/facts_transaction.h
index fb139a0..372eb2c 100644
--- a/libc3/facts_transaction.h
+++ b/libc3/facts_transaction.h
@@ -15,14 +15,19 @@
 
 #include "types.h"
 
-/* Stack allocation compatible functions */
+/* Stack allocation compatible functions, call
+   facts_transaction_clean after use. */
 s_facts_transaction * facts_transaction_clean
 (s_facts_transaction *transaction);
+s_facts_transaction * facts_transaction_init
+(s_facts_transaction *transaction);
 
 /* Operators. */
-s_facts *      facts_transaction_rollback
+void      facts_transaction_end
+(s_facts *facts, s_facts_transaction *transaction);
+s_facts * facts_transaction_rollback
 (s_facts *facts, const s_facts_transaction *transaction);
-void           facts_transaction_start
+void      facts_transaction_start
 (s_facts *facts, s_facts_transaction *transaction);
 
 #endif /* LIBC3_FACTS_TRANSACTION_H */
diff --git a/libc3/types.h b/libc3/types.h
index 86f7579..c7c875d 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -89,6 +89,12 @@ typedef enum {
 } e_bool;
 
 typedef enum {
+  FACT_ACTION_ADD,
+  FACT_ACTION_REMOVE,
+  FACT_ACTION_REPLACE
+} e_fact_action;
+
+typedef enum {
   TAG_VOID = 0,
   TAG_ARRAY,
   TAG_BLOCK,
@@ -344,12 +350,6 @@ struct buf {
   uw          wpos;
 };
 
-struct fact_action {
-  bool remove;
-  s_fact fact;
-  s_fact_action *next;
-};
-
 struct facts_spec_cursor {
   p_facts_spec spec;
   const s_tag *subject;
@@ -524,6 +524,13 @@ struct error_handler
   s_tag tag;
 };
 
+struct fact_action {
+  e_fact_action action;
+  s_fact fact;
+  s_tag object;
+  s_fact_action *next;
+};
+
 struct fact_w {
   s_tag subject;
   s_tag predicate;