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

Re: [PATCH v3 02/19] builtin/diff-tree: convert to struct object_id

From
Jeff King <peff@peff.net>
Date
Feb 18, 2017, 03:15 UTC
Message-ID
<20170218031530.2bhlnjcukl4ybt6h@sigill.intra.peff.net>
In-Reply-To
<20170218014217.sil4jyukkbqguxfz@sigill.intra.peff.net>
On Fri, Feb 17, 2017 at 08:42:17PM -0500, Jeff King wrote:
Show 17 quoted lines
> > I'm wondering if parse_oid_hex could be useful here as well.
> 
> I know I haven't looked at this chunk nearly as carefully as you have,
> but it seems somewhat crazy to me that these functions get the original
> "line" in the first place. Shouldn't they get line+40 from the caller
> (who in turn should be using parse_oid_hex to compute that)?
> 
> And then each function should subsequently parse left-to-right with
> a mix of isspace() and parse_oid_hex(), and probably doesn't even need
> to care about the original "len" at all (yes, you can quit early if you
> know your len isn't long enough, but that's the unusual error case
> anyway; it's not a big deal to find that out while parsing).
> 
> In general, I think this sort of left-to-right incremental pointer
> movement is safe and simple. There may be a few cases where it doesn't
> apply (i.e., where you need to look at the end of the string to know how
> to parse the beginning), but that should be relatively rare.
So for this case, something like the patch below.

Incidentally, there's an off-by-one in the original loop of stdin_diff_commit that reads past the end of the trailing NUL for the final sha1 on the line. The problem is the:

  pos += GIT_SHA1_HEXSZ + 1;

which assumes we're slurping up the trailing space. This works in practice because the caller will only permit a string which had a newline (which it converted into a NUL).

I suspect that function could be more aggressive about complaining about nonsense on the line, rather than silently ignoring it.

 builtin/diff-tree.c | 43 ++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 1f1573bb2..222c671f2 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -16,37 +16,33 @@ static int diff_tree_commit_sha1(const struct object_id *oid)
 }
 
 /* Diff one or more commits. */
-static int stdin_diff_commit(struct commit *commit, char *line, int len)
+static int stdin_diff_commit(struct commit *commit, const char *p)
 {
 	struct object_id oid;
-	if (isspace(line[GIT_SHA1_HEXSZ]) && !get_oid_hex(line+GIT_SHA1_HEXSZ+1, &oid)) {
-		/* Graft the fake parents locally to the commit */
-		int pos = GIT_SHA1_HEXSZ + 1;
-		struct commit_list **pptr;
-
-		/* Free the real parent list */
-		free_commit_list(commit->parents);
-		commit->parents = NULL;
-		pptr = &(commit->parents);
-		while (line[pos] && !get_oid_hex(line + pos, &oid)) {
-			struct commit *parent = lookup_commit(oid.hash);
-			if (parent) {
-				pptr = &commit_list_insert(parent, pptr)->next;
-			}
-			pos += GIT_SHA1_HEXSZ + 1;
+	struct commit_list **pptr = NULL;
+
+	/* Graft the fake parents locally to the commit */
+	while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) {
+		struct commit *parent = lookup_commit(oid.hash);
+		if (!pptr) {
+			/* Free the real parent list */
+			free_commit_list(commit->parents);
+			commit->parents = NULL;
+			pptr = &(commit->parents);
+		}
+		if (parent) {
+			pptr = &commit_list_insert(parent, pptr)->next;
 		}
 	}
 	return log_tree_commit(&log_tree_opt, commit);
 }
 
 /* Diff two trees. */
-static int stdin_diff_trees(struct tree *tree1, char *line, int len)
+static int stdin_diff_trees(struct tree *tree1, const char *p)
 {
 	struct object_id oid;
 	struct tree *tree2;
-	const int chunksz = GIT_SHA1_HEXSZ + 1;
-	if (len != 2 * chunksz || !isspace(line[chunksz-1]) ||
-		get_sha1_hex(line + chunksz, oid.hash))
+	if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p)
 		return error("Need exactly two trees, separated by a space");
 	tree2 = lookup_tree(oid.hash);
 	if (!tree2 || parse_tree(tree2))
@@ -64,19 +60,20 @@ static int diff_tree_stdin(char *line)
 	int len = strlen(line);
 	struct object_id oid;
 	struct object *obj;
+	const char *rest;
 
 	if (!len || line[len-1] != '\n')
 		return -1;
 	line[len-1] = 0;
-	if (get_oid_hex(line, &oid))
+	if (parse_oid_hex(line, &oid, &rest))
 		return -1;
 	obj = parse_object(oid.hash);
 	if (!obj)
 		return -1;
 	if (obj->type == OBJ_COMMIT)
-		return stdin_diff_commit((struct commit *)obj, line, len);
+		return stdin_diff_commit((struct commit *)obj, rest);
 	if (obj->type == OBJ_TREE)
-		return stdin_diff_trees((struct tree *)obj, line, len);
+		return stdin_diff_trees((struct tree *)obj, rest);
 	error("Object %s is a %s, not a commit or tree",
 	      oid_to_hex(&oid), typename(obj->type));
 	return -1;
Previous: Jeff KingNext: brian m. carlson
Message 6 of 28 in “object_id part 6”
  1. 00/19 object_id part 6brian m. carlson, Feb 18, 2017
  2. 02/19 builtin/diff-tree: convert to struct object_idbrian m. carlson, Feb 18, 2017
  3. Ramsay JonesFeb 18, 2017
  4. brian m. carlsonFeb 18, 2017
  5. Jeff KingFeb 18, 2017
  6. Jeff KingFeb 18, 2017
  7. brian m. carlsonFeb 18, 2017
  8. Jeff KingFeb 18, 2017
  9. 08/19 builtin/clone: convert to struct object_idbrian m. carlson, Feb 18, 2017
  10. 05/19 builtin/fmt-merge-message: convert to struct object_idbrian m. carlson, Feb 18, 2017
  11. 07/19 builtin/branch: convert to struct object_idbrian m. carlson, Feb 18, 2017
  12. 06/19 builtin/grep: convert to struct object_idbrian m. carlson, Feb 18, 2017
  13. 18/19 builtin/merge-base: convert to struct object_idbrian m. carlson, Feb 18, 2017
  14. 15/19 refs: simplify parsing of reflog entriesbrian m. carlson, Feb 18, 2017
  15. 17/19 Convert object iteration callbacks to struct object_idbrian m. carlson, Feb 18, 2017
  16. 19/19 wt-status: convert to struct object_idbrian m. carlson, Feb 18, 2017
  17. 13/19 refs: convert each_reflog_ent_fn to struct object_idbrian m. carlson, Feb 18, 2017
  18. 11/19 builtin/replace: convert to struct object_idbrian m. carlson, Feb 18, 2017
  19. 14/19 hex: introduce parse_oid_hexbrian m. carlson, Feb 18, 2017
  20. 12/19 reflog-walk: convert struct reflog_info to struct object_idbrian m. carlson, Feb 18, 2017
  21. 16/19 sha1_file: introduce an nth_packed_object_oid functionbrian m. carlson, Feb 18, 2017
  22. Ramsay JonesFeb 18, 2017
  23. brian m. carlsonFeb 18, 2017
  24. 01/19 builtin/commit: convert to struct object_idbrian m. carlson, Feb 18, 2017
  25. 04/19 builtin/fast-export: convert to struct object_idbrian m. carlson, Feb 18, 2017
  26. 03/19 builtin/describe: convert to struct object_idbrian m. carlson, Feb 18, 2017
  27. 10/19 Convert remaining callers of resolve_refdup to object_idbrian m. carlson, Feb 18, 2017
  28. 09/19 builtin/merge: convert to struct object_idbrian m. carlson, Feb 18, 2017

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.