git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 4/6] refs.c: lock cached_refs during for_each_ref

From
Sskimo@liacs.nl <skimo@liacs.nl>
Date
Jul 12, 2007, 19:06 UTC
Message-ID
<11842671632300-git-send-email-skimo@liacs.nl>
In-Reply-To
<11842671631744-git-send-email-skimo@liacs.nl>
From: Sven Verdoolaege <skimo@kotnet.org>

If the function called by for_each_ref modifies a ref in any way, the cached_refs that for_each_ref was looping over would be removed, resulting in undefined behavior.

This patch prevents the cached_refs from being removed while for_each_ref is still iterating over them.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
---
 refs.c |   37 +++++++++++++++++++++++++++++++++----
 1 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/refs.c b/refs.c
index 4dc7e8b..e710903 100644
--- a/refs.c
+++ b/refs.c
@@ -153,6 +153,8 @@ static struct ref_list *sort_ref_list(struct ref_list *list)
 static struct cached_refs {
 	char did_loose;
 	char did_packed;
+	char is_locked;
+	char is_invalidated;
 	struct ref_list *loose;
 	struct ref_list *packed;
 } cached_refs;
@@ -170,6 +172,11 @@ static void invalidate_cached_refs(void)
 {
 	struct cached_refs *ca = &cached_refs;
 
+	if (ca->is_locked) {
+		ca->is_invalidated = 1;
+		return;
+	}
+
 	if (ca->did_loose && ca->loose)
 		free_ref_list(ca->loose);
 	if (ca->did_packed && ca->packed)
@@ -178,6 +185,24 @@ static void invalidate_cached_refs(void)
 	ca->did_loose = ca->did_packed = 0;
 }
 
+static void lock_cached_refs(void)
+{
+	struct cached_refs *ca = &cached_refs;
+
+	ca->is_locked = 1;
+}
+
+static void unlock_cached_refs(void)
+{
+	struct cached_refs *ca = &cached_refs;
+
+	ca->is_locked = 0;
+	if (ca->is_invalidated) {
+		invalidate_cached_refs();
+		ca->is_invalidated = 0;
+	}
+}
+
 static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
 {
 	struct ref_list *list = NULL;
@@ -518,10 +543,12 @@ int peel_ref(const char *ref, unsigned char *sha1)
 static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
 			   void *cb_data)
 {
-	int retval;
+	int retval = 0;
 	struct ref_list *packed = get_packed_refs();
 	struct ref_list *loose = get_loose_refs();
 
+	lock_cached_refs();
+
 	while (packed && loose) {
 		struct ref_list *entry;
 		int cmp = strcmp(packed->name, loose->name);
@@ -538,15 +565,17 @@ static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
 		}
 		retval = do_one_ref(base, fn, trim, cb_data, entry);
 		if (retval)
-			return retval;
+			goto out;
 	}
 
 	for (packed = packed ? packed : loose; packed; packed = packed->next) {
 		retval = do_one_ref(base, fn, trim, cb_data, packed);
 		if (retval)
-			return retval;
+			goto out;
 	}
-	return 0;
+ out:
+	unlock_cached_refs();
+	return retval;
 }
 
 int head_ref(each_ref_fn fn, void *cb_data)
-- 
1.5.3.rc0.100.ge60b4
Previous: Johannes SchindelinNext: skimo@liacs.nl
Message 6 of 23 in “Add git-rewrite-commits v2”
  1. 0/6 Add git-rewrite-commits v2skimo@liacs.nl, Jul 12, 2007
  2. 1/6 revision: allow selection of commits that do not match a patternskimo@liacs.nl, Jul 12, 2007
  3. 2/6 export get_short_sha1skimo@liacs.nl, Jul 12, 2007
  4. 3/6 Define ishex(x) in git-compat-util.hskimo@liacs.nl, Jul 12, 2007
  5. Johannes SchindelinJul 14, 2007
  6. 4/6 refs.c: lock cached_refs during for_each_refskimo@liacs.nl, Jul 12, 2007
  7. 5/6 revision: mark commits that didn't match a pattern for later useskimo@liacs.nl, Jul 12, 2007
  8. 6/6 Add git-rewrite-commitsskimo@liacs.nl, Jul 12, 2007
  9. Sven VerdoolaegeJul 13, 2007
  10. Johannes SchindelinJul 14, 2007
  11. Junio C HamanoJul 14, 2007
  12. Sven VerdoolaegeJul 15, 2007
  13. Sven VerdoolaegeJul 14, 2007
  14. Sven VerdoolaegeJul 15, 2007
  15. Johannes SchindelinJul 16, 2007
  16. Sven VerdoolaegeJul 16, 2007
  17. Johannes SchindelinJul 18, 2007
  18. Sven VerdoolaegeJul 18, 2007
  19. Sven VerdoolaegeJul 16, 2007
  20. Sven VerdoolaegeJul 16, 2007
  21. Johannes SchindelinJul 18, 2007
  22. Johannes SchindelinJul 18, 2007
  23. Sven VerdoolaegeJul 19, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.