Re: [PATCH 7/9] ls-refs: ignore very long ref-prefix counts
From: Jeff King <hidden>
Date: 2021-09-14 19:22:15
On Tue, Sep 14, 2021 at 09:06:55PM +0200, Martin Ågren wrote:
quoted
But we can do better. Since supporting the ref-prefix capability is optional anyway, the client has to further cull the response based on their own patterns. So we can simply ignore the patterns once we cross a certain threshold. Note that we have to ignore _all_ patterns, not just the ones past our limit (since otherwise we'd send too little data).This all makes sense to me. At some point, we should be able to go "I don't know what you're trying to do, but let me just ignore all this craziness and instead try to give you a useful result sooner rather than later". I do wonder if we should document that the client can't trust us to actually do all this culling. In general, I find that it's a matter of hygiene for the client to do its own checks, but with this change they actually *need* to do them. (Unless they know our limit and that they're on the right side of it, but that kind of magic is even less hygienic.)
Perhaps we could say so more explicitly in the v2 protocol spec. I'll take a look.
quoted
+ else if (skip_prefix(arg, "ref-prefix ", &out)) { + if (too_many_prefixes) { + /* ignore any further ones */ + } else if (data.prefixes.nr >= MAX_ALLOWED_PREFIXES) { + strvec_clear(&data.prefixes); + too_many_prefixes = 1; + } else { + strvec_push(&data.prefixes, out); + } + }Is it easier to reason about with something like this (whitespace-damaged) on top?
You're the second person to complain about this if-else chain. I'll take the hint. ;)
quoted hunk ↗ jump to hunk
diff --git a/ls-refs.c b/ls-refs.c index 839fb0caa9..b3101ff361 100644 --- a/ls-refs.c +++ b/ls-refs.c@@ -147,7 +147,6 @@ static int ls_refs_config(const char *var, constchar *value, void *data) int ls_refs(struct repository *r, struct packet_reader *request) { struct ls_refs_data data; - int too_many_prefixes = 0; memset(&data, 0, sizeof(data)); strvec_init(&data.prefixes);@@ -164,14 +163,8 @@ int ls_refs(struct repository *r, structpacket_reader *request) else if (!strcmp("symrefs", arg)) data.symrefs = 1; else if (skip_prefix(arg, "ref-prefix ", &out)) { - if (too_many_prefixes) { - /* ignore any further ones */ - } else if (data.prefixes.nr >= MAX_ALLOWED_PREFIXES) { - strvec_clear(&data.prefixes); - too_many_prefixes = 1; - } else { + if (data.prefixes.nr <= MAX_ALLOWED_PREFIXES) strvec_push(&data.prefixes, out); - } }
Hmm. At first I liked this, because it reduces the number of cases (and variables!). But there's something really subtle going on here. I thought at first it should be "<", but you are intentionally over-allocating by one entry to indicate the overflow. I.e., you've essentially stuffed the too_many_prefixes boolean into the count.
quoted hunk ↗ jump to hunk
@@ -180,6 +173,9 @@ int ls_refs(struct repository *r, structpacket_reader *request) if (request->status != PACKET_READ_FLUSH) die(_("expected flush after ls-refs arguments")); + if (data.prefixes.nr > MAX_ALLOWED_PREFIXES) + strvec_clear(&data.prefixes); +
This is far from the parser, but I think that's OK. I'd probably couple it with a comment explaining why we need to clear rather than using what we got.
Maybe even name the macro TOO_MANY_PREFIXES (and bump it by one)
to make the logic instead be
if (data.prefixes.nr < TOO_MANY_PREFIXES)
strvec_push(&data.prefixes, out);
...
if (data.prefixes.nr >= TOO_MANY_PREFIXES)
strvec_clear(&data.prefixes);At first I thought this was just being cute, but it's an attempt to compensate for the off-by-one subtlety in the early check. I'll give it some thought. I kind of like it, but the fact that it took me a minute or three to be sure the code is correct makes me worried it's being too clever. -Peff