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

Re: [PATCH 5/5] load_ref_decorations(): avoid parsing non-tag objects

From
Jeff King <peff@peff.net>
Date
Jun 22, 2021, 19:08 UTC
Message-ID
<YNI1KmkGTYDCW3jZ@coredump.intra.peff.net>
In-Reply-To
<87zgvh20j3.fsf@evledraar.gmail.com>
On Tue, Jun 22, 2021 at 08:27:53PM +0200, Ævar Arnfjörð Bjarmason wrote:
Show 30 quoted lines
> > Whoops, thanks for catching that. I originally called it "enum
> > object_type type", but then of course the compiler informed that there
> > was already a "type" variable in the function. So I renamed it to
> > "objtype" but missed updating that line. But it still compiled. Yikes. :)
> 
> [Enter Captain Hindsight]
> 
> If you use a slightly different coding style and leverage the
> information the compiler has to work with you'd get it to error for you,
> e.g. this on your original patch would catch it:
> 
> 	diff --git a/log-tree.c b/log-tree.c
> 	index 8b700e9c142..7e3a011b533 100644
> 	--- a/log-tree.c
> 	+++ b/log-tree.c
> 	@@ -157,9 +157,12 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
> 	 	}
> 	 
> 	 	objtype = oid_object_info(the_repository, oid, NULL);
> 	-	if (type < 0)
> 	+	switch (type) {
> 	+	case OBJ_BAD:
> 	 		return 0;
> 	-	obj = lookup_object_by_type(the_repository, oid, objtype);
> 	+	default:
> 	+		obj = lookup_object_by_type(the_repository, oid, objtype);
> 	+	}
> 	 
> 	 	if (starts_with(refname, "refs/heads/"))
> 	 		type = DECORATION_REF_LOCAL;

Yeah, I agree that would find it in this case. I do find that style slightly harder to read, though. And...

Show 11 quoted lines
> IMO the real problem is an over-reliance on C being so happy to treat
> enums as ints (well, with them being ints). If you consistently use
> labels you get the compiler to do the checking. For me with gcc and
> clang with that on top:
> 	
> 	log-tree.c:161:2: error: case value ‘4294967295’ not in enumerated type ‘enum decoration_type’ [-Werror=switch]
> 	  case OBJ_BAD:
> 	  ^~~~
> 	log-tree.c:161:7: error: case value not in enumerated type 'enum decoration_type' [-Werror,-Wswitch]
> 	        case OBJ_BAD:
> 	             ^

...it would help in this case because OBJ_BAD happens to have a value that is not defined for decoration_type. If it did, then the compiler would be quite happy to consider them equivalent.

So I don't disagree with you exactly, but I'm not sure of the tradeoff of always using switches instead of conditionals (which IMHO is less readable) for more compiler safety that only works sometimes is worth it.

> I think we've disagreed on that exact point before recently, i.e. you
> think we shouldn't rely on OBJ_BAD in that way, and instead check for
> any negative value:
> https://lore.kernel.org/git/YHCZh5nLNVEHCWV2@coredump.intra.peff.net/

To be clear, my complaint about checking for OBJ_BAD exactly is that it closes the door on other negative return types. And indeed, the switch() you showed above would become a silent bug if we introduced OBJ_BAD_FOR_ANOTHER_READ as "-2" (without any compiler support, because of the "default" case in the switch statement).

Now that's somewhat hypothetical, but in the near-term it also means confirming that any of the functions which get converted from "int" to "enum object_type" are not in fact passing back "-2" in any circumstances.

That said...
Show 10 quoted lines
> In practice I don't think it's too verbose, because once you start
> consistently using the pattern you'll usually not be doing conversions
> all over the place, and would just do this sort of thing via a helper
> that does the type checking, e.g. something like this (or anything else
> where you don't lose the type & labels):
> [...]
> 	-	objtype = oid_object_info(the_repository, oid, NULL);
> 	-	if (type < 0)
> 	+	if (!oid_object_info_ok(the_repository, oid, &type, NULL))
> 	 		return 0;

Yes, that would deal with that problem. It's definitely a different style, but one that I could get used to. It's a lot more object oriented ("you are not allowed to do numeric logic on an object type; you can only use these accessor methods to query it"). If we were going that route, I would stop having "enum object_type" at all, and instead make it "struct object_type { enum { ... } value }". That would prevent anybody from accidentally just looking at it, and instead force people into that object-oriented style.

I dunno. It is is a big departure from how we do things now. And the bug here notwithstanding, I don't feel like enum confusion has generally been a big source of error for us.

-Peff
Previous: Ævar Arnfjörð BjarmasonNext: Ævar Arnfjörð Bjarmason
Message 12 of 16 in “some "log --decorate" optimizations”
  1. 0/5 some "log --decorate" optimizationsJeff King, Jun 22, 2021
  2. 1/5 pretty.h: update and expand docstring for userformat_find_requirements()Jeff King, Jun 22, 2021
  3. 2/5 log: avoid loading decorations for userformats that don't need itJeff King, Jun 22, 2021
  4. 3/5 object.h: expand docstring for lookup_unknown_object()Jeff King, Jun 22, 2021
  5. 4/5 object.h: add lookup_object_by_type() functionJeff King, Jun 22, 2021
  6. 5/5 load_ref_decorations(): avoid parsing non-tag objectsJeff King, Jun 22, 2021
  7. Derrick StoleeJun 22, 2021
  8. Jeff KingJun 22, 2021
  9. Jeff KingJun 22, 2021
  10. Derrick StoleeJun 22, 2021
  11. Ævar Arnfjörð BjarmasonJun 22, 2021
  12. Jeff KingJun 22, 2021
  13. Ævar Arnfjörð BjarmasonJun 22, 2021
  14. Jeff KingJun 22, 2021
  15. Taylor BlauJun 23, 2021
  16. Jeff KingJun 23, 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.