summaryrefslogtreecommitdiff
path: root/tests-clar/diff/tree.c
diff options
context:
space:
mode:
authorMichael Schubert <schu@schu.io>2012-09-10 21:29:07 +0200
committerMichael Schubert <schu@schu.io>2012-09-11 15:58:13 +0200
commit6ee6861123ccb599af584377dd8b75eeea24858b (patch)
tree163e4ce1ceea09ef45fcc3b18b3e139016ab621c /tests-clar/diff/tree.c
parent2130dee49ffee6c55b49f4f5cd447b2fb7e0acc3 (diff)
downloadlibgit2-6ee6861123ccb599af584377dd8b75eeea24858b.tar.gz
cache: fix race condition
Example: a cached node is owned only by the cache (refcount == 1). Thread A holds the lock and determines that the entry which should get cached equals the node (git_oid_cmp(&node->oid, &entry->oid) == 0). It frees the given entry to instead return the cached node to the user (entry = node). Now, before Thread A happens to increment the refcount of the node *outside* the cache lock, Thread B tries to store another entry and hits the slot of the node before, decrements its refcount and frees it *before* Thread A gets a chance to increment for the user. git_cached_obj_incref(entry); git_mutex_lock(&cache->lock); { git_cached_obj *node = cache->nodes[hash & cache->size_mask]; if (node == NULL) { cache->nodes[hash & cache->size_mask] = entry; } else if (git_oid_cmp(&node->oid, &entry->oid) == 0) { git_cached_obj_decref(entry, cache->free_obj); entry = node; } else { git_cached_obj_decref(node, cache->free_obj); // Thread B is here cache->nodes[hash & cache->size_mask] = entry; } } git_mutex_unlock(&cache->lock); // Thread A is here /* increase the refcount again, because we are * returning it to the user */ git_cached_obj_incref(entry);
Diffstat (limited to 'tests-clar/diff/tree.c')
0 files changed, 0 insertions, 0 deletions