Skip to content

Commit

Permalink
add a test for the hashindex corruption bug, fixes borgbackup#5531
Browse files Browse the repository at this point in the history
for the bug, see borgbackup#4829.
  • Loading branch information
ThomasWaldmann committed Dec 2, 2020
1 parent 326a617 commit aa3938a
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/borg/testsuite/hashindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,3 +510,45 @@ class AllIndexTestCase(BaseTestCase):
def test_max_load_factor(self):
assert NSIndex.MAX_LOAD_FACTOR < 1.0
assert ChunkIndex.MAX_LOAD_FACTOR < 1.0


class IndexCorruptionTestCase(BaseTestCase):
def test_bug_4829(self):

from struct import pack

def HH(x, y):
# make some 32byte long thing that depends on x and y.
# same x will mean a collision in the hashtable as bucket index is computed from
# first 4 bytes. giving a specific x targets bucket index x.
# y is to create different keys and does not go into the bucket index calculation.
# so, same x + different y --> collision
return pack('<IIQQQ', x, y, 0, 0, 0) # 2 * 4 + 3 * 8 == 32

idx = NSIndex()

# create lots of colliding entries
for y in range(700): # stay below max load to not trigger resize
idx[HH(0, y)] = (0, y)

assert idx.size() == 1031 * 40 + 18 # 1031 buckets + header

# delete lots of the collisions, creating lots of tombstones
for y in range(400): # stay above min load to not trigger resize
del idx[HH(0, y)]

# create lots of colliding entries, within the not yet used part of the hashtable
for y in range(330): # stay below max load to not trigger resize
# at y == 259 a resize will happen due to going beyond max EFFECTIVE load
# if the bug is present, that element will be inserted at the wrong place.
# and because it will be at the wrong place, it can not be found again.
idx[HH(600, y)] = 600, y

# now check if hashtable contents is as expected:

assert [idx.get(HH(0, y)) for y in range(400, 700)] == [(0, y) for y in range(400, 700)]

assert [HH(0, y) in idx for y in range(400)] == [False for y in range(400)] # deleted entries

# this will fail at HH(600, 259) if the bug is present.
assert [idx.get(HH(600, y)) for y in range(330)] == [(600, y) for y in range(330)]

0 comments on commit aa3938a

Please sign in to comment.