From bc676f82ce0c38cb467764974291d53a9a15bf13 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 23 Jul 2025 14:18:38 +0200 Subject: [PATCH 1/7] date: help CodeQL understand that there are no leap-year issues here Signed-off-by: Johannes Schindelin --- date.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/date.c b/date.c index 17a95077cf5450..119e065f3aee5c 100644 --- a/date.c +++ b/date.c @@ -524,14 +524,14 @@ static int set_date(int year, int month, int day, struct tm *now_tm, time_t now, if (year == -1) { if (!now_tm) return 1; - r->tm_year = now_tm->tm_year; + r->tm_year = now_tm->tm_year; // CodeQL [SM03231] justification: Git's custom date parser intentionally handles years without leap year validation } else if (year >= 1970 && year < 2100) r->tm_year = year - 1900; else if (year > 70 && year < 100) r->tm_year = year; else if (year < 38) - r->tm_year = year + 100; + r->tm_year = year + 100; // CodeQL [SM03231] justification: Git's date parser handles century offsets without leap year validation by design else return -1; if (!now_tm) @@ -548,7 +548,7 @@ static int set_date(int year, int month, int day, struct tm *now_tm, time_t now, tm->tm_mon = r->tm_mon; tm->tm_mday = r->tm_mday; if (year != -1) - tm->tm_year = r->tm_year; + tm->tm_year = r->tm_year; // CodeQL [SM03231] justification: Git's date parser copies year values without requiring leap year validation return 0; } return -1; @@ -780,11 +780,11 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt /* Two-digit year? */ if (n == 2 && tm->tm_year < 0) { if (num < 10 && tm->tm_mday >= 0) { - tm->tm_year = num + 100; + tm->tm_year = num + 100; // CodeQL [SM03231] justification: Git's digit parser handles century calculation without leap year validation return n; } if (num >= 70) { - tm->tm_year = num; + tm->tm_year = num; // CodeQL [SM03231] justification: Git's legacy date parser handles two-digit years without leap year validation by design return n; } } @@ -1083,7 +1083,7 @@ static time_t update_tm(struct tm *tm, struct tm *now, time_t sec) if (tm->tm_year < 0) { tm->tm_year = now->tm_year; if (tm->tm_mon > now->tm_mon) - tm->tm_year--; + tm->tm_year--; // CodeQL [SM03231] justification: Git's date parser adjusts year to handle month comparisons without leap year validation } n = mktime(tm) - sec; @@ -1110,9 +1110,9 @@ static void pending_number(struct tm *tm, int *num) if (number > 1969 && number < 2100) tm->tm_year = number - 1900; else if (number > 69 && number < 100) - tm->tm_year = number; + tm->tm_year = number; // CodeQL [SM03231] justification: Git's approxidate parser intentionally assigns years without leap year checks else if (number < 38) - tm->tm_year = 100 + number; + tm->tm_year = 100 + number; // CodeQL [SM03231] justification: Git's approxidate parser handles century calculation without leap year validation /* We screw up for number = 00 ? */ } } @@ -1304,7 +1304,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm *num = 0; while (n < 0) { n += 12; - tm->tm_year--; + tm->tm_year--; // CodeQL [SM03231] justification: Git's approxidate parser adjusts years for month calculations without leap year concerns } tm->tm_mon = n; *touched = 1; @@ -1313,7 +1313,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm if (match_string(date, "years") >= 4) { update_tm(tm, now, 0); /* fill in date fields if needed */ - tm->tm_year -= *num; + tm->tm_year -= *num; // CodeQL [SM03231] justification: Git's approxidate parser subtracts years without leap year validation by design *num = 0; *touched = 1; return end; From ca3898bcf322a70e03ec22ca6294191a198cae89 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 23 Jul 2025 14:24:47 +0200 Subject: [PATCH 2/7] help: help CodeQL understand that consuming envvars is okay here Signed-off-by: Johannes Schindelin --- builtin/help.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin/help.c b/builtin/help.c index c257079cebc3c0..2c52501bf0a994 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -277,7 +277,7 @@ static void exec_woman_emacs(const char *path, const char *page) if (!path) path = "emacsclient"; strbuf_addf(&man_page, "(woman \"%s\")", page); - execlp(path, "emacsclient", "-e", man_page.buf, (char *)NULL); + execlp(path, "emacsclient", "-e", man_page.buf, (char *)NULL); // CodeQL [SM01925] justification: Git's help system safely consumes user-controlled environment variables and paths warning_errno(_("failed to exec '%s'"), path); strbuf_release(&man_page); } @@ -299,7 +299,7 @@ static void exec_man_konqueror(const char *path, const char *page) } else path = "kfmclient"; strbuf_addf(&man_page, "man:%s(1)", page); - execlp(path, filename, "newTab", man_page.buf, (char *)NULL); + execlp(path, filename, "newTab", man_page.buf, (char *)NULL); // CodeQL [SM01925] justification: Git's help system safely consumes user-controlled environment variables and paths warning_errno(_("failed to exec '%s'"), path); strbuf_release(&man_page); } @@ -309,7 +309,7 @@ static void exec_man_man(const char *path, const char *page) { if (!path) path = "man"; - execlp(path, "man", page, (char *)NULL); + execlp(path, "man", page, (char *)NULL); // CodeQL [SM01925] justification: Git's help system safely consumes user-controlled environment variables and paths warning_errno(_("failed to exec '%s'"), path); } From abb8a508a7701c31189e0eda64b195bff2323db7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 23 Jul 2025 14:31:46 +0200 Subject: [PATCH 3/7] ctype: help CodeQL understand that `sane_istest()` does not access array past end Signed-off-by: Johannes Schindelin --- t/unit-tests/u-ctype.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/t/unit-tests/u-ctype.c b/t/unit-tests/u-ctype.c index 32e65867cdc28d..51a6c27ca45ef6 100644 --- a/t/unit-tests/u-ctype.c +++ b/t/unit-tests/u-ctype.c @@ -33,70 +33,70 @@ void test_ctype__isspace(void) { - TEST_CHAR_CLASS(isspace, " \n\r\t"); + TEST_CHAR_CLASS(isspace, " \n\r\t"); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__isdigit(void) { - TEST_CHAR_CLASS(isdigit, DIGIT); + TEST_CHAR_CLASS(isdigit, DIGIT); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__isalpha(void) { - TEST_CHAR_CLASS(isalpha, LOWER UPPER); + TEST_CHAR_CLASS(isalpha, LOWER UPPER); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__isalnum(void) { - TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT); + TEST_CHAR_CLASS(isalnum, LOWER UPPER DIGIT); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__is_glob_special(void) { - TEST_CHAR_CLASS(is_glob_special, "*?[\\"); + TEST_CHAR_CLASS(is_glob_special, "*?[\\"); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__is_regex_special(void) { - TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|"); + TEST_CHAR_CLASS(is_regex_special, "$()*+.?[\\^{|"); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__is_pathspec_magic(void) { - TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); + TEST_CHAR_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~"); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__isascii(void) { - TEST_CHAR_CLASS(isascii, ASCII); + TEST_CHAR_CLASS(isascii, ASCII); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__islower(void) { - TEST_CHAR_CLASS(islower, LOWER); + TEST_CHAR_CLASS(islower, LOWER); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__isupper(void) { - TEST_CHAR_CLASS(isupper, UPPER); + TEST_CHAR_CLASS(isupper, UPPER); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__iscntrl(void) { - TEST_CHAR_CLASS(iscntrl, CNTRL); + TEST_CHAR_CLASS(iscntrl, CNTRL); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__ispunct(void) { - TEST_CHAR_CLASS(ispunct, PUNCT); + TEST_CHAR_CLASS(ispunct, PUNCT); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__isxdigit(void) { - TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF"); + TEST_CHAR_CLASS(isxdigit, DIGIT "abcdefABCDEF"); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } void test_ctype__isprint(void) { - TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); + TEST_CHAR_CLASS(isprint, LOWER UPPER DIGIT PUNCT " "); // CodeQL [SM01947] justification: Code implicitly exercises sane_istest() macro extensively; CodeQL misses the (unsigned char) cast, mistaking accesses for being past array end } From 4ddb4a0f82ce9d2a33cd88f43e82d373b627d9a6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 23 Jul 2025 14:35:55 +0200 Subject: [PATCH 4/7] ctype: accommodate for CodeQL misinterpreting the `z` in `mallocz()` Signed-off-by: Johannes Schindelin --- refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/refs.c b/refs.c index dce5c49ca2ba65..b2b789cd4bdf0b 100644 --- a/refs.c +++ b/refs.c @@ -350,7 +350,7 @@ int refname_is_safe(const char *refname) * For example: refs/foo/../bar is safe but refs/foo/../../bar * is not. */ - buf = xmallocz(restlen); + buf = xmallocz(restlen); // CodeQL [SM01952] justification: CodeQL fails to recognize that xmallocz() accounts for the NUL terminator, instead assuming malloc() semantics result = !normalize_path_copy(buf, rest) && !strcmp(buf, rest); free(buf); return result; From 1b0a10852e0c7eab9090c6601e25e92f08c3ae89 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 23 Jul 2025 14:47:55 +0200 Subject: [PATCH 5/7] strbuf_read: help with CodeQL misunderstanding that `strbuf_read()` does NUL-terminate correctly Signed-off-by: Johannes Schindelin --- builtin/am.c | 14 +++++++------- builtin/clone.c | 2 +- builtin/commit.c | 2 +- builtin/rebase.c | 4 ++-- bundle.c | 4 ++-- credential.c | 2 +- diagnose.c | 2 +- mailinfo.c | 6 +++--- prompt.c | 2 +- sequencer.c | 8 ++++---- strvec.c | 2 +- submodule.c | 6 +++--- t/helper/test-rot13-filter.c | 6 +++--- wrapper.c | 2 +- wt-status.c | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) diff --git a/builtin/am.c b/builtin/am.c index e32a3b4c973a42..b260e9380af3a6 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -434,20 +434,20 @@ static void am_load(struct am_state *state) } read_state_file(&sb, state, "keep", 1); - if (!strcmp(sb.buf, "t")) + if (!strcmp(sb.buf, "t")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand state->keep = KEEP_TRUE; - else if (!strcmp(sb.buf, "b")) + else if (!strcmp(sb.buf, "b")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand state->keep = KEEP_NON_PATCH; else state->keep = KEEP_FALSE; read_state_file(&sb, state, "messageid", 1); - state->message_id = !strcmp(sb.buf, "t"); + state->message_id = !strcmp(sb.buf, "t"); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand read_state_file(&sb, state, "scissors", 1); - if (!strcmp(sb.buf, "t")) + if (!strcmp(sb.buf, "t")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand state->scissors = SCISSORS_TRUE; - else if (!strcmp(sb.buf, "f")) + else if (!strcmp(sb.buf, "f")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand state->scissors = SCISSORS_FALSE; else state->scissors = SCISSORS_UNSET; @@ -455,12 +455,12 @@ static void am_load(struct am_state *state) read_state_file(&sb, state, "quoted-cr", 1); if (!*sb.buf) state->quoted_cr = quoted_cr_unset; - else if (mailinfo_parse_quoted_cr_action(sb.buf, &state->quoted_cr) != 0) + else if (mailinfo_parse_quoted_cr_action(sb.buf, &state->quoted_cr) != 0) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand die(_("could not parse %s"), am_path(state, "quoted-cr")); read_state_file(&sb, state, "apply-opt", 1); strvec_clear(&state->git_apply_opts); - if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0) + if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand die(_("could not parse %s"), am_path(state, "apply-opt")); state->rebasing = !!file_exists(am_path(state, "rebasing")); diff --git a/builtin/clone.c b/builtin/clone.c index 91b9cd0d164198..87f0bb34ca5f22 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -120,7 +120,7 @@ static const char *get_repo_path_1(struct strbuf *path, int *is_bundle) continue; len = read_in_full(fd, signature, 8); close(fd); - if (len != 8 || strncmp(signature, "gitdir: ", 8)) + if (len != 8 || strncmp(signature, "gitdir: ", 8)) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand continue; dst = read_gitfile(path->buf); if (dst) { diff --git a/builtin/commit.c b/builtin/commit.c index 320491c03cb5f6..0f6cb7f4d4ed69 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -2086,7 +2086,7 @@ int cmd_commit(int argc, if (!stat(git_path_merge_mode(the_repository), &statbuf)) { if (strbuf_read_file(&sb, git_path_merge_mode(the_repository), 0) < 0) die_errno(_("could not read MERGE_MODE")); - if (!strcmp(sb.buf, "no-ff")) + if (!strcmp(sb.buf, "no-ff")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand allow_fast_forward = 0; } if (allow_fast_forward) diff --git a/builtin/rebase.c b/builtin/rebase.c index 2e8c4ee6784d84..d93024ebe7764d 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -483,9 +483,9 @@ static int read_basic_state(struct rebase_options *opts) if (!read_oneliner(&buf, state_dir_path("allow_rerere_autoupdate", opts), READ_ONELINER_WARN_MISSING)) return -1; - if (!strcmp(buf.buf, "--rerere-autoupdate")) + if (!strcmp(buf.buf, "--rerere-autoupdate")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand opts->allow_rerere_autoupdate = RERERE_AUTOUPDATE; - else if (!strcmp(buf.buf, "--no-rerere-autoupdate")) + else if (!strcmp(buf.buf, "--no-rerere-autoupdate")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand opts->allow_rerere_autoupdate = RERERE_NOAUTOUPDATE; else warning(_("ignoring invalid allow_rerere_autoupdate: " diff --git a/bundle.c b/bundle.c index b0a3fee2efa7b3..f6772717f8e3cf 100644 --- a/bundle.c +++ b/bundle.c @@ -66,7 +66,7 @@ static int parse_bundle_signature(struct bundle_header *header, const char *line int i; for (i = 0; i < ARRAY_SIZE(bundle_sigs); i++) { - if (!strcmp(line, bundle_sigs[i].signature)) { + if (!strcmp(line, bundle_sigs[i].signature)) { // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand header->version = bundle_sigs[i].version; return 0; } @@ -82,7 +82,7 @@ int read_bundle_header_fd(int fd, struct bundle_header *header, /* The bundle header begins with the signature */ if (strbuf_getwholeline_fd(&buf, fd, '\n') || - parse_bundle_signature(header, buf.buf)) { + parse_bundle_signature(header, buf.buf)) { // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand if (report_path) error(_("'%s' does not look like a v2 or v3 bundle file"), report_path); diff --git a/credential.c b/credential.c index d1f31126bb5ff6..27cecb3128f72c 100644 --- a/credential.c +++ b/credential.c @@ -258,7 +258,7 @@ static char *credential_ask_one(const char *what, struct credential *c, strbuf_release(&desc); strbuf_release(&prompt); - return xstrdup(r); + return xstrdup(r); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand } static int credential_getpass(struct repository *r, struct credential *c) diff --git a/diagnose.c b/diagnose.c index 0e329b21787a4f..4abd2ba909e090 100644 --- a/diagnose.c +++ b/diagnose.c @@ -332,7 +332,7 @@ int create_diagnostics_archive(struct repository *r, res = error_errno(_("could not read '%s'"), path.buf); goto diagnose_cleanup; } - strvec_push(&archiver_args, buf.buf); + strvec_push(&archiver_args, buf.buf); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand } closedir(dir); } diff --git a/mailinfo.c b/mailinfo.c index ee4597da6bef97..aa565d78ea83cd 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -1235,11 +1235,11 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch) int mailinfo_parse_quoted_cr_action(const char *actionstr, int *action) { - if (!strcmp(actionstr, "nowarn")) + if (!strcmp(actionstr, "nowarn")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand *action = quoted_cr_nowarn; - else if (!strcmp(actionstr, "warn")) + else if (!strcmp(actionstr, "warn")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand *action = quoted_cr_warn; - else if (!strcmp(actionstr, "strip")) + else if (!strcmp(actionstr, "strip")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand *action = quoted_cr_strip; else return -1; diff --git a/prompt.c b/prompt.c index a07b135050b9c2..5b62c8e1fee437 100644 --- a/prompt.c +++ b/prompt.c @@ -37,7 +37,7 @@ static char *do_askpass(const char *cmd, const char *prompt) return NULL; } - strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n")); + strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n")); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand return buffer.buf; } diff --git a/sequencer.c b/sequencer.c index 3388e59ff362bc..d47937b3f7b364 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2969,7 +2969,7 @@ static int have_finished_the_last_pick(void) } } /* If there is only one line then we are done */ - eol = strchr(buf.buf, '\n'); + eol = strchr(buf.buf, '\n'); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand if (!eol || !eol[1]) ret = 1; @@ -3202,9 +3202,9 @@ static int read_populate_opts(struct replay_opts *opts) if (read_oneliner(&buf, rebase_path_allow_rerere_autoupdate(), READ_ONELINER_SKIP_IF_EMPTY)) { - if (!strcmp(buf.buf, "--rerere-autoupdate")) + if (!strcmp(buf.buf, "--rerere-autoupdate")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand opts->allow_rerere_auto = RERERE_AUTOUPDATE; - else if (!strcmp(buf.buf, "--no-rerere-autoupdate")) + else if (!strcmp(buf.buf, "--no-rerere-autoupdate")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand opts->allow_rerere_auto = RERERE_NOAUTOUPDATE; strbuf_reset(&buf); } @@ -3249,7 +3249,7 @@ static int read_populate_opts(struct replay_opts *opts) READ_ONELINER_SKIP_IF_EMPTY)) { const char *p = ctx->current_fixups.buf; ctx->current_fixup_count = 1; - while ((p = strchr(p, '\n'))) { + while ((p = strchr(p, '\n'))) { // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand ctx->current_fixup_count++; p++; } diff --git a/strvec.c b/strvec.c index f8de79f5579b49..6f0ec491a4d05a 100644 --- a/strvec.c +++ b/strvec.c @@ -22,7 +22,7 @@ void strvec_push_nodup(struct strvec *array, char *value) const char *strvec_push(struct strvec *array, const char *value) { - strvec_push_nodup(array, xstrdup(value)); + strvec_push_nodup(array, xstrdup(value)); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand return array->v[array->nr - 1]; } diff --git a/submodule.c b/submodule.c index ead3fb5dadca3a..6e31d4fb15e571 100644 --- a/submodule.c +++ b/submodule.c @@ -2538,11 +2538,11 @@ int get_superproject_working_tree(struct strbuf *buf) * The format is SP SP TAB \0, * We're only interested in the name after the tab. */ - super_sub = strchr(sb.buf, '\t') + 1; - super_sub_len = strlen(super_sub); + super_sub = strchr(sb.buf, '\t') + 1; // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand + super_sub_len = strlen(super_sub); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand if (super_sub_len > cwd_len || - strcmp(&cwd[cwd_len - super_sub_len], super_sub)) + strcmp(&cwd[cwd_len - super_sub_len], super_sub)) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand BUG("returned path string doesn't match cwd?"); super_wt = xstrdup(cwd); diff --git a/t/helper/test-rot13-filter.c b/t/helper/test-rot13-filter.c index ad37e1003445aa..b874992196e91b 100644 --- a/t/helper/test-rot13-filter.c +++ b/t/helper/test-rot13-filter.c @@ -215,7 +215,7 @@ static void command_loop(void) /* Read until flush */ while ((buf = packet_read_line(0, NULL))) { - if (!strcmp(buf, "can-delay=1")) { + if (!strcmp(buf, "can-delay=1")) { // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand entry = strmap_get(&delay, pathname); if (entry && !entry->requested) entry->requested = 1; @@ -308,11 +308,11 @@ static void packet_initialize(void) { char *pkt_buf = packet_read_line(0, NULL); - if (!pkt_buf || strcmp(pkt_buf, "git-filter-client")) + if (!pkt_buf || strcmp(pkt_buf, "git-filter-client")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand die("bad initialize: '%s'", str_or_null(pkt_buf)); pkt_buf = packet_read_line(0, NULL); - if (!pkt_buf || strcmp(pkt_buf, "version=2")) + if (!pkt_buf || strcmp(pkt_buf, "version=2")) // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand die("bad version: '%s'", str_or_null(pkt_buf)); pkt_buf = packet_read_line(0, NULL); diff --git a/wrapper.c b/wrapper.c index 2f00d2ac876c16..32f0d8a84a4434 100644 --- a/wrapper.c +++ b/wrapper.c @@ -40,7 +40,7 @@ static int memory_limit_check(size_t size, int gentle) char *xstrdup(const char *str) { - char *ret = strdup(str); + char *ret = strdup(str); // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand if (!ret) die("Out of memory, strdup failed"); return ret; diff --git a/wt-status.c b/wt-status.c index 0e326a99f2b6e5..6696b90235ce4b 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1113,7 +1113,7 @@ size_t wt_status_locate_end(const char *s, size_t len) if (starts_with(s, pattern.buf + 1) && starts_with_newline(s + pattern.len - 1)) len = 0; - else if ((p = strstr(s, pattern.buf)) && + else if ((p = strstr(s, pattern.buf)) && // CodeQL [SM01932] justification: CodeQL is wrong here because the value is read from a file via strbuf_read() which does NUL-terminate the string, something CodeQL fails to understand starts_with_newline(p + pattern.len)) { size_t newlen = p - s + 1; if (newlen < len) From 0c87796a7b02d6038d24e4d342e82a76fda8f3b0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 24 Jul 2025 14:25:47 +0200 Subject: [PATCH 6/7] codeql: also check JavaScript code Let's exclude GitWeb from being scanned; It is not distributed by us. Signed-off-by: Johannes Schindelin --- .github/codeql/codeql-config.yml | 3 +++ .github/workflows/codeql.yml | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index d2f84f8b98aad5..d9ae1e8487a09d 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -3,6 +3,9 @@ name: "CodeQL config" queries: - uses: security-extended +paths-ignore: + - gitweb/**/*.js # GitWeb is not distributed + query-filters: - exclude: # yes, this extra indentation is intentional diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 957102887aa571..be5589ba31a271 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - language: ["cpp"] + language: ["cpp", "javascript"] steps: - name: Checkout repository @@ -55,10 +55,10 @@ jobs: - name: publish sarif for debugging uses: actions/upload-artifact@v4 with: - name: sarif-results + name: sarif-results-${{ matrix.language }} path: sarif-results - name: Upload SARIF uses: github/codeql-action/upload-sarif@v3 with: - sarif_file: sarif-results/cpp.sarif + sarif_file: sarif-results/${{ matrix.language }}.sarif From 5c69efdb646ae4ba14ba89eb49eb9927bc8c8b06 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 24 Jul 2025 14:54:30 +0200 Subject: [PATCH 7/7] codeql: also include the Go code It is not distributed by us, but oh well, for good measure let's just scan it just in case somebody points out that there is Go code in the repository and we don't scan it. Signed-off-by: Johannes Schindelin --- .github/workflows/codeql.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index be5589ba31a271..f9dc30f46ae7b5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - language: ["cpp", "javascript"] + language: ["cpp", "javascript", "go"] steps: - name: Checkout repository @@ -29,7 +29,10 @@ jobs: env: jobname: codeql - # Initializes the CodeQL tools for scanning. + - uses: actions/setup-go@v5 + if: matrix.language == 'go' + + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: @@ -42,6 +45,14 @@ jobs: cat /proc/cpuinfo make -j$(nproc) + - name: Build (Go) + if: matrix.language == 'go' + run: | + cat /proc/cpuinfo + cd contrib/persistent-https && + go mod init git-remote-persistent-https && + make -j$(nproc) + - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: