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(©str); } - 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