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

[PATCH] Fix bug in tag parsing when thorough verification was in effect

From
Johan Herland <johan@herland.net>
Date
Jun 7, 2007, 22:13 UTC
Message-ID
<200706080013.50644.johan@herland.net>
In-Reply-To
<200706040251.52613.johan@herland.net>

The code that was enabled by passing a non-zero 'thorough_verify' argument to parse_and_verify_tag_buffer() moved the 'tag_line' and 'keywords_line' pointer variables forward in memory while checking for illegal chars. These pointers were later used when setting the respective members on the parsed tag object.

The fix refactors the verification loop so as to use offsets to the 'tag_line' and 'keywords_line' pointers, instead of moving the pointers directly.

The patch also includes cleanup of the code associated with moving the various '*_line' pointers past their initial header field identifier. These operations are now done along with the calculation of their corresponding '*_len' variables.

The patch also includes minor changes to expected output in associated testcases.

The bug was discovered by inspection. Currently none of the callers of parse_and_verify_tag_buffer() that use thorough_verify != 0, also use the 'tag' and 'keywords' members of the parsed tag object.

Signed-off-by: Johan Herland <johan@herland.net>
---
This goes on top of the existing "Refactor the tag object" patch series.
Have fun!
...Johan
 t/t3800-mktag.sh |    8 ++++----
 tag.c            |   49 ++++++++++++++++++++++++++-----------------------
 2 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh
index f6e3d10..ac9008a 100755
--- a/t/t3800-mktag.sh
+++ b/t/t3800-mktag.sh
@@ -186,7 +186,7 @@ tagger bar@baz.com
 EOF
 
 cat >expect.pat <<EOF
-^error: char67: could not verify tag name$
+^error: char66: could not verify tag name$
 EOF
 
 check_verify_failure 'verify tag-name check'
@@ -240,7 +240,7 @@ tagger bar@baz.com
 EOF
 
 cat >expect.pat <<EOF
-^error: char83: .*$
+^error: char82: .*$
 EOF
 
 check_verify_failure '"keywords" line check #1'
@@ -258,7 +258,7 @@ tagger bar@baz.com
 EOF
 
 cat >expect.pat <<EOF
-^error: char87: .*$
+^error: char86: .*$
 EOF
 
 check_verify_failure '"keywords" line check #2'
@@ -276,7 +276,7 @@ tagger bar@baz.com
 EOF
 
 cat >expect.pat <<EOF
-^error: char83: .*$
+^error: char82: .*$
 EOF
 
 check_verify_failure '"keywords" line check #3'
diff --git a/tag.c b/tag.c
index 9c95e0b..e371179 100644
--- a/tag.c
+++ b/tag.c
@@ -153,52 +153,55 @@ int parse_and_verify_tag_buffer(struct tag *item, const char *data, const unsign
 	if (*header_end != '\n') /* header must end with "\n\n" */
 		return error("char" PD_FMT ": could not find blank line after header section", header_end - data);
 
-	/* Calculate lengths of header fields */
-	type_len      = tag_line      == type_line ? 0 :     /* 0 if not given, > 0 if given */
-			(tag_line      - type_line)     - strlen("type \n");
-	tag_len       = keywords_line == tag_line ? 0 :      /* 0 if not given, > 0 if given */
-			(keywords_line - tag_line)      - strlen("tag \n");
-	keywords_len  = tagger_line   == keywords_line ? 0 : /* 0 if not given, > 0 if given */
-			(tagger_line   - keywords_line) - strlen("keywords \n");
-	tagger_len    = header_end    == tagger_line ? 0 :   /* 0 if not given, > 0 if given */
-			(header_end    - tagger_line)   - strlen("tagger \n");
+	/*
+	 * Advance header field pointers past their initial identifier.
+	 * Calculate lengths of header fields (0 for fields that are not given).
+	 */
+	type_line     += strlen("type ");
+	type_len       =       tag_line >     type_line ? (     tag_line -     type_line) - 1 : 0;
+	tag_line      += strlen("tag ");
+	tag_len        =  keywords_line >      tag_line ? (keywords_line -      tag_line) - 1 : 0;
+	keywords_line += strlen("keywords ");
+	keywords_len   =    tagger_line > keywords_line ? (  tagger_line - keywords_line) - 1 : 0;
+	tagger_line   += strlen("tagger ");
+	tagger_len     =     header_end >   tagger_line ? (   header_end -   tagger_line) - 1 : 0;
 
 	/* Get the actual type */
 	if (type_len >= sizeof(type))
-		return error("char" PD_FMT ": type too long", (type_line + 5) - data);
-	memcpy(type, type_line + 5, type_len);
+		return error("char" PD_FMT ": type too long", (type_line) - data);
+	memcpy(type, type_line, type_len);
 	type[type_len] = '\0';
 
 	if (thorough_verify) {
+		unsigned long i;
+
 		/* Verify that the object matches */
 		if (verify_object(sha1, type))
 			return error("char%d: could not verify object %s", 7, sha1_to_hex(sha1));
 
 		/* Verify the tag name: we don't allow control characters or spaces in it */
 		if (tag_len > 0) { /* tag name was given */
-			tag_line += 4; /* skip past "tag " */
-			for (;;) {
-				unsigned char c = *tag_line++;
+			for (i = 0; i < tag_len; ++i) {
+				unsigned char c = tag_line[i];
 				if (c == '\n')
 					break;
 				if (c > ' ' && c != 0x7f)
 					continue;
-				return error("char" PD_FMT ": could not verify tag name", tag_line - data);
+				return error("char" PD_FMT ": could not verify tag name", tag_line + i - data);
 			}
 		}
 
 		/* Verify the keywords line: we don't allow control characters or spaces in it, or two subsequent commas */
 		if (keywords_len > 0) { /* keywords line was given */
-			keywords_line += 9; /* skip past "keywords " */
-			for (;;) {
-				unsigned char c = *keywords_line++;
+			for (i = 0; i < keywords_len; ++i) {
+				unsigned char c = keywords_line[i];
 				if (c == '\n')
 					break;
-				if (c == ',' && *keywords_line == ',')
-					return error("char" PD_FMT ": found empty keyword", keywords_line - data);
+				if (c == ',' && keywords_line[i + 1] == ',') /* consecutive commas */
+					return error("char" PD_FMT ": found empty keyword", keywords_line + i - data);
 				if (c > ' ' && c != 0x7f)
 					continue;
-				return error("char" PD_FMT ": could not verify keywords", keywords_line - data);
+				return error("char" PD_FMT ": could not verify keywords", keywords_line + i - data);
 			}
 		}
 
@@ -211,7 +214,7 @@ int parse_and_verify_tag_buffer(struct tag *item, const char *data, const unsign
 	if (item) { /* Store parsed information into item */
 		if (tag_len > 0) { /* optional tag name was given */
 			item->tag = xmalloc(tag_len + 1);
-			memcpy(item->tag, tag_line + 4, tag_len);
+			memcpy(item->tag, tag_line, tag_len);
 			item->tag[tag_len] = '\0';
 		}
 		else { /* optional tag name not given */
@@ -221,7 +224,7 @@ int parse_and_verify_tag_buffer(struct tag *item, const char *data, const unsign
 
 		if (keywords_len > 0) { /* optional keywords string was given */
 			item->keywords = xmalloc(keywords_len + 1);
-			memcpy(item->keywords, keywords_line + 9, keywords_len);
+			memcpy(item->keywords, keywords_line, keywords_len);
 			item->keywords[keywords_len] = '\0';
 		}
 		else { /* optional keywords string not given. Set default keywords */
-- 
1.5.2
Previous: Junio C HamanoNext: Johan Herland
Message 20 of 52 in “Refactoring the tag object; Introducing soft references (softrefs); Git 'notes' (take 2)”
  1. Johan HerlandJun 4, 2007
  2. 0/6 Refactor the tag objectJohan Herland, Jun 4, 2007
  3. 1/6 Refactor git tag objects; make "tag" header optional; introduce new optional "keywords" headerJohan Herland, Jun 4, 2007
  4. Matthias LederhoferJun 4, 2007
  5. Johan HerlandJun 4, 2007
  6. 2/6 git-show: When showing tag objects with no tag name, show tag object's SHA1 instead of an empty stringJohan Herland, Jun 4, 2007
  7. 3/6 git-fsck: Do thorough verification of tag objects.Johan Herland, Jun 4, 2007
  8. Matthias LederhoferJun 4, 2007
  9. Johan HerlandJun 4, 2007
  10. Junio C HamanoJun 6, 2007
  11. 3/6 git-fsck: Do thorough verification of tag objects.Johan Herland, Jun 6, 2007
  12. Junio C HamanoJun 6, 2007
  13. Junio C HamanoJun 6, 2007
  14. Johan HerlandJun 6, 2007
  15. Junio C HamanoJun 6, 2007
  16. 4/6 Documentation/git-mktag: Document the changes in tag object structureJohan Herland, Jun 4, 2007
  17. 5/6 git-mktag tests: Fix and expand the mktag tests according to the new tag object structureJohan Herland, Jun 4, 2007
  18. 6/6 Add fsck_verify_ref_to_tag_object() to verify that refname matches name stored in tag objectJohan Herland, Jun 4, 2007
  19. Junio C HamanoJun 4, 2007
  20. Fix bug in tag parsing when thorough verification was in effectJohan Herland, Jun 7, 2007
  21. 0/7 Introduce soft references (softrefs)Johan Herland, Jun 9, 2007
  22. 1/7 Softrefs: Add softrefs header file with API documentationJohan Herland, Jun 9, 2007
  23. Johannes SchindelinJun 10, 2007
  24. Junio C HamanoJun 10, 2007
  25. Johannes SchindelinJun 10, 2007
  26. Johan HerlandJun 10, 2007
  27. Jakub NarebskiJun 10, 2007
  28. Teach git-gc to merge unsorted softrefsJohan Herland, Jun 10, 2007
  29. 2/7 Softrefs: Add implementation of softrefs APIJohan Herland, Jun 9, 2007
  30. 3/7 Softrefs: Add git-softref, a builtin command for adding, listing and administering softrefsJohan Herland, Jun 9, 2007
  31. 4/7 Softrefs: Add manual page documenting git-softref and softrefs subsystem in generalJohan Herland, Jun 9, 2007
  32. 5/7 Softrefs: Add testcases for basic softrefs behaviourJohan Herland, Jun 9, 2007
  33. 6/7 Softrefs: Administrivia associated with softrefs subsystem and git-softref builtinJohan Herland, Jun 9, 2007
  34. 7/7 Teach git-mktag to register softrefs for all tag objectsJohan Herland, Jun 9, 2007
  35. Change softrefs file format from text (82 bytes per entry) to binary (40 bytes per entry)Johan Herland, Jun 9, 2007
  36. Johannes SchindelinJun 10, 2007
  37. Junio C HamanoJun 10, 2007
  38. Johannes SchindelinJun 10, 2007
  39. Johan HerlandJun 10, 2007
  40. Comment on weak refsJunio C Hamano, Jun 9, 2007
  41. Johan HerlandJun 10, 2007
  42. Johannes SchindelinJun 10, 2007
  43. Johan HerlandJun 10, 2007
  44. Pierre HabouzitJun 10, 2007
  45. Pierre HabouzitJun 10, 2007
  46. Pierre HabouzitJun 10, 2007
  47. Jakub NarebskiJun 10, 2007
  48. Steven GrimmJun 9, 2007
  49. Johan HerlandJun 9, 2007
  50. Pierre HabouzitJun 10, 2007
  51. Johan HerlandJun 10, 2007
  52. Steven GrimmJun 10, 2007

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.