Git development
 help / color / mirror / Atom feed
From: Jeff King <peff@peff.net>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>,
	Patrick Steinhardt <ps@pks.im>,
	Collin Funk <collin.funk1@gmail.com>,
	Michael J Gruber <git@grubix.eu>
Subject: [PATCH v2 07/12] pseudo-merge: fix disk reads from find_pseudo_merge()
Date: Thu, 2 Apr 2026 00:15:05 -0400	[thread overview]
Message-ID: <20260402041505.GG3501239@coredump.intra.peff.net> (raw)
In-Reply-To: <20260402041433.GA3501120@coredump.intra.peff.net>

The goal of this commit was to fix a const warning when compiling
with new versions of glibc, but ended up untangling a much deeper
problem.

The find_pseudo_merge() function does a bsearch() on the "commits"
pointer of a pseudo_merge_map. This pointer ultimately comes from memory
mapped from the on-disk bitmap file, and is thus not writable.

The "commits" array is correctly marked const, but the result from
bsearch() is returned directly as a non-const pseudo_merge_commit
struct. Since new versions of glibc annotate bsearch() in a way that
detects the implicit loss of const, the compiler now warns.

My first instinct was that we should be returning a const struct. That
requires apply_pseudo_merges_for_commit() to mark its local pointer as
const. But that doesn't work! If the offset field has the high-bit set,
we look it up in the extended table via nth_pseudo_merge_ext(). And that
function then feeds our const struct to read_pseudo_merge_commit_at(),
which writes into it by byte-swapping from the on-disk mmap.

But I think this points to a larger problem with find_pseudo_merge(). It
is not just that the return value is missing const, but it is missing
that byte-swapping! And we know that byte-swapping is needed here,
because the comparator we use for bsearch() also calls our
read_pseudo_merge_commit_at() helper.

So I think the interface is all wrong here. We should not be returning a
pointer to a struct which was cast from on-disk data. We should be
filling in a caller-provided struct using the bytes we found,
byte-swapping the values.

That of course raises the dual question: how did this ever work, and
does it work now? The answer to the first part is: this code does not
seem to be triggered in the test suite at all. If we insert a BUG("foo")
call into apply_pseudo_merges_for_commit(), it never triggers.

So I think there is something wrong or missing from the test setup, and
this bears further investigation. Sadly the answer to the second part
("does it work now") is still "no idea". I _think_ this takes us in a
positive direction, but my goal here is mainly to quiet the compiler
warning. Further bug-hunting on this experimental feature can be done
separately.

Signed-off-by: Jeff King <peff@peff.net>
---
 pseudo-merge.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/pseudo-merge.c b/pseudo-merge.c
index a2d5bd85f9..ff18b6c364 100644
--- a/pseudo-merge.c
+++ b/pseudo-merge.c
@@ -638,31 +638,37 @@ static int pseudo_merge_commit_cmp(const void *va, const void *vb)
 	return 0;
 }
 
-static struct pseudo_merge_commit *find_pseudo_merge(const struct pseudo_merge_map *pm,
-						     uint32_t pos)
+static int find_pseudo_merge(const struct pseudo_merge_map *pm, uint32_t pos,
+			     struct pseudo_merge_commit *out)
 {
+	const unsigned char *at;
+
 	if (!pm->commits_nr)
-		return NULL;
+		return 0;
 
-	return bsearch(&pos, pm->commits, pm->commits_nr,
-		       PSEUDO_MERGE_COMMIT_RAWSZ, pseudo_merge_commit_cmp);
+	at = bsearch(&pos, pm->commits, pm->commits_nr,
+		     PSEUDO_MERGE_COMMIT_RAWSZ, pseudo_merge_commit_cmp);
+	if (!at)
+		return 0;
+
+	read_pseudo_merge_commit_at(out, at);
+	return 1;
 }
 
 int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
 				   struct bitmap *result,
 				   struct commit *commit, uint32_t commit_pos)
 {
 	struct pseudo_merge *merge;
-	struct pseudo_merge_commit *merge_commit;
+	struct pseudo_merge_commit merge_commit;
 	int ret = 0;
 
-	merge_commit = find_pseudo_merge(pm, commit_pos);
-	if (!merge_commit)
+	if (!find_pseudo_merge(pm, commit_pos, &merge_commit))
 		return 0;
 
-	if (merge_commit->pseudo_merge_ofs & ((uint64_t)1<<63)) {
+	if (merge_commit.pseudo_merge_ofs & ((uint64_t)1<<63)) {
 		struct pseudo_merge_commit_ext ext = { 0 };
-		off_t ofs = merge_commit->pseudo_merge_ofs & ~((uint64_t)1<<63);
+		off_t ofs = merge_commit.pseudo_merge_ofs & ~((uint64_t)1<<63);
 		uint32_t i;
 
 		if (pseudo_merge_ext_at(pm, &ext, ofs) < -1) {
@@ -673,11 +679,11 @@ int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
 		}
 
 		for (i = 0; i < ext.nr; i++) {
-			if (nth_pseudo_merge_ext(pm, &ext, merge_commit, i) < 0)
+			if (nth_pseudo_merge_ext(pm, &ext, &merge_commit, i) < 0)
 				return ret;
 
 			merge = pseudo_merge_at(pm, &commit->object.oid,
-						merge_commit->pseudo_merge_ofs);
+						merge_commit.pseudo_merge_ofs);
 
 			if (!merge)
 				return ret;
@@ -687,7 +693,7 @@ int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
 		}
 	} else {
 		merge = pseudo_merge_at(pm, &commit->object.oid,
-					merge_commit->pseudo_merge_ofs);
+					merge_commit.pseudo_merge_ofs);
 
 		if (!merge)
 			return ret;
-- 
2.53.0.1172.ge9e20b5838


  parent reply	other threads:[~2026-04-02  4:15 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-31 23:38 [PATCH 0/12] fixing the remainder of the C23 strchr warnings Jeff King
2026-03-31 23:41 ` [PATCH 01/12] convert: add const to fix strchr() warnings Jeff King
2026-03-31 23:41 ` [PATCH 02/12] http: " Jeff King
2026-03-31 23:41 ` [PATCH 03/12] transport-helper: drop " Jeff King
2026-04-01 13:46   ` Patrick Steinhardt
2026-03-31 23:42 ` [PATCH 04/12] pager: explicitly cast away strchr() constness Jeff King
2026-04-01 20:50   ` Junio C Hamano
2026-04-02  3:54     ` Jeff King
2026-03-31 23:42 ` [PATCH 05/12] run-command: explicitly cast away constness when assigning to void Jeff King
2026-03-31 23:44 ` [PATCH 06/12] find_last_dir_sep(): convert inline function to macro Jeff King
2026-03-31 23:46 ` [PATCH 07/12] pseudo-merge: fix disk reads from find_pseudo_merge() Jeff King
2026-03-31 23:56   ` Jeff King
2026-04-01 21:40     ` Junio C Hamano
2026-04-02 23:51     ` Taylor Blau
2026-03-31 23:50 ` [PATCH 08/12] skip_prefix(): check const match between in and out params Jeff King
2026-04-01 13:17   ` Phillip Wood
2026-04-01 14:04     ` Phillip Wood
2026-04-01 19:24       ` Jeff King
2026-04-01 22:13         ` Junio C Hamano
2026-04-02 15:05         ` Phillip Wood
2026-04-01 13:46   ` Patrick Steinhardt
2026-03-31 23:51 ` [PATCH 09/12] pkt-line: make packet_reader.line non-const Jeff King
2026-04-01 22:18   ` Junio C Hamano
2026-04-02  3:55     ` Jeff King
2026-03-31 23:52 ` [PATCH 10/12] range-diff: drop const to fix strstr() warnings Jeff King
2026-03-31 23:52 ` [PATCH 11/12] http: drop const to fix strstr() warning Jeff King
2026-03-31 23:53 ` [PATCH 12/12] refs/files-backend: drop const to fix strchr() warning Jeff King
2026-04-01 13:46   ` Patrick Steinhardt
2026-04-01 22:22     ` Junio C Hamano
2026-04-02  3:56       ` Jeff King
2026-04-02  4:14 ` [PATCH v2 0/12] fixing the remainder of the C23 strchr warnings Jeff King
2026-04-02  4:14   ` [PATCH v2 01/12] convert: add const to fix strchr() warnings Jeff King
2026-04-02  4:14   ` [PATCH v2 02/12] http: " Jeff King
2026-04-02  4:14   ` [PATCH v2 03/12] transport-helper: drop " Jeff King
2026-04-02  4:14   ` [PATCH v2 04/12] pager: explicitly cast away strchr() constness Jeff King
2026-04-02  4:15   ` [PATCH v2 05/12] run-command: explicitly cast away constness when assigning to void Jeff King
2026-04-02  4:15   ` [PATCH v2 06/12] find_last_dir_sep(): convert inline function to macro Jeff King
2026-04-02  4:15   ` Jeff King [this message]
2026-04-02  4:15   ` [PATCH v2 08/12] skip_prefix(): check const match between in and out params Jeff King
2026-04-02  5:11     ` Junio C Hamano
2026-04-02  6:01       ` Jeff King
2026-04-02 15:50         ` Junio C Hamano
2026-04-02 15:41       ` Junio C Hamano
2026-04-03 11:13     ` Toon Claes
2026-04-04  5:42       ` [PATCH v2 13/12] git-compat-util: fix CONST_OUTPARAM typo and indentation Jeff King
2026-04-02  4:15   ` [PATCH v2 09/12] pkt-line: make packet_reader.line non-const Jeff King
2026-04-02  4:15   ` [PATCH v2 10/12] range-diff: drop const to fix strstr() warnings Jeff King
2026-04-02  4:15   ` [PATCH v2 11/12] http: drop const to fix strstr() warning Jeff King
2026-04-02  4:15   ` [PATCH v2 12/12] refs/files-backend: drop const to fix strchr() warning Jeff King
2026-04-03 11:14   ` [PATCH v2 0/12] fixing the remainder of the C23 strchr warnings Toon Claes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260402041505.GG3501239@coredump.intra.peff.net \
    --to=peff@peff.net \
    --cc=collin.funk1@gmail.com \
    --cc=git@grubix.eu \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=ps@pks.im \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox