summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2025-01-13object-name: be more strict in parsing describe-like outputElijah Newren2-1/+78
From Documentation/revisions.txt: '<describeOutput>', e.g. 'v1.7.4.2-679-g3bee7fb':: Output from `git describe`; i.e. a closest tag, optionally followed by a dash and a number of commits, followed by a dash, a 'g', and an abbreviated object name. which means that output of the format ${REFNAME}-${INTEGER}-g${HASH} should parse to fully expanded ${HASH}. This is fine. However, we currently don't validate any of ${REFNAME}-${INTEGER}, we only parse -g${HASH} and assume the rest is valid. That is problematic, since it breaks things like git cat-file -p branchname:path/to/file/named/i-gaffed which, when commit (or tree or blob) affed exists, will not return us information about the file we are looking for but will instead erroneously tell us about object affed. A few additional notes: - This is a slight backward incompatibility break, because we used to allow ${GARBAGE}-g${HASH} as a way to spell ${HASH}. However, a backward incompatible break is necessary, because there is no other way for someone to be more specific and disambiguate that they want the blob master:path/to/who-gabbed instead of the object abbed. - There is a possibility that check_refname_format() rules change in the future. However, we can only realistically loosen the rules for what that function accepts rather than tighten. If we were to tighten the rules, some real world repositories may already have refnames that suddenly become unacceptable and we break those repositories. As such, any describe-like syntax of the form ${VALID_FOR_A_REFNAME}-${INTEGER}-g${HASH} that is valid with the changes in this commit will remain valid in the future. - The fact that check_refname_format() rules could loosen in the future is probably also an important reason to make this change. If the rules loosen, there might be additional cases within ${GARBAGE}-g${HASH} that become ambiguous in the future. While abbreviated hashes can be disambiguated by abbreviating less, it may well be that these alternative object names have no way of being disambiguated (much like pathnames cannot be). Accepting all random ${GARBAGE} thus makes it difficult for us to allow future extensions to object naming. So, tighten up the parsing to make sure ${REFNAME} and ${INTEGER} are present in the string, and would be considered a valid ref and non-negative integer. Also, add a few tests for git describe using object names of the form ${REVISION_NAME}${MODIFIERS} since an early version of this patch failed on constructs like git describe v2.48.0-rc2-161-g6c2274cdbc^0 Reported-by: Gabriel Amaral <gabriel-amaral@github.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-13object-name: fix resolution of object names containing curly bracesElijah Newren2-4/+35
Given a branch name of 'foo{bar', commands like git cat-file -p foo{bar:README.md should succeed (assuming that branch had a README.md file, of course). However, the change in cce91a2caef9 (Change 'master@noon' syntax to 'master@{noon}'., 2006-05-19) presumed that curly braces would always come after an '@' or '^' and be paired, causing e.g. 'foo{bar:README.md' to entirely miss the ':' and assume there's no object being referenced. In short, git would report: fatal: Not a valid object name foo{bar:README.md Change the parsing to only make the assumption of paired curly braces immediately after either a '@' or '^' character appears. Add tests for this, as well as for a few other test cases that initial versions of this patch broke: * 'foo@@{...}' * 'foo^{/${SEARCH_TEXT_WITH_COLON}}:${PATH}' Note that we'd prefer not duplicating the special logic for "@^" characters here, because if get_oid_basic() or interpret_nth_prior_checkout() or get_oid_basic() or similar gain extra methods of using curly braces, then the logic in get_oid_with_context_1() would need to be updated as well. But it's not clear how to refactor all of these to have a simple common callpoint with the specialized logic. Reported-by: Gabriel Amaral <gabriel-amaral@github.com> Helped-by: Michael Haggerty <mhagger@github.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-13Merge branch 'ps/meson-weak-sha1-build' into ps/build-meson-fixesJunio C Hamano2-15/+44
* ps/meson-weak-sha1-build: meson: provide a summary of configured backends meson: wire up unsafe SHA1 backend meson: add missing dots for build options meson: simplify conditions for HTTPS and SHA1 dependencies meson: require SecurityFramework when it's used as SHA1 backend meson: deduplicate access to SHA1/SHA256 backend options meson: consistenlty spell 'CommonCrypto'
2025-01-13help: interpret boolean string values for help.autocorrectScott Chacon2-16/+35
A help.autocorrect value of 1 is currently interpreted as "wait 1 decisecond", which can be confusing to users who believe they are setting a boolean value to turn the autocorrect feature on. Interpret the value of help.autocorrect as either one of the accepted list of special values ("never", "immediate", ...), a boolean or an integer. If the value is 1, it is no longer interpreted as a decisecond value of 0.1s but as a true boolean, the equivalent of "immediate". If the value is 2 or more, continue treating it as a decisecond wait time. False boolean string values ("off", "false", "no") are now equivalent to "never", meaning that guessed values are still shown but nothing is executed. True boolean string values are interpreted as "immediate". Signed-off-by: Scott Chacon <schacon@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-11gitk: make the "list references" default window width widerJames J. Raden1-1/+1
When using remotes (with git-flow especially), the remote reference names are almost always wordwrapped in the "list references" window because it's somewhat narrow by default. It's possible to resize it with a mouse, but it's annoying to have to do this every time, especially on Windows 10, where the window border seems to be only one (1) pixel wide, thus making the grabbing of the window border tricky. Signed-off-by: James J. Raden <james.raden@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-01-11gitk: fix arrow keys in input fields with Tcl/Tk >= 8.6Johannes Schindelin1-3/+9
Tcl/Tk 8.6 introduced new events for the cursor left/right keys and apparently changed the behavior of the previous event. Let's work around that by using the new events when we are running with Tcl/Tk 8.6 or later. This fixes https://github.com/git-for-windows/git/issues/495 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-01-11gitk: Use an external icon file on WindowsSebastian Schuberth1-19/+22
Git for Windows now ships with the new Git icon from git-scm.com. Use that icon file if it exists instead of the old procedurally drawn one. This patch was sent upstream but so far no decision on its inclusion was made, so commit it to our fork. Signed-off-by: Sebastian Schuberth <sschuberth@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-01-11gitk: Unicode file name supportKarsten Blees1-7/+8
Assumes file names in git tree objects are UTF-8 encoded. On most unix systems, the system encoding (and thus the TCL system encoding) will be UTF-8, so file names will be displayed correctly. On Windows, it is impossible to set the system encoding to UTF-8. Changing the TCL system encoding (via 'encoding system ...', e.g. in the startup code) is explicitly discouraged by the TCL docs. Change gitk functions dealing with file names to always convert from and to UTF-8. Signed-off-by: Karsten Blees <blees@dcon.de> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-01-11gitk(Windows): avoid inadvertently calling executables in the worktreeJohannes Schindelin1-0/+135
Just like CVE-2022-41953 for Git GUI, there exists a vulnerability of `gitk` where it looks for `taskkill.exe` in the current directory before searching `PATH`. Note that the many `exec git` calls are unaffected, due to an obscure quirk in Tcl's `exec` function. Typically, `git.exe` lives next to `wish.exe` (i.e. the program that is run to execute `gitk` or Git GUI) in Git for Windows, and that is the saving grace for `git.exe because `exec` searches the directory where `wish.exe` lives even before the current directory, according to https://www.tcl-lang.org/man/tcl/TclCmd/exec.htm#M24: If a directory name was not specified as part of the application name, the following directories are automatically searched in order when attempting to locate the application: The directory from which the Tcl executable was loaded. The current directory. The Windows 32-bit system directory. The Windows home directory. The directories listed in the path. The same is not true, however, for `taskkill.exe`: it lives in the Windows system directory (never mind the 32-bit, Tcl's documentation is outdated on that point, it really means `C:\Windows\system32`). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-01-10instaweb: fix ip binding for the python http.serverAlecs King1-2/+2
`git instaweb -d python` should bind the server to 0.0.0.0, while `git instaweb -d python -l` should bind the server to 127.0.0.1. The code had them backwards by mistake since 2eb14bb2d4 (git-instaweb: add Python builtin http.server support, 2019-01-28). Signed-off-by: Alecs King <alecsk@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10doc: convert git-restore to new style formatJean-Noël Avila1-54/+54
- Switch the synopsis to a 'synopsis' block which will automatically format placeholders in italics and keywords in monospace - Use _<placeholder>_ instead of <placeholder> in the description - Use backticks for keywords and more complex option descriptions. The new rendering engine will apply synopsis rules to these spans. While at it, also convert an option description to imperative mood. Signed-off-by: Jean-Noël Avila <jn.avila@free.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10doc: convert git-notes to new documentation formatJean-Noël Avila2-110/+111
- Switch the synopsis to a synopsis block which will automatically format placeholders in italics and keywords in monospace - Use _<placeholder>_ instead of <placeholder> in the description - Use `backticks` for keywords and more complex option descriptions. The new rendering engine will apply synopsis rules to these spans. Signed-off-by: Jean-Noël Avila <jn.avila@free.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10Merge branch 'ps/meson-weak-sha1-build' into ps/zlib-ngJunio C Hamano2-15/+44
* ps/meson-weak-sha1-build: meson: provide a summary of configured backends meson: wire up unsafe SHA1 backend meson: add missing dots for build options meson: simplify conditions for HTTPS and SHA1 dependencies meson: require SecurityFramework when it's used as SHA1 backend meson: deduplicate access to SHA1/SHA256 backend options meson: consistenlty spell 'CommonCrypto'
2025-01-10docs: discuss caching personal access tokensM Hickford1-0/+17
Describe problems storing personal access tokens in git-credential-cache and suggest alternatives. Research suggests that many users are confused about this: > the point of passwords is that (ideally) you memorise them [so] > they're never stored anywhere in plain text. Yet GitHub's personal > access token system seems to basically force you to store the token in > plain text? https://stackoverflow.com/questions/46645843/where-to-store-my-git-personal-access-token#comment89963004_46645843 Signed-off-by: M Hickford <mirth.hickford@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10docs: list popular credential helpersM Hickford1-12/+29
git-credential-store saves credentials unencrypted on disk. It is the least secure choice of credential helper. Nevertheless, it appears several times more popular than any other credential helper [1]. Inform users about more secure alternatives. [1] https://stackoverflow.com/questions/35942754/how-can-i-save-username-and-password-in-git Signed-off-by: M Hickford <mirth.hickford@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10Git 2.48v2.48.0Junio C Hamano1-1/+1
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10Merge branch 'ps/build-sign-compare'Junio C Hamano2-4/+31
Last-minute fix for a regression in "git blame --abbrev=<length>" when insane <length> is specified; we used to correctly cap it to the hash output length but broke it during the cycle. * ps/build-sign-compare: builtin/blame: fix out-of-bounds write with blank boundary commits builtin/blame: fix out-of-bounds read with excessive `--abbrev`
2025-01-10Merge branch 'js/git-version-gen-update'Junio C Hamano1-4/+4
Build regression fix. * js/git-version-gen-update: GIT-VERSION-GEN: allow it to be run in parallel
2025-01-10ci: remove stale code for Azure PipelinesPatrick Steinhardt2-25/+1
Support for Azure Pipelines has been retired in 6081d3898f (ci: retire the Azure Pipelines definition, 2020-04-11) in favor of GitHub Actions. Our CI library still has some infrastructure left for Azure though that is now unused. Remove it. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10ci: use latest Ubuntu releasePatrick Steinhardt2-14/+14
Both GitHub Actions and GitLab CI use the "ubuntu:latest" tag as the default image for most jobs. This tag is somewhat misleading though, as it does not refer to the latest release of Ubuntu, but to the latest LTS release thereof. But as we already have a couple of jobs exercising the oldest LTS release of Ubuntu that Git still supports, it would make more sense to test the oldest and youngest versions of Ubuntu. Adapt these jobs to instead use the "ubuntu:rolling" tag, which refers to the actual latest release, which currently is Ubuntu 24.10. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10ci: stop special-casing for Ubuntu 16.04Patrick Steinhardt1-8/+1
With c85bcb5de1 (gitlab-ci: switch from Ubuntu 16.04 to 20.04, 2024-10-31) we have adapted the last CI job to stop using Ubuntu 16.04 in favor of Ubuntu 20.04. Remove the special-casing we still have in our CI scripts. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10gitlab-ci: add linux32 job testing against i386Patrick Steinhardt2-1/+3
Add another job to GitLab CI that tests against the i386 architecture. This job is equivalent to the same job in GitHub Workflows. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10gitlab-ci: remove the "linux-old" jobPatrick Steinhardt1-3/+0
The "linux-old" job was historically testing against the oldest supported LTS release of Ubuntu. But with c85bcb5de1 (gitlab-ci: switch from Ubuntu 16.04 to 20.04, 2024-10-31) it has been converted to test against Ubuntu 20.04, which already gets exercised in a couple of other CI jobs. It's thus not adding any significant test coverage. Drop the job. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10github: simplify computation of the job's distroPatrick Steinhardt3-20/+8
We explicitly list the distro of Linux-based jobs, but it is equivalent to the name of the image in almost all cases, except that colons are replaced with dashes. Drop the redundant information and massage it in our CI scripts, which is equivalent to how we do it in GitLab CI. There are a couple of exceptions: - The "linux32" job, whose distro name is different than the image name. This is handled by adapting all sites to use the new name. - The "alpine" and "fedora" jobs, neither of which specify a tag for their image. This is handled by adding the "latest" tag. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10github: convert all Linux jobs to be containerizedPatrick Steinhardt1-29/+39
We have split the CI jobs in GitHub Workflows into two categories: - Those running on a machine pool directly. - Those running in a container on the machine pool. The latter is more flexible because it allows us to freely pick whatever container image we want to use for a specific job, while the former only allows us to pick from a handful of different distros. The containerized jobs do not have any significant downsides to the best of my knowledge: - They aren't significantly slower to start up. A quick comparison by Peff shows that the difference is mostly lost in the noise: job | old | new --------------------|------|------ linux-TEST-vars 11m30s 10m54s linux-asan-ubsan 30m26s 31m14s linux-gcc 9m47s 10m6s linux-gcc-default 9m47s 9m41s linux-leaks 25m50s 25m21s linux-meson 10m36s 10m41s linux-reftable 10m25s 10m23s linux-reftable-leaks 27m18s 27m28s linux-sha256 9m54s 10m31s Some jobs are a bit faster, some are a bit slower, but there does not seem to be any significant change. - Containerized jobs run as root, which keeps a couple of tests from running. This has been addressed in the preceding commit though, where we now use setpriv(1) to run tests as a separate user. - GitHub injects a Node binary into containerized jobs, which is dynamically linked. This has led to some issues in the past [1], but only for our 32 bit jobs. The issues have since been resolved. Overall there seem to be no downsides, but the upside is that we have more control over the exact image that these jobs use. Convert the Linux jobs accordingly. [1]: https://lore.kernel.org/git/20240912094841.GD589828@coredump.intra.peff.net/ Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10github: adapt containerized jobs to be rootlessPatrick Steinhardt2-3/+5
The containerized jobs in GitHub Actions run as root, giving them special permissions to for example delete files even when the user shouldn't be able to due to file permissions. This limitation keeps us from using containerized jobs for most of our Ubuntu-based jobs as it causes a number of tests to fail. Adapt the jobs to create a separate user that executes the test suite. This follows similar infrastructure that we already have in GitLab CI. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10t7422: fix flaky test caused by buffered stdoutPatrick Steinhardt1-4/+39
One test in t7422 asserts that `git submodule status --recursive` properly handles SIGPIPE. This test is flaky though and may sometimes not see a SIGPIPE at all: expecting success of 7422.18 'git submodule status --recursive propagates SIGPIPE': { git submodule status --recursive 2>err; echo $?>status; } | grep -q X/S && test_must_be_empty err && test_match_signal 13 "$(cat status)" ++ git submodule status --recursive ++ grep -q X/S ++ echo 0 ++ test_must_be_empty err ++ test 1 -ne 1 ++ test_path_is_file err ++ test 1 -ne 1 ++ test -f err ++ test -s err +++ cat status ++ test_match_signal 13 0 ++ test 0 = 141 ++ test 0 = 269 ++ return 1 error: last command exited with $?=1 not ok 18 - git submodule status --recursive propagates SIGPIPE The issue is caused by a race between git-submodule(1) and grep(1): 1. git-submodule(1) (or its child process) writes the first X/S line we're trying to match. 2. grep(1) matches the line. 3a. grep(1) exits, closing the pipe. 3b. git-submodule(1) (or its child process) writes the rest of its lines. Steps 3a and 3b happen at the same time without any guarantees. If 3a happens first, we get SIGPIPE. Otherwise, we don't and the test fails. Fix the issue by generating a couple thousand nested submodules and matching on the first nested submodule. This ensures that the recursive git-submodule(1) process completely fills its stdout buffer, which makes subsequent writes block until the downstream consumer of the pipe either reads more or closes it. To verify that this works as expected one can apply the following patch to the preimage of this commit, which used to reliably trigger the race: diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh index 3c5177cc30..df6001f8a0 100755 --- a/t/t7422-submodule-output.sh +++ b/t/t7422-submodule-output.sh @@ -202,7 +202,7 @@ test_expect_success !MINGW 'git submodule status --recursive propagates SIGPIPE' cd repo && GIT_ALLOW_PROTOCOL=file git submodule add "$(pwd)"/../submodule && { git submodule status --recursive 2>err; echo $?>status; } | - grep -q recursive-submodule-path-1 && + { sleep 1 && grep -q recursive-submodule-path-1 && sleep 1; } && test_must_be_empty err && test_match_signal 13 "$(cat status)" ) With the pipe-stuffing workaround the test runs successfully. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10t0060: fix EBUSY in MinGW when setting up runtime prefixPatrick Steinhardt1-4/+6
Two of our tests in t0060 verify that the runtime prefix functionality works as expected by creating a separate directory hierarchy, copying the Git executable in there and then creating scripts relative to that executable. These tests fail quite regularly in GitLab CI with the following error: expecting success of 0060.218 '%(prefix)/ works': mkdir -p pretend/bin && cp "$GIT_EXEC_PATH"/git$X pretend/bin/ && git config yes.path "%(prefix)/yes" && GIT_EXEC_PATH= ./pretend/bin/git config --path yes.path >actual && echo "$(pwd)/pretend/yes" >expect && test_cmp expect actual ++ mkdir -p pretend/bin ++ cp /c/GitLab-Runner/builds/gitlab-org/git/git.exe pretend/bin/ cp: cannot create regular file 'pretend/bin/git.exe': Device or resource busy error: last command exited with $?=1 not ok 218 - %(prefix)/ works Seemingly, the "git.exe" binary we are trying to overwrite is still being held open. It is somewhat puzzling why exactly that is: while the preceding test _does_ write to and execute the same path, it should have exited and shouldn't keep any backgrounded processes around. So it must be held open by something else, either in MinGW or in Windows itself. While the root cause is puzzling, the workaround is trivial enough: instead of writing the file twice we simply pull the common setup into a separate test case so that we won't observe EBUSY in the first place. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10GIT-VERSION-GEN: allow it to be run in parallelJohannes Schindelin1-4/+4
"Why would one want to run it in parallel?" I hear you ask. I am glad you are curious, because a curious story is what it is, indeed. The `GIT-VERSION-GEN` script is quite a pillar of Git's source code, with most lines being unchanged for the past 15 years. Until the v2.48.0 release candidate cycle. Its original purpose was to generate the version string and store it in the `GIT-VERSION-FILE`. This paradigm changed quite dramatically when support for building with Meson was introduced. Most crucially, a38edab7c88b (Makefile: generate doc versions via GIT-VERSION-GEN, 2024-12-06) changed the way the documentation is built by using the `GIT-VERSION-GEN` file to write out the `asciidocor-extensions.rb` and `asciidoc.conf` files with now hard-coded version strings. Crucially, the Makefile rule to generate those files needs to be run in every build because `GIT_VERSION` could have been specified in the `make` command-line, which would require these files to be modified. This introduced a surprising race condition! And this is how that race surfaces: When calling `make -j2 html man` from the top-level directory (a variant of which is invoked in Git for Windows' release process), two sub-processes are spawned, a `make -C Documentation html` one and a `make -C Documentation man` one. Both run the rule to (re-)generate `asciidoctor-extensions.rb` or `asciidoc.conf`, invoking `GIT-VERSION-GEN` to do so. That script first generates a temporary file (appending the `+` character to the filename), then looks whether it contains something different than the already existing file (if it exists, that is), and either replaces it if needed, or removes the temporary file. If one of the two parallel invocations removes that temporary file before the other can compare it, or even worse: if one tries to replace the target file just after the other _started_ writing the temporary file (but did not finish writing it yet), that race condition now causes bad builds. This may sound highly theoretical, but due to the design of Git's build process, Git for Windows is forced to use a (slow) POSIX emulation layer to run that script and in the blink of an eye it becomes very much not theoretical at all. See Exhibit A: These GitHub workflow runs failed because one of the two competing `make` processes tried to remove the temporary file when the other process had already done so: https://github.com/git-for-windows/git-sdk-32/actions/runs/12663456654 https://github.com/git-for-windows/git-sdk-32/actions/runs/12683174970 https://github.com/git-for-windows/git-sdk-64/actions/runs/12649348496 While it is undesirable to run this script over and over again, certainly when this involves above-mentioned slow POSIX emulation layer, the stage of the release cycle in which we are presently finding ourselves does not lend itself to a re-design where this script could be run once, and once only, but instead dictates that a quick and reliable work-around be implemented that prevents the race condition without changing the overall architecture of the build process. This patch does that: By using a filename suffix for the temporary file which is based on the currently-executing script's process ID, We guarantee that the two competing invocations cannot overwrite or remove each others' temporary files. The filename suffix still ends in `+` to ensure that the temporary artifacts are matched by the `*+` pattern in `.gitignore` that was added in f9bbaa384ef (Add intermediate build products to .gitignore, 2009-11-08). Helped-by: Martin Ågren <martin.agren@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10builtin/blame: fix out-of-bounds write with blank boundary commitsPatrick Steinhardt2-3/+21
When passing the `-b` flag to git-blame(1), then any blamed boundary commits which were marked as uninteresting will not get their actual commit ID printed, but will instead be replaced by a couple of spaces. The flag can lead to an out-of-bounds write as though when combined with `--abbrev=` when the abbreviation length is longer than `GIT_MAX_HEXSZ` as we simply use memset(3p) on that array with the user-provided length directly. The result is most likely that we segfault. An obvious fix would be to cull `length` to `GIT_MAX_HEXSZ` many bytes. But when the underlying object ID is SHA1, and if the abbreviated length exceeds the SHA1 length, it would cause us to print more bytes than desired, and the result would be misaligned. Instead, fix the bug by computing the length via strlen(3p). This makes us write as many bytes as the formatted object ID requires and thus effectively limits the length of what we may end up printing to the length of its hash. If `--abbrev=` asks us to abbreviate to something shorter than the full length of the underlying hash function it would be handled by the call to printf(3p) correctly. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-10builtin/blame: fix out-of-bounds read with excessive `--abbrev`Patrick Steinhardt2-1/+10
In 6411a0a896 (builtin/blame: fix type of `length` variable when emitting object ID, 2024-12-06) we have fixed the type of the `length` variable. In order to avoid a cast from `size_t` to `int` in the call to printf(3p) with the "%.*s" formatter we have converted the code to instead use fwrite(3p), which accepts the length as a `size_t`. It was reported though that this makes us read over the end of the OID array when the provided `--abbrev=` length exceeds the length of the object ID. This is because fwrite(3p) of course doesn't stop when it sees a NUL byte, whereas printf(3p) does. Fix the bug by reverting back to printf(3p) and culling the provided length to `GIT_MAX_HEXSZ` to keep it from overflowing when cast to an `int`. Reported-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09credential-cache: respect authtype capabilityM Hickford2-2/+17
Previously, credential-cache populated authtype regardless whether "get" request had authtype capability. As documented in git-credential.txt, authtype "should not be sent unless the appropriate capability ... is provided". Add test. Without this change, the test failed because "credential fill" printed an incomplete credential with only protocol and host attributes (the unexpected authtype attribute was discarded by credential.c). Signed-off-by: M Hickford <mirth.hickford@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: make list tail-passing more explicitJeff King1-26/+21
The ll_diff_tree_paths() function and its helpers all take a pointer to a list tail, possibly add to it, and then return the new tail. This works but has two downsides: - The top-level caller (diff_tree_paths() in this case) has to make a fake combine_diff_path struct to act as the list head. This is especially weird here, as it's a flexible-sized struct which will have an empty FLEX_ARRAY field. That used to be a portability problem, though these days it is legal because our FLEX_ARRAY macro over-allocates if necessary. It's still kind of ugly, though. - Besides the name "tail", it's not immediately obvious that the entry we pass around will not be examined by each function. Using a pointer-to-pointer or similar makes it more obvious we only care about the pointer itself, not its contents. We can solve both by passing around a pointer to the tail instead. That gets rid of the return value entirely, though note that because of the recursion we actually need a three-star pointer for this to work. The result is fairly readable, as we only need to dereference the tail in one spot. If we wanted to make it simpler we could wrap the tail in a struct, which we pass around. Another option is to convert combine_diff to use our generic list_head API. I tried that and found the result became much harder to read overall. It means that _all_ code that looks at combine_diff_path structs needs to be modified, since the "next" pointer is now inside a list_head which has to be dereferenced with list_entry(). And we lose some type safety, since we're just passing around a list_head struct everywhere, and everybody who looks at it has to specify the type to list_entry themselves. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: simplify emit_path() list managementJeff King1-6/+5
In emit_path() we may append a new combine_diff_path entry to our list, decide that we don't want it (because opt->pathchange() told us so) and then roll it back. Between the addition and the rollback, it doesn't matter if it's in the list or not (no functions can even tell, since it's a singly-linked list and we pass around just the tail entry). So it's much simpler to just wait until opt->pathchange() tells us whether to keep it, and either attach it (or free it) then. We do still have to allocate it up front since it's that struct itself which is passed to the pathchange callback. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: use the name "tail" to refer to list tailJeff King1-16/+17
The ll_diff_tree_paths() function and its helpers all append to a running list by taking in a pointer to the old tail and returning the new tail. But they just call this argument "p", which is not very descriptive. It gets particularly confusing in emit_path(), where we actually add to the list, because "p" does double-duty: it is the tail of the list, but it is also the entry which we add. Except that in some cases we _don't_ add a new entry (or we might even add it and roll it back) if the path isn't interesting. At first glance, this makes it look like a bug that we pass "p" on to ll_diff_tree_paths() to recurse; sometimes it is getting the new entry we made and sometimes not! But it's not a bug, because ll_diff_tree_paths() does not care about the entry itself at all. It is only using its "next" pointer as the tail of the list. Let's swap out "p" for "tail" to make this obvious. And then in emit_path() we'll continue to use "p" for our newly allocated entry. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: drop list-tail argument to diff_tree_paths()Jeff King3-13/+12
The internals of the path diffing code, including ll_diff_tree_paths(), all take an extra combine_diff_path parameter which they use as the tail of a list of results, appending any new entries to it. The public-facing diff_tree_paths() takes the same argument, but it just makes the callers more awkward. They always start with a clean list, and have to set up a fake head struct to pass in. Let's keep the public API clean by always returning a new list. That keeps the fake struct as an implementation detail of tree-diff.c. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09combine-diff: drop public declaration of combine_diff_path_size()Jeff King2-5/+3
We want callers to use combine_diff_path_new() to allocate structs, rather than using combine_diff_path_size() and xmalloc(). That gives us more consistency over the initialization of the fields. Now that the final external user of combine_diff_path_size() is gone, we can stop declaring it publicly. And since our constructor is the only caller, we can just inline it there. Breaking the size computation into two parts also lets us reuse the intermediate multiplication result of the parent length, since we need to know it to perform our memset(). The result is a little easier to read. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: inline path_appendnew()Jeff King1-27/+4
Our path_appendnew() has been simplified to the point that it is mostly just implementing combine_diff_path_new(), plus setting the "next" pointer. Since there's only one caller, let's replace it completely with a call to that helper function. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: pass whole path string to path_appendnew()Jeff King1-5/+6
When diffing trees, we'll have a strbuf "base" containing the slash-separted names of our parent trees, and a "path" string representing an entry name from the current tree. We pass these separately to path_appendnew(), which combines them to form a single path string in the combine_diff_path struct. Instead, let's append the path string to our base strbuf ourselves, pass in the result, and then roll it back with strbuf_setlen(). This lets us simplify path_appendnew() a bit, enabling further refactoring. And while it might seem like this causes extra wasted allocations, it does not in practice. We reuse the same strbuf for each tree entry, so we only have to allocate it to match the largest name. Plus, in a recursive diff we'll end up doing this same operation to extend the base for the next level of recursion. So we're really just incurring a small memcpy(). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: drop path_appendnew() alloc optimizationJeff King1-61/+6
When we're diffing trees, we create a list of combine_diff_path structs that represent changed paths. We allocate each struct and add it to the list with path_appendnew(), which we then feed to opt->pathchange(). That function tells us whether the path is of interest or not; if not, then we can throw away the struct we allocated. So there's an optimization to avoid extra allocations: instead of throwing away the new entry, we try to reuse it. If it was large enough to store the next path we care about, we can do so. And if not, we fall back to freeing and re-allocating a new struct. This comes from 72441af7c4 (tree-diff: rework diff_tree() to generate diffs for multiparent cases as well, 2014-04-07), where the goal was to have even the 2-parent diff code use the combine-diff infrastructure, but without taking a performance hit. The implementation causes some complexities in the interface (as we store the allocation length inside the "next" pointer), and prevents us from using the regular combine_diff_path_new() constructor. The complexity is mostly contained inside two functions, but it's worth re-evaluating how much it's helping. That commit claims it helps ~1% on generating two-parent diffs in linux.git. Here are the timings I get on the same command today ("old" is the current tip of master, and "new" has this patch applied): Benchmark 1: ./git.old log --raw --no-abbrev --no-renames v3.10..v3.11 Time (mean ± σ): 532.9 ms ± 5.8 ms [User: 472.7 ms, System: 59.6 ms] Range (min … max): 525.9 ms … 543.3 ms 10 runs Benchmark 2: ./git.new log --raw --no-abbrev --no-renames v3.10..v3.11 Time (mean ± σ): 538.3 ms ± 5.7 ms [User: 478.0 ms, System: 59.7 ms] Range (min … max): 528.5 ms … 545.3 ms 10 runs Summary ./git.old log --raw --no-abbrev --no-renames v3.10..v3.11 ran 1.01 ± 0.02 times faster than ./git.new log --raw --no-abbrev --no-renames v3.10..v3.11 So we do end up on average 1% faster, but with 2% of noise. I tried to focus more on diff performance by running the commit traversal separately, like: git rev-list v3.10..v3.11 >in and then timing just the diffs: Benchmark 1: ./git.old diff-tree --stdin -r <in Time (mean ± σ): 415.7 ms ± 5.8 ms [User: 357.7 ms, System: 58.0 ms] Range (min … max): 410.9 ms … 430.3 ms 10 runs Benchmark 2: ./git.new diff-tree --stdin -r <in Time (mean ± σ): 418.5 ms ± 2.1 ms [User: 361.7 ms, System: 56.6 ms] Range (min … max): 414.9 ms … 421.3 ms 10 runs Summary ./git.old diff-tree --stdin -r <in ran 1.01 ± 0.02 times faster than ./git.new diff-tree --stdin -r <in That gets roughly the same result. Adding in "-c" to do multi-parent diffs doesn't change much: Benchmark 1: ./git.old diff-tree --stdin -r -c <in Time (mean ± σ): 525.3 ms ± 6.6 ms [User: 470.0 ms, System: 55.1 ms] Range (min … max): 508.4 ms … 531.0 ms 10 runs Benchmark 2: ./git.new diff-tree --stdin -r -c <in Time (mean ± σ): 532.3 ms ± 6.2 ms [User: 469.0 ms, System: 63.1 ms] Range (min … max): 520.3 ms … 539.4 ms 10 runs Summary ./git.old diff-tree --stdin -r -c <in ran 1.01 ± 0.02 times faster than ./git.new diff-tree --stdin -r -c <in And of course if you add in a lot more work by doing actual content-level diffs, any difference is lost entirely (here the newer version is actually faster, but that's really just noise): Benchmark 1: ./git.old diff-tree --stdin -r --cc <in Time (mean ± σ): 11.571 s ± 0.064 s [User: 11.287 s, System: 0.283 s] Range (min … max): 11.497 s … 11.615 s 3 runs Benchmark 2: ./git.new diff-tree --stdin -r --cc <in Time (mean ± σ): 11.466 s ± 0.109 s [User: 11.108 s, System: 0.357 s] Range (min … max): 11.346 s … 11.560 s 3 runs Summary ./git.new diff-tree --stdin -r --cc <in ran 1.01 ± 0.01 times faster than ./git.old diff-tree --stdin -r --cc <in So my conclusion is that it probably does help a little, but it's mostly lost in the noise. I could see an argument for keeping it, as the complexity is hidden away in functions that do not often need to be touched. But it does make them more confusing than necessary (despite some detailed explanations from the author of that commit; it just took me a while to wrap my head around what was going on) and prevents further refactoring of the combine_diff_path struct. So let's drop it. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09run_diff_files(): de-mystify the size of combine_diff_path structJeff King1-1/+6
We allocate a combine_diff_path struct with space for 5 parents. Why 5? The history is not particularly enlightening. The allocation comes from b4b1550315 (Don't instantiate structures with FAMs., 2006-06-18), which just switched to xmalloc from a stack struct with 5 elements. That struct changed to 5 from 4 in 2454c962fb (combine-diff: show mode changes as well., 2006-02-06), when we also moved from storing raw sha1 bytes to the combine_diff_parent struct. But no explanation is given. That 4 comes from the earliest code in ea726d02e9 (diff-files: -c and --cc options., 2006-01-28). One might guess it is for the 4 stages we can store in the index. But this code path only ever diffs the current state against stages 2 and 3. So we only need two slots. And it's easy to see this is still the case. We fill the parent slots by subtracting 2 from the ce_stage() values, ignoring values below 2. And since ce_stage() is only 2 bits, there are 4 values, and thus we need 2 slots. Let's use the correct value (saving a tiny bit of memory) and add a comment explaining what's going on (saving a tiny bit of programmer brain power). Arguably we could use: 1 + (STAGEMASK >> STAGESHIFT) - 2 which lets the compiler enforce that we will not go out-of-bounds if we see an unexpected value from ce_stage(). But that is more confusing to explain, and the constant "2" is baked into other parts of the function. It is a fundamental constant, not something where somebody might bump a macro and forget to update this code. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09diff: add a comment about combine_diff_path.parent.pathJeff King1-0/+6
We only fill in the per-parent "path" field when it differs from what's in combine_diff_path.path (and even then only when the option is appropriate). Let's document that. Suggested-by: Wink Saville <wink@saville.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09combine-diff: use pointer for parent pathsJeff King2-20/+12
Commit d76ce4f734 (log,diff-tree: add --combined-all-paths option, 2019-02-07) added a "path" field to each combine_diff_parent struct. It's defined as a strbuf, but this is overkill. We never manipulate the buffer beyond inserting a single string into it. And in fact there's a small bug: we zero the parent structs, including the path strbufs. For the 0th parent, we strbuf_init() the strbuf before adding to it. But for subsequent parents, we never do the init. This is technically violating the strbuf API, though the code there is resilient enough to handle this zero'd state. This patch switches us to just store an allocated string pointer. Zeroing it is enough to properly initialize it there (modulo the usual assumption we make that a NULL pointer is all-zeroes). And as a bonus, we can just check for a non-NULL value to see if it is present, rather than repeating the combined_all_paths logic at each site. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09tree-diff: clear parent array in path_appendnew()Jeff King1-2/+2
All of the other functions which allocate a combine_diff_path struct zero out the parent array, but this code path does not. There's no bug, since our caller will fill in most of the fields. But leaving the unused fields (like combine_diff_parent.path) uninitialized makes working with the struct more error-prone than it needs to be. Let's just zero the parent field to be consistent with the combine_diff_path_new() allocator. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09combine-diff: add combine_diff_path_new()Jeff King3-36/+36
The combine_diff_path struct has variable size, since it embeds both the memory allocation for the path field as well as a variable-sized parent array. This makes allocating one a bit tricky. We have a helper to compute the required size, but it's up to individual sites to actually initialize all of the fields. Let's provide a constructor function to make that a little nicer. Besides being shorter, it also hides away tricky bits like the computation of the "path" pointer (which is right after the "parent" flex array). As a bonus, using the same constructor everywhere means that we'll consistently initialize all parts of the struct. A few code paths left the parent array unitialized. This didn't cause any bugs, but we'll be able to simplify some code in the next few patches knowing that the parent fields have all been zero'd. This also gets rid of some questionable uses of "int" to store buffer lengths. Though we do use them to allocate, I don't think there are any integer overflow vulnerabilities here (the allocation helper promotes them to size_t and checks arithmetic for overflow, and the actual memcpy of the bytes is done using the possibly-truncated "int" value). Sadly we can't use the FLEX_* macros to simplify the allocation here, because there are two variable-sized parts to the struct (and those macros only handle one). Nor can we get stop publicly declaring combine_diff_path_size(). This patch does not touch the code in path_appendnew() at all, which is not ready to be moved to our new constructor for a few reasons: - path_appendnew() has a memory-reuse optimization where it tries to reuse combine_diff_path structs rather than freeing and reallocating. - path_appendnew() does not create the struct from a single path string, but rather allocates and copies into the buffer from multiple sources. These can be addressed by some refactoring, but let's leave it as-is for now. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09run_diff_files(): delay allocation of combine_diff_pathJeff King1-12/+12
While looping over the index entries, when we see a higher level stage the first thing we do is allocate a combine_diff_path struct for it. But this can leak; if check_removed() returns an error, we'll continue to the next iteration of the loop without cleaning up. We can fix this by just delaying the allocation by a few lines. I don't think this leak is triggered in the test suite, but it's pretty easy to see by inspection. My ulterior motive here is that the delayed allocation means we have all of the data needed to initialize "dpath" at the time of malloc, making it easier to factor out a constructor function. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09difftool docs: restore correct position of tool listAdam Johnson2-2/+2
2a9dfdf260 (difftool docs: de-duplicate configuration sections, 2022-09-07) moved the difftool documentation, but missed moving this "include" line that includes the generated list of diff tools, as referenced in the moved text. Restore the correct position of the included list. Signed-off-by: Adam Johnson <me@adamj.eu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-09t/unit-tests: convert hash to use clar test frameworkSeyi Kuforiji3-25/+50
Adapt the hash test functions to clar framework by using clar assertions where necessary. Following the consensus to convert the unit-tests scripts found in the t/unit-tests folder to clar driven by Patrick Steinhardt. Test functions are structured as a standalone to test individual hash string and literal case. Mentored-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Seyi Kuforiji <kuforiji98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-01-08Merge branch 'js/reftable-realloc-errors-fix'Junio C Hamano1-4/+4
Last-minute fix to a recent update. * js/reftable-realloc-errors-fix: t-reftable-basics: allow for `malloc` to be `#define`d
2025-01-08Merge branch 'sj/meson-perl-build-fix'Junio C Hamano8-0/+8
The build procedure in "meson" for the "perl/" hierarchy lacked necessary dependencies, which has been corrected. * sj/meson-perl-build-fix: meson: fix perl dependencies