Package: subversion
Version: 1.8.5-1
Severity: minor
Tags: upstream

There is also another bug Subversion 1.8 libsvn_subr - cache->hit_count and entry->hit_count are incremented without proper mutual exclusion (only with read lock), so some increments get lost in multithreaded svnserve; as it's unlikely two threads access the same entry at once, usually cache->hit_count (not entry->hit_count) increments are lost, which leads to cache->hit_count being less than sum(entry->hit_count). So it may overflow during subtraction of entry->hit_count and lead to removing of values that should not be removed from the cache in ensure_data_insertable(). Instead of killing the performance by mutual exclusion we may just check for possible overflow.

This doesn't affect general svnserve usability, so severity=minor.

A patch is attached; this is also an upstream issue, so I'll also try to send it to authors.
See the comment.

--- a/subversion/libsvn_subr/cache-membuffer.c  2014-02-12 21:53:58.547230675 
+0000
+++ a/subversion/libsvn_subr/cache-membuffer.c  2014-02-12 22:02:11.039246322 
+0000
@@ -639,9 +639,16 @@ drop_entry(svn_membuffer_t *cache, entry
   assert(idx <= last_in_group);
 
   /* update global cache usage counters
+   *
+   * cache->hit_count and entry->hit_count are incremented without proper 
mutual
+   * exclusion (only with read lock), so some increments get lost in 
multithreaded svnserve;
+   * as it's unlikely two threads access the same entry at once usually it 
leads to
+   * cache->hit_count being less than sum(entry->hit_count). So it may overflow
+   * during subtraction and lead to emptying the cache in 
ensure_data_insertable().
+   * instead of killing the performance by mutual exclusion we just check for 
possible overflow.
    */
   cache->used_entries--;
-  cache->hit_count -= entry->hit_count;
+  cache->hit_count = cache->hit_count < entry->hit_count ? 0 : 
cache->hit_count-entry->hit_count;
   cache->data_used -= entry->size;
 
   /* extend the insertion window, if the entry happens to border it
@@ -802,7 +809,7 @@ let_entry_age(svn_membuffer_t *cache, en
 {
   apr_uint32_t hits_removed = (entry->hit_count + 1) >> 1;
 
-  cache->hit_count -= hits_removed;
+  cache->hit_count = cache->hit_count < hits_removed ? 0 : 
cache->hit_count-hits_removed;
   entry->hit_count -= hits_removed;
 }
 

Reply via email to