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

[PATCH v3 1/3] refs API: use "failure_errno", not "errno"

From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Date
Jan 12, 2022, 12:36 UTC
Message-ID
<patch-v3-1.3-a45268ac24b-20220112T123117Z-avarab@gmail.com>
In-Reply-To
<cover-v3-0.3-00000000000-20220112T123117Z-avarab@gmail.com>

Fix a logic error in refs_resolve_ref_unsafe() introduced in a recent series of mine to abstract the refs API away from errno. See 96f6623ada0 (Merge branch 'ab/refs-errno-cleanup', 2021-11-29)for that series.

In that series introduction of "failure_errno" to refs_resolve_ref_unsafe came in ef18119dec8 (refs API: add a version of refs_resolve_ref_unsafe() with "errno", 2021-10-16). There we'd set "errno = 0" immediately before refs_read_raw_ref(), and then set "failure_errno" to "errno" if errno was non-zero afterwards.

Then in the next commit 8b72fea7e91 (refs API: make refs_read_raw_ref() not set errno, 2021-10-16) we started expecting "refs_read_raw_ref()" to set "failure_errno". It would do that if refs_read_raw_ref() failed, but it wouldn't be the same errno.

So we might set the "errno" here to any arbitrary bad value, and end up e.g. returning NULL when we meant to return the refname from refs_resolve_ref_unsafe(), or the other way around. Instrumenting this code will reveal cases where refs_read_raw_ref() will fail, and "errno" and "failure_errno" will be set to different values.

In practice I haven't found a case where this scary bug changed anything in practice. The reason for that is that we'll not care about the actual value of "errno" here per-se, but only whether:

 1. We have an errno
 2. If it's one of ENOENT, EISDIR or ENOTDIR. See the adjacent code
    added in a1c1d8170db (refs_resolve_ref_unsafe: handle d/f
    conflicts for writes, 2017-10-06)

I.e. if we clobber "failure_errno" with "errno", but it happened to be one of those three, and we'll clobber it with another one of the three we were OK.

Perhaps there are cases where the difference ended up mattering, but I haven't found them. Instrumenting the test suite to fail if "errno" and "failure_errno" are different shows a lot of failures, checking if they're different *and* one is but not the other is outside that list of three "errno" values yields no failures.

But let's fix the obvious bug. We should just stop paying attention to "errno" in refs_resolve_ref_unsafe(). In addition let's change the partial resetting of "errno" in files_read_raw_ref() to happen just before the "return", to ensure that any such bug will be more easily spotted in the future.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 refs.c               | 2 --
 refs/files-backend.c | 3 +--
 2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/refs.c b/refs.c
index bd2546ae230..addb26293b4 100644
--- a/refs.c
+++ b/refs.c
@@ -1722,8 +1722,6 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
 		if (refs_read_raw_ref(refs, refname, oid, &sb_refname,
 				      &read_flags, failure_errno)) {
 			*flags |= read_flags;
-			if (errno)
-				*failure_errno = errno;
 
 			/* In reading mode, refs must eventually resolve */
 			if (resolve_flags & RESOLVE_REF_READING)
diff --git a/refs/files-backend.c b/refs/files-backend.c
index b529fdf237e..43a3b882d7c 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -382,7 +382,6 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 	if (lstat(path, &st) < 0) {
 		int ignore_errno;
 		myerr = errno;
-		errno = 0;
 		if (myerr != ENOENT)
 			goto out;
 		if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
@@ -399,7 +398,6 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 		strbuf_reset(&sb_contents);
 		if (strbuf_readlink(&sb_contents, path, st.st_size) < 0) {
 			myerr = errno;
-			errno = 0;
 			if (myerr == ENOENT || myerr == EINVAL)
 				/* inconsistent with lstat; retry */
 				goto stat_ref;
@@ -469,6 +467,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
 
 	strbuf_release(&sb_path);
 	strbuf_release(&sb_contents);
+	errno = 0;
 	return ret;
 }
 
-- 
2.35.0.rc0.848.gb9d3879eb1d
Previous: Ævar Arnfjörð BjarmasonNext: Junio C Hamano
Message 14 of 28 in “errno oversight”
  1. Han-Wen NienhuysDec 8, 2021
  2. Ævar Arnfjörð BjarmasonDec 8, 2021
  3. Ævar Arnfjörð BjarmasonDec 8, 2021
  4. Junio C HamanoDec 8, 2021
  5. 0/3 refs: ab/refs-errno-cleanup fixup + remove "failure_errno"Ævar Arnfjörð Bjarmason, Dec 9, 2021
  6. 1/3 refs API: use "failure_errno", not "errno"Ævar Arnfjörð Bjarmason, Dec 9, 2021
  7. 2/3 sequencer: don't use die_errno() on refs_resolve_ref_unsafe() failureÆvar Arnfjörð Bjarmason, Dec 9, 2021
  8. 3/3 refs API: remove "failure_errno" from refs_resolve_ref_unsafe()Ævar Arnfjörð Bjarmason, Dec 9, 2021
  9. 0/3 refs: ab/refs-errno-cleanup fixup + remove "failure_errno"Ævar Arnfjörð Bjarmason, Dec 12, 2021
  10. 1/3 refs API: use "failure_errno", not "errno"Ævar Arnfjörð Bjarmason, Dec 12, 2021
  11. 2/3 sequencer: don't use die_errno() on refs_resolve_ref_unsafe() failureÆvar Arnfjörð Bjarmason, Dec 12, 2021
  12. 3/3 refs API: remove "failure_errno" from refs_resolve_ref_unsafe()Ævar Arnfjörð Bjarmason, Dec 12, 2021
  13. 0/3 For v2.35.0: refs: ab/refs-errno-cleanup fixup + remove "failure_errno"Ævar Arnfjörð Bjarmason, Jan 12, 2022
  14. 1/3 refs API: use "failure_errno", not "errno"Ævar Arnfjörð Bjarmason, Jan 12, 2022
  15. Junio C HamanoJan 12, 2022
  16. Ævar Arnfjörð BjarmasonJan 13, 2022
  17. 2/3 sequencer: don't use die_errno() on refs_resolve_ref_unsafe() failureÆvar Arnfjörð Bjarmason, Jan 12, 2022
  18. Junio C HamanoJan 12, 2022
  19. 3/3 refs API: remove "failure_errno" from refs_resolve_ref_unsafe()Ævar Arnfjörð Bjarmason, Jan 12, 2022
  20. Junio C HamanoJan 12, 2022
  21. Ævar Arnfjörð BjarmasonJan 13, 2022
  22. Junio C HamanoJan 13, 2022
  23. Ævar Arnfjörð BjarmasonJan 14, 2022
  24. 0/2 refs: remove the last use of "errno" from the public APIÆvar Arnfjörð Bjarmason, Jan 26, 2022
  25. 1/2 sequencer: don't use die_errno() on refs_resolve_ref_unsafe() failureÆvar Arnfjörð Bjarmason, Jan 26, 2022
  26. Junio C HamanoJan 26, 2022
  27. 2/2 refs API: remove "failure_errno" from refs_resolve_ref_unsafe()Ævar Arnfjörð Bjarmason, Jan 26, 2022
  28. Han-Wen NienhuysDec 8, 2021

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.