Thread (20 messages) 20 messages, 4 authors, 7d ago

Re: [PATCH 7/9] http: discard hash in dumb-http http_object_request

From: Patrick Steinhardt <hidden>
Date: 2026-07-06 06:16:07

On Sun, Jul 05, 2026 at 08:01:05PM -0400, Jeff King wrote:
On Fri, Jul 03, 2026 at 01:27:36PM +0200, Patrick Steinhardt wrote:
quoted
On Thu, Jul 02, 2026 at 04:07:07AM -0400, Jeff King wrote:
[snip]
The second issue is related: what should we do in other functions when
the active flag is not set? For example, what should this do:

  algo->init_fn(&ctx);

  git_hash_update(&ctx, ...);
  git_hash_final(out, &ctx);

  git_hash_update(&ctx, ...);
  git_hash_final(out, &ctx);

In the second git_hash_update() call, there are two obvious options:

  1. It should do nothing; there is no active context to add to.

  2. It should automatically re-init the context (using the algo from
     the previous init) and add the data.
Or 3rd: we `BUG()` when any of the functions is called on an
uninitialized context. That to me feels like the most sensible solution.
The second final() call has the added bonus that it returns data, but I
think there are two matching options:

  1. It should do nothing, and hashclr() the output (leaving it
     uninitialized just seems insane).

  2. It should automatically re-init the context (assuming there was not
     already an update() call that did so). And then I guess return
     whatever hash that particular algo generates for the empty string?

Those all seem reasonable-ish to me and give a defined output at every
moment (which is better than crashing). But it kind of feels like they'd
be papering over potential bugs. Maybe crashing _is_ better (we don't do
so reliably now, but a BUG() could make sense).
Yes, agreed.
And the third is related: do we check the active flag when initializing?
Right now the answer must be "no", because the point of the init
function is that the input is potentially garbage. But that means
something like:

  struct git_hash_ctx ctx;
  algo->init_fn(&ctx);
  algo->init_fn(&ctx);

leaks. That's maybe OK in practice. We could do something more like:

  struct git_hash_ctx = HASH_CTX_INIT;
  git_hash_start(&ctx, algo);

where the INIT step doesn't actually allocate anything, and start() is
the moment where you must promise to call final() or discard(). And then
it would be OK for start() to BUG() when the active flag is already set.
I'd say being as strict as possible is the best way to go until we find
a case where it makes sense to be less strict.
That was maybe more than you wanted to read about the topic. But if the
request is for safer object lifetimes in general, then I think there are
a lot of details about what that means.

If we are going to do anything, I'd be inclined to stop mostly after the
diff I showed above. That's the only thing I've seen that would simplify
existing code. The rest are mostly hypotheticals, but since Rust was
mentioned, I wondered if you're trying to shoot for something safer.

At any rate, I would prefer to do any of this on top of the series I
posted. I took care there to avoid double-calling final()/discard(),
which could now be simplified away. But I think I'd rather see that
simplification its own step.
Fully agreed.

Thanks!

Patrick
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help