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

[PATCH 3/4] reftable/stack: fix zero-sized allocation when there are no readers

From
Patrick Steinhardt <ps@pks.im>
Date
Dec 21, 2024, 11:50 UTC
Message-ID
<20241221-b4-pks-reftable-oom-fix-without-readers-v1-3-12db83a3267c@pks.im>
In-Reply-To
<20241221-b4-pks-reftable-oom-fix-without-readers-v1-0-12db83a3267c@pks.im>

Similar as the preceding commit, we may try to do a zero-sized allocation when reloading a reftable stack that ain't got any tables. It is implementation-defined whether malloc(3p) returns a NULL pointer in that case or a zero-sized object. In case it does return a NULL pointer though it causes us to think we have run into an out-of-memory situation, and thus we return an error.

Fix this by only allocating arrays when they have at least one entry. Refactor the code so that we don't try to access those arrays in case they are empty.

Reported-by: Randall S. Becker <rsbecker@nexbridge.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 reftable/stack.c | 44 +++++++++++++++++++++++---------------------
 1 file changed, 23 insertions(+), 21 deletions(-)
diff --git a/reftable/stack.c b/reftable/stack.c
index 6ca21965d8e1135d986043113d465abd14cd532c..8328bfc58e9c207983ce88355d6110c40be3fac1 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -270,40 +270,42 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
 				      int reuse_open)
 {
 	size_t cur_len = !st->merged ? 0 : st->merged->readers_len;
-	struct reftable_reader **cur;
+	struct reftable_reader **cur = NULL;
 	struct reftable_reader **reused = NULL;
-	struct reftable_reader **new_readers;
+	struct reftable_reader **new_readers = NULL;
 	size_t reused_len = 0, reused_alloc = 0, names_len;
 	size_t new_readers_len = 0;
 	struct reftable_merged_table *new_merged = NULL;
 	struct reftable_buf table_path = REFTABLE_BUF_INIT;
 	int err = 0;
-	size_t i;
 
-	cur = stack_copy_readers(st, cur_len);
-	if (!cur) {
-		err = REFTABLE_OUT_OF_MEMORY_ERROR;
-		goto done;
+	if (cur_len) {
+		cur = stack_copy_readers(st, cur_len);
+		if (!cur) {
+			err = REFTABLE_OUT_OF_MEMORY_ERROR;
+			goto done;
+		}
 	}
 
 	names_len = names_length(names);
-
-	new_readers = reftable_calloc(names_len, sizeof(*new_readers));
-	if (!new_readers) {
-		err = REFTABLE_OUT_OF_MEMORY_ERROR;
-		goto done;
+	if (names_len) {
+		new_readers = reftable_calloc(names_len, sizeof(*new_readers));
+		if (!new_readers) {
+			err = REFTABLE_OUT_OF_MEMORY_ERROR;
+			goto done;
+		}
 	}
 
-	while (*names) {
+	for (size_t i = 0; i < names_len; i++) {
 		struct reftable_reader *rd = NULL;
-		const char *name = *names++;
+		const char *name = names[i];
 
 		/* this is linear; we assume compaction keeps the number of
 		   tables under control so this is not quadratic. */
-		for (i = 0; reuse_open && i < cur_len; i++) {
-			if (cur[i] && 0 == strcmp(cur[i]->name, name)) {
-				rd = cur[i];
-				cur[i] = NULL;
+		for (size_t j = 0; reuse_open && j < cur_len; j++) {
+			if (cur[j] && 0 == strcmp(cur[j]->name, name)) {
+				rd = cur[j];
+				cur[j] = NULL;
 
 				/*
 				 * When reloading the stack fails, we end up
@@ -357,7 +359,7 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
 	 * file of such an open reader wouldn't have been possible to be
 	 * unlinked by the compacting process.
 	 */
-	for (i = 0; i < cur_len; i++) {
+	for (size_t i = 0; i < cur_len; i++) {
 		if (cur[i]) {
 			const char *name = reader_name(cur[i]);
 
@@ -388,11 +390,11 @@ static int reftable_stack_reload_once(struct reftable_stack *st,
 	 * happen on the successful case, because on the unsuccessful one we
 	 * decrement their refcount via `new_readers`.
 	 */
-	for (i = 0; i < reused_len; i++)
+	for (size_t i = 0; i < reused_len; i++)
 		reftable_reader_decref(reused[i]);
 
 done:
-	for (i = 0; i < new_readers_len; i++)
+	for (size_t i = 0; i < new_readers_len; i++)
 		reftable_reader_decref(new_readers[i]);
 	reftable_free(new_readers);
 	reftable_free(reused);
-- 
2.48.0.rc0.184.g0fc57dec57.dirty
Previous: Junio C HamanoNext: Junio C Hamano
Message 10 of 30 in “reftable: fix out-of-memory errors on NonStop”
  1. 0/4 reftable: fix out-of-memory errors on NonStopPatrick Steinhardt, Dec 21, 2024
  2. 1/4 reftable/stack: don't perform auto-compaction with less than two tablesPatrick Steinhardt, Dec 21, 2024
  3. Junio C HamanoDec 21, 2024
  4. Junio C HamanoDec 21, 2024
  5. Patrick SteinhardtDec 22, 2024
  6. 2/4 reftable/merged: fix zero-sized allocation when there are no readersPatrick Steinhardt, Dec 21, 2024
  7. Kristoffer HaugsbakkDec 21, 2024
  8. Patrick SteinhardtDec 21, 2024
  9. Junio C HamanoDec 21, 2024
  10. 3/4 reftable/stack: fix zero-sized allocation when there are no readersPatrick Steinhardt, Dec 21, 2024
  11. Junio C HamanoDec 21, 2024
  12. Junio C HamanoDec 21, 2024
  13. rsbecker@nexbridge.comDec 21, 2024
  14. Junio C HamanoDec 21, 2024
  15. rsbecker@nexbridge.comDec 22, 2024
  16. rsbecker@nexbridge.comDec 22, 2024
  17. Patrick SteinhardtDec 22, 2024
  18. Junio C HamanoDec 23, 2024
  19. Patrick SteinhardtDec 22, 2024
  20. 4/4 reftable/basics: return NULL on zero-sized allocationsPatrick Steinhardt, Dec 21, 2024
  21. Kristoffer HaugsbakkDec 21, 2024
  22. Randall BeckerDec 21, 2024
  23. Junio C HamanoDec 21, 2024
  24. Junio C HamanoDec 21, 2024
  25. 0/4 reftable: fix out-of-memory errors on NonStopPatrick Steinhardt, Dec 22, 2024
  26. 1/4 reftable/stack: don't perform auto-compaction with less than two tablesPatrick Steinhardt, Dec 22, 2024
  27. 2/4 reftable/merged: fix zero-sized allocation when there are no readersPatrick Steinhardt, Dec 22, 2024
  28. 3/4 reftable/stack: fix zero-sized allocation when there are no readersPatrick Steinhardt, Dec 22, 2024
  29. 4/4 reftable/basics: return NULL on zero-sized allocationsPatrick Steinhardt, Dec 22, 2024
  30. Junio C HamanoDec 22, 2024

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.