Skip to content

Commit cac15b3

Browse files
avargitster
authored andcommitted
refs API: use "failure_errno", not "errno"
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 96f6623 (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 ef18119 (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 8b72fea (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 a1c1d81 (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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f1da24c commit cac15b3

File tree

2 files changed

+1
-4
lines changed

2 files changed

+1
-4
lines changed

refs.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,8 +1713,6 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
17131713
if (refs_read_raw_ref(refs, refname, oid, &sb_refname,
17141714
&read_flags, failure_errno)) {
17151715
*flags |= read_flags;
1716-
if (errno)
1717-
*failure_errno = errno;
17181716

17191717
/* In reading mode, refs must eventually resolve */
17201718
if (resolve_flags & RESOLVE_REF_READING)

refs/files-backend.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,6 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
385385
if (lstat(path, &st) < 0) {
386386
int ignore_errno;
387387
myerr = errno;
388-
errno = 0;
389388
if (myerr != ENOENT)
390389
goto out;
391390
if (refs_read_raw_ref(refs->packed_ref_store, refname, oid,
@@ -402,7 +401,6 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
402401
strbuf_reset(&sb_contents);
403402
if (strbuf_readlink(&sb_contents, path, st.st_size) < 0) {
404403
myerr = errno;
405-
errno = 0;
406404
if (myerr == ENOENT || myerr == EINVAL)
407405
/* inconsistent with lstat; retry */
408406
goto stat_ref;
@@ -472,6 +470,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname,
472470

473471
strbuf_release(&sb_path);
474472
strbuf_release(&sb_contents);
473+
errno = 0;
475474
return ret;
476475
}
477476

0 commit comments

Comments
 (0)