浏览代码

cache sync: add more refcount tests

Marian Beermann 8 年之前
父节点
当前提交
5af66dbb12
共有 2 个文件被更改,包括 65 次插入2 次删除
  1. 6 2
      src/borg/cache_sync/unpack.h
  2. 59 0
      src/borg/testsuite/cache.py

+ 6 - 2
src/borg/cache_sync/unpack.h

@@ -251,8 +251,12 @@ static inline int unpack_callback_array_end(unpack_user* u)
         /* b'chunks': [ ( b'1234...', 123, 345 )
          *                                     ^ */
         cache_entry = (uint32_t*) hashindex_get(u->chunks, u->current.key);
-        if (cache_entry) {
+        if(cache_entry) {
             refcount = _le32toh(cache_entry[0]);
+            if(refcount > _MAX_VALUE) {
+                SET_LAST_ERROR("invalid reference count");
+                return -1;
+            }
             refcount += 1;
             cache_entry[0] = _htole32(MIN(refcount, _MAX_VALUE));
         } else {
@@ -260,7 +264,7 @@ static inline int unpack_callback_array_end(unpack_user* u)
             cache_values[0] = _htole32(1);
             cache_values[1] = _htole32(u->current.size);
             cache_values[2] = _htole32(u->current.csize);
-            if (!hashindex_set(u->chunks, u->current.key, cache_values)) {
+            if(!hashindex_set(u->chunks, u->current.key, cache_values)) {
                 SET_LAST_ERROR("hashindex_set failed");
                 return -1;
             }

+ 59 - 0
src/borg/testsuite/cache.py

@@ -1,3 +1,4 @@
+import io
 
 from msgpack import packb
 
@@ -137,3 +138,61 @@ class TestCacheSynchronizer:
         with pytest.raises(ValueError) as excinfo:
             sync.feed(packed)
         assert str(excinfo.value) == 'cache_sync_feed failed: ' + error
+
+    def make_index_with_refcount(self, refcount):
+        index_data = io.BytesIO()
+        index_data.write(b'BORG_IDX')
+        # num_entries
+        index_data.write((1).to_bytes(4, 'little'))
+        # num_buckets
+        index_data.write((1).to_bytes(4, 'little'))
+        # key_size
+        index_data.write((32).to_bytes(1, 'little'))
+        # value_size
+        index_data.write((3 * 4).to_bytes(1, 'little'))
+
+        index_data.write(H(0))
+        index_data.write(refcount.to_bytes(4, 'little'))
+        index_data.write((1234).to_bytes(4, 'little'))
+        index_data.write((5678).to_bytes(4, 'little'))
+
+        index_data.seek(0)
+        index = ChunkIndex.read(index_data)
+        return index
+
+    def test_corrupted_refcount(self):
+        index = self.make_index_with_refcount(ChunkIndex.MAX_VALUE + 1)
+        sync = CacheSynchronizer(index)
+        data = packb({
+            'chunks': [
+                (H(0), 1, 2),
+            ]
+        })
+        with pytest.raises(ValueError) as excinfo:
+            sync.feed(data)
+        assert str(excinfo.value) == 'cache_sync_feed failed: invalid reference count'
+
+    def test_refcount_max_value(self):
+        index = self.make_index_with_refcount(ChunkIndex.MAX_VALUE)
+        sync = CacheSynchronizer(index)
+        data = packb({
+            'chunks': [
+                (H(0), 1, 2),
+            ]
+        })
+        sync.feed(data)
+        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234, 5678)
+
+    def test_refcount_one_below_max_value(self):
+        index = self.make_index_with_refcount(ChunkIndex.MAX_VALUE - 1)
+        sync = CacheSynchronizer(index)
+        data = packb({
+            'chunks': [
+                (H(0), 1, 2),
+            ]
+        })
+        sync.feed(data)
+        # Incremented to maximum
+        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234, 5678)
+        sync.feed(data)
+        assert index[H(0)] == (ChunkIndex.MAX_VALUE, 1234, 5678)