- When deleting a directory entry, also remove it from the hash table. This prevents use after free in the case of a hash collision
CORE-7774 #resolve

svn path=/trunk/; revision=61643
This commit is contained in:
Thomas Faber 2014-01-16 10:29:51 +00:00
parent 4aa5c6f093
commit bcb5f9475e

View file

@ -10,7 +10,7 @@ djb_hash(const char *name)
{ {
unsigned int val = 5381; unsigned int val = 5381;
int i = 0; int i = 0;
for (i = 0; name[i]; i++) for (i = 0; name[i]; i++)
{ {
val = (33 * val) + name[i]; val = (33 * val) + name[i];
@ -65,6 +65,19 @@ get_entry_by_normname(struct target_dir_hash *dh, const char *norm)
return de; return de;
} }
static void
delete_entry_by_normname(struct target_dir_hash *dh, const char *norm)
{
unsigned int hashcode;
struct target_dir_entry **ent;
hashcode = djb_hash(norm);
ent = &dh->buckets[hashcode % NUM_DIR_HASH_BUCKETS];
while (*ent && strcmp((*ent)->normalized_name, norm))
ent = &(*ent)->next;
if (*ent)
*ent = (*ent)->next;
}
void normalize_dirname(char *filename) void normalize_dirname(char *filename)
{ {
int i, tgt; int i, tgt;
@ -147,9 +160,9 @@ void dir_hash_add_file(struct target_dir_hash *dh, const char *source, const cha
} }
struct target_dir_entry * struct target_dir_entry *
dir_hash_next_dir(struct target_dir_hash *dh, struct target_dir_traversal *t) dir_hash_next_dir(struct target_dir_hash *dh, struct target_dir_traversal *t)
{ {
if (t->i == -1) if (t->i == -1)
return NULL; return NULL;
if (!t->it) if (!t->it)
{ {
@ -177,14 +190,16 @@ dir_hash_next_dir(struct target_dir_hash *dh, struct target_dir_traversal *t)
} }
} }
void dir_hash_destroy_dir(struct target_dir_entry *de) static void
dir_hash_destroy_dir(struct target_dir_hash *dh, struct target_dir_entry *de)
{ {
struct target_file *tf; struct target_file *tf;
struct target_dir_entry *te; struct target_dir_entry *te;
unsigned int hashcode;
while ((te = de->child)) while ((te = de->child))
{ {
de->child = te->next; de->child = te->next;
dir_hash_destroy_dir(te); dir_hash_destroy_dir(dh, te);
free(te); free(te);
} }
while ((tf = de->head)) while ((tf = de->head))
@ -194,11 +209,12 @@ void dir_hash_destroy_dir(struct target_dir_entry *de)
free(tf->target_name); free(tf->target_name);
free(tf); free(tf);
} }
delete_entry_by_normname(dh, de->normalized_name);
free(de->normalized_name); free(de->normalized_name);
free(de->case_name); free(de->case_name);
} }
void dir_hash_destroy(struct target_dir_hash *dh) void dir_hash_destroy(struct target_dir_hash *dh)
{ {
dir_hash_destroy_dir(&dh->root); dir_hash_destroy_dir(dh, &dh->root);
} }