summaryrefslogtreecommitdiff
path: root/dir.c
diff options
context:
space:
mode:
authorDavid Turner <dturner@twopensource.com>2015-10-21 17:54:11 (GMT)
committerJunio C Hamano <gitster@pobox.com>2015-10-21 19:47:38 (GMT)
commit41284eb0f944fe2d73708bb4105a8e3ccd0297df (patch)
treed9fb4779370efc2eec5079f72c210bdec900ef87 /dir.c
parent441c4a40173fe1ee8a5c0094e587dfc47e2a6460 (diff)
downloadgit-41284eb0f944fe2d73708bb4105a8e3ccd0297df.zip
git-41284eb0f944fe2d73708bb4105a8e3ccd0297df.tar.gz
git-41284eb0f944fe2d73708bb4105a8e3ccd0297df.tar.bz2
name-hash: don't reuse cache_entry in dir_entry
Stop reusing cache_entry in dir_entry; doing so causes a use-after-free bug. During merges, we free entries that we no longer need in the destination index. But those entries might have also been stored in the dir_entry cache, and when a later call to add_to_index found them, they would be used after being freed. To prevent this, change dir_entry to store a copy of the name instead of a pointer to a cache_entry. This entails some refactoring of code that expects the cache_entry. Keith McGuigan <kmcguigan@twitter.com> diagnosed this bug and wrote the initial patch, but this version does not use any of Keith's code. Helped-by: Keith McGuigan <kmcguigan@twitter.com> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: David Turner <dturner@twopensource.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c22
1 files changed, 4 insertions, 18 deletions
diff --git a/dir.c b/dir.c
index 3f7a025..8545922 100644
--- a/dir.c
+++ b/dir.c
@@ -964,29 +964,15 @@ enum exist_status {
*/
static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
{
- const struct cache_entry *ce = cache_dir_exists(dirname, len);
- unsigned char endchar;
+ struct cache_entry *ce;
- if (!ce)
- return index_nonexistent;
- endchar = ce->name[len];
-
- /*
- * The cache_entry structure returned will contain this dirname
- * and possibly additional path components.
- */
- if (endchar == '/')
+ if (cache_dir_exists(dirname, len))
return index_directory;
- /*
- * If there are no additional path components, then this cache_entry
- * represents a submodule. Submodules, despite being directories,
- * are stored in the cache without a closing slash.
- */
- if (!endchar && S_ISGITLINK(ce->ce_mode))
+ ce = cache_file_exists(dirname, len, ignore_case);
+ if (ce && S_ISGITLINK(ce->ce_mode))
return index_gitdir;
- /* This should never be hit, but it exists just in case. */
return index_nonexistent;
}