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

[PATCH v2 2/2] hex: make hash_to_hex_algop() and friends thread-safe

From
Matheus Tavares <matheus.bernardino@usp.br>
Date
Jun 26, 2020, 21:54 UTC
Message-ID
<b47445fa1cef6d4523dd0ca336f7ee22bce89466.1593208411.git.matheus.bernardino@usp.br>
In-Reply-To
<cover.1593208411.git.matheus.bernardino@usp.br>

hash_to_hex_algop() returns a static buffer, relieving callers from the responsibility of freeing memory after use. But the current implementation uses the same static data for all threads and, thus, is not thread-safe. We could avoid using this function and its wrappers in threaded code, but they are sometimes too deep in the call stack to be noticed or even avoided.

grep.c:grep_source_load_oid(), for example, uses the thread-unsafe oid_to_hex() (on errors) despite being called in threaded code. And oid_to_hex() -- which calls hash_to_hex_algop() -- is used in many other places, as well:

$ git grep 'oid_to_hex(' | wc -l 818

Although hash_to_hex_algop() and its wrappers don't seem to be causing problems out there for now (at least not reported), making them thread-safe makes the codebase more robust against race conditions. We can easily do that by replicating the static buffer in each thread's local storage.

Original-patch-by: Fredrik Kuivinen <frekui@gmail.com>
Signed-off-by: Fredrik Kuivinen <frekui@gmail.com>
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
---
 hex.c | 46 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 42 insertions(+), 4 deletions(-)
diff --git a/hex.c b/hex.c
index da51e64929..4f2f163d5e 100644
--- a/hex.c
+++ b/hex.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "thread-utils.h"
 
 const signed char hexval_table[256] = {
 	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 00-07 */
@@ -136,12 +137,49 @@ char *oid_to_hex_r(char *buffer, const struct object_id *oid)
 	return hash_to_hex_algop_r(buffer, oid->hash, the_hash_algo);
 }
 
+struct hexbuf_array {
+	int idx;
+	char bufs[4][GIT_MAX_HEXSZ + 1];
+};
+
+#ifdef HAVE_THREADS
+static pthread_key_t hexbuf_array_key;
+static pthread_once_t hexbuf_array_once = PTHREAD_ONCE_INIT;
+
+static void init_hexbuf_array_key(void)
+{
+	if (pthread_key_create(&hexbuf_array_key, free))
+		die(_("failed to initialize threads' key for hash to hex conversion"));
+}
+
+#else
+static struct hexbuf_array default_hexbuf_array;
+#endif
+
 char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *algop)
 {
-	static int bufno;
-	static char hexbuffer[4][GIT_MAX_HEXSZ + 1];
-	bufno = (bufno + 1) % ARRAY_SIZE(hexbuffer);
-	return hash_to_hex_algop_r(hexbuffer[bufno], hash, algop);
+	struct hexbuf_array *ha;
+
+#ifdef HAVE_THREADS
+	void *value;
+
+	if (pthread_once(&hexbuf_array_once, init_hexbuf_array_key))
+		die(_("failed to initialize threads' key for hash to hex conversion"));
+
+	value = pthread_getspecific(hexbuf_array_key);
+	if (value) {
+		ha = (struct hexbuf_array *) value;
+	} else {
+		ha = xmalloc(sizeof(*ha));
+		if (pthread_setspecific(hexbuf_array_key, (void *)ha))
+			die(_("failed to set thread buffer for hash to hex conversion"));
+	}
+#else
+	ha = &default_hexbuf_array;
+#endif
+
+	ha->idx = (ha->idx + 1) % ARRAY_SIZE(ha->bufs);
+	return hash_to_hex_algop_r(ha->bufs[ha->idx], hash, algop);
 }
 
 char *hash_to_hex(const unsigned char *hash)
-- 
2.26.2
Previous: Matheus TavaresNext: Johannes Schindelin
Message 17 of 25 in “[RFC] Thread safety in some low-level functions”
  1. Matheus Tavares BernardinoJun 24, 2020
  2. Matheus Tavares BernardinoJun 24, 2020
  3. brian m. carlsonJun 25, 2020
  4. 0/2 Make oid_to_hex() thread-safeMatheus Tavares, Jun 25, 2020
  5. 1/2 compat/win32/pthread: add pthread_once()Matheus Tavares, Jun 25, 2020
  6. Christian CouderJun 26, 2020
  7. Matheus Tavares BernardinoJun 26, 2020
  8. 2/2 hex: make hash_to_hex_algop() and friends thread-safeMatheus Tavares, Jun 25, 2020
  9. brian m. carlsonJun 25, 2020
  10. Matheus Tavares BernardinoJun 25, 2020
  11. Matheus Tavares BernardinoJun 26, 2020
  12. Christian CouderJun 26, 2020
  13. Christian CouderJun 26, 2020
  14. Matheus Tavares BernardinoJun 26, 2020
  15. 0/2 Make oid_to_hex() thread-safeMatheus Tavares, Jun 26, 2020
  16. 1/2 compat/win32/pthread: add pthread_once()Matheus Tavares, Jun 26, 2020
  17. 2/2 hex: make hash_to_hex_algop() and friends thread-safeMatheus Tavares, Jun 26, 2020
  18. Johannes SchindelinJun 29, 2020
  19. Matheus Tavares BernardinoJun 30, 2020
  20. Johannes SchindelinJul 1, 2020
  21. Johannes SchindelinJul 16, 2020
  22. Matheus Tavares BernardinoJul 18, 2020
  23. Johannes SchindelinAug 10, 2020
  24. Matheus TavaresJul 18, 2020
  25. René ScharfeJul 26, 2020

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.