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

[PATCH] attr: fix off-by-one directory component length calculation

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Jan 15, 2013, 13:35 UTC
Message-ID
<1358256924-31578-1-git-send-email-pclouds@gmail.com>

94bc671 (Add directory pattern matching to attributes - 2012-12-08) uses find_basename() to calculate the length of directory part in prepare_attr_stack. This function expects the directory without the trailing slash (as "origin" field in match_attr struct is without the trailing slash). find_basename() includes the trailing slash and confuses push/pop algorithm.

Consider path = "abc/def" and the push down code:
	while (1) {
		len = strlen(attr_stack->origin);
		if (dirlen <= len)
			break;
		cp = memchr(path + len + 1, '/', dirlen - len - 1);
		if (!cp)
			cp = path + dirlen;

dirlen is 4, not 3, without this patch. So when attr_stack->origin is "abc", it'll miss the exit condition because 4 <= 3 is wrong. It'll then try to push "abc/" down the attr stack (because "cp" would be NULL). So we have both "abc" and "abc/" in the stack.

Next time when "abc/ghi" is checked, "abc/" is popped out because of the off-by-one dirlen, only to be pushed back in again by the above code. This repeats for all files in the same directory. Which means at least one failed open syscall per file, or more if .gitattributes exists.

This is the perf result with 10 runs on git.git:

Test 94bc671^ 94bc671 HEAD ---------------------------------------------------------------------------------------------------------- 7810.1: grep worktree, cheap regex 0.02(0.01+0.04) 0.05(0.03+0.05) +150.0% 0.02(0.01+0.04) +0.0% 7810.2: grep worktree, expensive regex 0.25(0.94+0.01) 0.26(0.94+0.02) +4.0% 0.25(0.93+0.02) +0.0% 7810.3: grep --cached, cheap regex 0.11(0.10+0.00) 0.12(0.10+0.02) +9.1% 0.10(0.10+0.00) -9.1% 7810.4: grep --cached, expensive regex 0.61(0.60+0.01) 0.62(0.61+0.01) +1.6% 0.61(0.60+0.00) +0.0%

Reported-by: Ross Lagerwall <rosslagerwall@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 This may be an indication that our perf framework is never actively used :-(
 attr.c | 7 +++++++
 1 file changed, 7 insertions(+)
diff --git a/attr.c b/attr.c
index 466c93f..bb9a470 100644
--- a/attr.c
+++ b/attr.c
@@ -584,6 +584,13 @@ static void prepare_attr_stack(const char *path)
 	dirlen = find_basename(path) - path;
 
 	/*
+	 * find_basename() includes the trailing slash, but we do
+	 * _not_ want it.
+	 */
+	if (dirlen)
+		dirlen--;
+
+	/*
 	 * At the bottom of the attribute stack is the built-in
 	 * set of attribute definitions, followed by the contents
 	 * of $(prefix)/etc/gitattributes and a file specified by
-- 
1.8.0.rc2.23.g1fb49df
Next: Junio C Hamano
Message 1 of 32 in “attr: fix off-by-one directory component length calculation”
  1. attr: fix off-by-one directory component length calculationNguyễn Thái Ngọc Duy, Jan 15, 2013
  2. Junio C HamanoJan 15, 2013
  3. Jean-Noël AVILAJan 15, 2013
  4. Junio C HamanoJan 15, 2013
  5. Jean-Noël AVILAJan 15, 2013
  6. Junio C HamanoJan 15, 2013
  7. Jeff KingJan 15, 2013
  8. Torsten BögershausenJan 16, 2013
  9. Jean-Noël AVILAJan 17, 2013
  10. Jonathan NiederJan 18, 2013
  11. Junio C HamanoJan 18, 2013
  12. Torsten BögershausenJan 18, 2013
  13. Junio C HamanoJan 18, 2013
  14. Junio C HamanoJan 18, 2013
  15. Jean-Noël AVILAJan 18, 2013
  16. Junio C HamanoJan 18, 2013
  17. Junio C HamanoJan 18, 2013
  18. Torsten BögershausenJan 19, 2013
  19. Re* t9902 failsJunio C Hamano, Jan 19, 2013
  20. 1/2 help: include <common-cmds.h> only in one fileJunio C Hamano, Jan 19, 2013
  21. 2/2 help --standard: list standard commandsJunio C Hamano, Jan 19, 2013
  22. Jean-Noël AVILAJan 19, 2013
  23. Jean-Noël AVILAJan 19, 2013
  24. Jean-Noël AVILAJan 19, 2013
  25. Duy NguyenJan 16, 2013
  26. Duy NguyenJan 16, 2013
  27. Junio C HamanoJan 16, 2013
  28. Duy NguyenJan 16, 2013
  29. Junio C HamanoJan 16, 2013
  30. Duy NguyenJan 16, 2013
  31. Junio C HamanoJan 16, 2013
  32. Duy NguyenJan 16, 2013

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.