Blob Blame History Raw
diff -ur b/apply.c a/apply.c
--- b/apply.c	2020-06-01 17:49:27.000000000 +0200
+++ a/apply.c	2023-05-03 13:53:00.200547081 +0200
@@ -4516,7 +4516,7 @@
 	FILE *rej;
 	char namebuf[PATH_MAX];
 	struct fragment *frag;
-	int cnt = 0;
+	int fd, cnt = 0;
 	struct strbuf sb = STRBUF_INIT;
 
 	for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
@@ -4556,7 +4556,17 @@
 	memcpy(namebuf, patch->new_name, cnt);
 	memcpy(namebuf + cnt, ".rej", 5);
 
-	rej = fopen(namebuf, "w");
+	fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+	if (fd < 0) {
+		if (errno != EEXIST)
+			return error_errno(_("cannot open %s"), namebuf);
+		if (unlink(namebuf))
+			return error_errno(_("cannot unlink '%s'"), namebuf);
+		fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+		if (fd < 0)
+			return error_errno(_("cannot open %s"), namebuf);
+	}
+	rej = fdopen(fd, "w");
 	if (!rej)
 		return error_errno(_("cannot open %s"), namebuf);
 
diff -ur b/builtin/clone.c a/builtin/clone.c
--- b/builtin/clone.c	2020-06-01 17:49:27.000000000 +0200
+++ a/builtin/clone.c	2023-05-03 13:52:23.803339233 +0200
@@ -248,6 +248,15 @@
 		while (start < end && is_dir_sep(end[-1]))
 			end--;
 	}
+	
+	/*
+	 * It should not be possible to overflow `ptrdiff_t` by passing in an
+	 * insanely long URL, but GCC does not know that and will complain
+	 * without this check.
+	 */
+	if (end - start < 0)
+		die(_("No directory name could be guessed.\n"
+		      "Please specify a directory on the command line"));
 
 	/*
 	 * Strip trailing port number if we've got only a
diff -ur b/compat/nedmalloc/nedmalloc.c a/compat/nedmalloc/nedmalloc.c
--- b/compat/nedmalloc/nedmalloc.c	2020-06-01 17:49:27.000000000 +0200
+++ a/compat/nedmalloc/nedmalloc.c	2023-05-03 13:51:33.546052246 +0200
@@ -323,7 +323,6 @@
 }
 static void DestroyCaches(nedpool *p) THROWSPEC
 {
-	if(p->caches)
 	{
 		threadcache *tc;
 		int n;
diff -ur b/compat/win32/syslog.c a/compat/win32/syslog.c
--- b/compat/win32/syslog.c	2020-06-01 17:49:27.000000000 +0200
+++ a/compat/win32/syslog.c	2023-05-03 13:51:35.154061429 +0200
@@ -43,6 +43,7 @@
 	va_end(ap);
 
 	while ((pos = strstr(str, "%1")) != NULL) {
+		size_t offset = pos - str;
 		char *oldstr = str;
 		str = realloc(str, st_add(++str_len, 1));
 		if (!str) {
@@ -50,6 +51,7 @@
 			warning_errno("realloc failed");
 			return;
 		}
+		pos = str + offset;
 		memmove(pos + 2, pos + 1, strlen(pos));
 		pos[1] = ' ';
 	}
diff -ur b/config.c a/config.c
--- b/config.c	2020-06-01 17:49:27.000000000 +0200
+++ a/config.c	2023-05-03 13:50:49.378800030 +0200
@@ -3009,9 +3009,10 @@
 					multi_replace);
 }
 
-static int section_name_match (const char *buf, const char *name)
+static size_t section_name_match (const char *buf, const char *name)
 {
-	int i = 0, j = 0, dot = 0;
+	size_t i = 0, j = 0;
+	int dot = 0;
 	if (buf[i] != '[')
 		return 0;
 	for (i = 1; buf[i] && buf[i] != ']'; i++) {
@@ -3064,6 +3065,8 @@
 	return 1;
 }
 
+#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
+
 /* if new_name == NULL, the section is removed instead */
 static int git_config_copy_or_rename_section_in_file(const char *config_filename,
 				      const char *old_name,
@@ -3073,11 +3076,12 @@
 	char *filename_buf = NULL;
 	struct lock_file lock = LOCK_INIT;
 	int out_fd;
-	char buf[1024];
+	struct strbuf buf = STRBUF_INIT;
 	FILE *config_file = NULL;
 	struct stat st;
 	struct strbuf copystr = STRBUF_INIT;
 	struct config_store_data store;
+	uint32_t line_nr = 0;
 
 	memset(&store, 0, sizeof(store));
 
@@ -3114,16 +3118,25 @@
 		goto out;
 	}
 
-	while (fgets(buf, sizeof(buf), config_file)) {
-		int i;
-		int length;
+	while (!strbuf_getwholeline(&buf, config_file, '\n')) {
+		size_t i, length;
 		int is_section = 0;
-		char *output = buf;
-		for (i = 0; buf[i] && isspace(buf[i]); i++)
+		char *output = buf.buf;
+
+		line_nr++;
+
+		if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) {
+			ret = error(_("refusing to work with overly long line "
+				      "in '%s' on line %"PRIuMAX),
+				    config_filename, (uintmax_t)line_nr);
+			goto out;
+		}
+
+		for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++)
 			; /* do nothing */
-		if (buf[i] == '[') {
+		if (buf.buf[i] == '[') {
 			/* it's a section */
-			int offset;
+			size_t offset;
 			is_section = 1;
 
 			/*
@@ -3140,7 +3153,7 @@
 				strbuf_reset(&copystr);
 			}
 
-			offset = section_name_match(&buf[i], old_name);
+			offset = section_name_match(&buf.buf[i], old_name);
 			if (offset > 0) {
 				ret++;
 				if (new_name == NULL) {
@@ -3215,6 +3228,7 @@
 out_no_rollback:
 	free(filename_buf);
 	config_store_data_clear(&store);
+	strbuf_release(&buf);
 	return ret;
 }
 
diff -ur b/gettext.c a/gettext.c
--- b/gettext.c	2020-06-01 17:49:27.000000000 +0200
+++ a/gettext.c	2023-05-03 13:47:46.953758294 +0200
@@ -173,6 +173,8 @@
 		setlocale(LC_CTYPE, "C");
 }
 
+int git_gettext_enabled = 0;
+
 void git_setup_gettext(void)
 {
 	const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
@@ -194,6 +196,8 @@
 	init_gettext_charset("git");
 	textdomain("git");
 
+	git_gettext_enabled = 1;
+	
 	free(p);
 }
 
diff -ur b/gettext.h a/gettext.h
--- b/gettext.h	2020-06-01 17:49:27.000000000 +0200
+++ a/gettext.h	2023-05-03 13:46:54.234457247 +0200
@@ -31,9 +31,11 @@
 int use_gettext_poison(void);
 
 #ifndef NO_GETTEXT
+extern int git_gettext_enabled;
 void git_setup_gettext(void);
 int gettext_width(const char *s);
 #else
+#define git_gettext_enabled (0)
 static inline void git_setup_gettext(void)
 {
 	use_gettext_poison(); /* getenv() reentrancy paranoia */
@@ -48,7 +50,8 @@
 {
 	if (!*msgid)
 		return "";
-	return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid);
+	return use_gettext_poison() ? "# GETTEXT POISON #" :
+		!git_gettext_enabled ? msgid : gettext(msgid);
 }
 
 static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
@@ -56,6 +59,8 @@
 {
 	if (use_gettext_poison())
 		return "# GETTEXT POISON #";
+	if (!git_gettext_enabled)
+		return n == 1 ? msgid : plu;
 	return ngettext(msgid, plu, n);
 }
 
diff -ur b/range-diff.c a/range-diff.c
--- b/range-diff.c	2020-06-01 17:49:27.000000000 +0200
+++ a/range-diff.c	2023-05-03 13:44:54.980776256 +0200
@@ -25,17 +25,6 @@
 	struct object_id oid;
 };
 
-static size_t find_end_of_line(char *buffer, unsigned long size)
-{
-	char *eol = memchr(buffer, '\n', size);
-
-	if (!eol)
-		return size;
-
-	*eol = '\0';
-	return eol + 1 - buffer;
-}
-
 /*
  * Reads the patches into a string list, with the `util` field being populated
  * as struct object_id (will need to be free()d).
@@ -48,7 +37,7 @@
 	struct patch_util *util = NULL;
 	int in_header = 1;
 	char *line, *current_filename = NULL;
-	int offset, len;
+	ssize_t len;
 	size_t size;
 
 	argv_array_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges",
@@ -83,11 +72,18 @@
 
 	line = contents.buf;
 	size = contents.len;
-	for (offset = 0; size > 0; offset += len, size -= len, line += len) {
+	for (; size > 0; size -= len, line += len) {
 		const char *p;
+		char *eol;
+
+		eol = memchr(line, '\n', size);
+		if (eol) {
+			*eol = '\0';
+			len = eol + 1 - line;
+		} else {
+			len = size;
+		}
 
-		len = find_end_of_line(line, size);
-		line[len - 1] = '\0';
 		if (skip_prefix(line, "commit ", &p)) {
 			if (util) {
 				string_list_append(list, buf.buf)->util = util;
@@ -129,7 +125,8 @@
 			strbuf_addch(&buf, '\n');
 			if (!util->diff_offset)
 				util->diff_offset = buf.len;
-			line[len - 1] = '\n';
+			if (eol)
+				*eol = '\n';
 			orig_len = len;
 			len = parse_git_diff_header(&root, &linenr, 0, line,
 						    len, size, &patch);
diff -ur b/t/t1300-config.sh a/t/t1300-config.sh
--- b/t/t1300-config.sh	2020-06-01 17:49:27.000000000 +0200
+++ a/t/t1300-config.sh	2023-05-03 13:39:43.864071831 +0200
@@ -616,6 +616,36 @@
 	test_must_fail git config --rename-section branch.zwei "bogus name"
 '
 
+test_expect_success 'renaming a section with a long line' '
+	{
+		printf "[b]\\n" &&
+		printf "  c = d %1024s [a] e = f\\n" " " &&
+		printf "[a] g = h\\n"
+	} >y &&
+	git config -f y --rename-section a xyz &&
+	test_must_fail git config -f y b.e
+'
+
+test_expect_success 'renaming an embedded section with a long line' '
+	{
+		printf "[b]\\n" &&
+		printf "  c = d %1024s [a] [foo] e = f\\n" " " &&
+		printf "[a] g = h\\n"
+	} >y &&
+	git config -f y --rename-section a xyz &&
+	test_must_fail git config -f y foo.e
+'
+
+test_expect_success 'renaming a section with an overly-long line' '
+	{
+		printf "[b]\\n" &&
+		printf "  c = d %525000s e" " " &&
+		printf "[a] g = h\\n"
+	} >y &&
+	test_must_fail git config -f y --rename-section a xyz 2>err &&
+	test_i18ngrep "refusing to work with overly long line in .y. on line 2" err
+'
+
 cat >> .git/config << EOF
   [branch "zwei"] a = 1 [branch "vier"]
 EOF
diff -ur b/t/t4115-apply-symlink.sh a/t/t4115-apply-symlink.sh
--- b/t/t4115-apply-symlink.sh	2020-06-01 17:49:27.000000000 +0200
+++ a/t/t4115-apply-symlink.sh	2023-05-03 13:39:01.453839938 +0200
@@ -44,4 +44,17 @@
 
 '
 
+test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' '
+	test_when_finished "git reset --hard && git clean -dfx" &&
+	test_commit file &&
+	echo modified >file.t &&
+	git diff -- file.t >patch &&
+	echo modified-again >file.t &&
+	ln -s foo file.t.rej &&
+	test_must_fail git apply patch --reject 2>err &&
+	test_i18ngrep "Rejected hunk" err &&
+	test_path_is_missing foo &&
+	test_path_is_file file.t.rej
+'
+
 test_done
Only in a: .vscode