diff options
| author | Sebastian Thiel <sebastian.thiel@icloud.com> | 2023-08-09 07:47:41 +0000 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2023-08-09 11:46:12 -0700 |
| commit | 72695d8214791161a943086e894874b4fd71ba9f (patch) | |
| tree | ca6ce6929e54f372f3a5a26ef1b1ffc3a262430b | |
| parent | fb7d80edcae482f4fa5d4be0227dc3054734e5f3 (diff) | |
| download | git-72695d8214791161a943086e894874b4fd71ba9f.tar.gz | |
mv: handle lstat() failure correctly
When moving a directory onto another with `git mv` various checks are
performed. One of of these validates that the destination is not existing.
When calling `lstat` on the destination path and it fails as the path
doesn't exist, some environments seem to overwrite the passed in
`stat` memory nonetheless (I observed this issue on debian 12 of x86_64,
running on OrbStack on ARM, emulated with Rosetta).
This would affect the code that followed as it would still acccess a now
modified `st` structure, which now seems to contain uninitialized memory.
`S_ISDIR(st_dir_mode)` would then typically return false causing the code
to run into a bad case.
The fix avoids overwriting the existing `st` structure, providing an
alternative that exists only for that purpose.
Note that this patch minimizes complexity instead of stack-frame size.
Signed-off-by: Sebastian Thiel <sebastian.thiel@icloud.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
| -rw-r--r-- | builtin/mv.c | 4 | ||||
| -rwxr-xr-x | t/t7001-mv.sh | 7 |
2 files changed, 9 insertions, 2 deletions
diff --git a/builtin/mv.c b/builtin/mv.c index 665bd27448..5213d99381 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -183,7 +183,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) int src_dir_nr = 0, src_dir_alloc = 0; struct strbuf a_src_dir = STRBUF_INIT; enum update_mode *modes, dst_mode = 0; - struct stat st; + struct stat st, dest_st; struct string_list src_for_dst = STRING_LIST_INIT_NODUP; struct lock_file lock_file = LOCK_INIT; struct cache_entry *ce; @@ -303,7 +303,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) goto act_on_entry; } if (S_ISDIR(st.st_mode) - && lstat(dst, &st) == 0) { + && lstat(dst, &dest_st) == 0) { bad = _("cannot move directory over file"); goto act_on_entry; } diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 898a920532..f136ea76f7 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -174,6 +174,13 @@ test_expect_success 'do not move directory over existing directory' ' test_must_fail git mv path2 path0 ' +test_expect_success 'rename directory to non-existing directory' ' + mkdir dir-a && + >dir-a/f && + git add dir-a && + git mv dir-a non-existing-dir +' + test_expect_success 'move into "."' ' git mv path1/path2/ . ' |
