Browse Source

Fixed BitfieldMan::getOffsetCompletedLength overflow on 32-bit systems

Tatsuhiro Tsujikawa 13 years ago
parent
commit
04586f50b1
2 changed files with 24 additions and 2 deletions
  1. 2 2
      src/BitfieldMan.cc
  2. 22 0
      test/BitfieldManTest.cc

+ 2 - 2
src/BitfieldMan.cc

@@ -863,7 +863,7 @@ int64_t BitfieldMan::getOffsetCompletedLength
     }
   } else {
     if(isBitSet(start)) {
-      res += (start+1)*blockLength_-offset;
+      res += static_cast<int64_t>(start+1)*blockLength_-offset;
     }
     for(size_t i = start+1; i <= end-1; ++i) {
       if(isBitSet(i)) {
@@ -871,7 +871,7 @@ int64_t BitfieldMan::getOffsetCompletedLength
       }
     }
     if(isBitSet(end)) {
-      res += offset+length-end*blockLength_;
+      res += offset+length-static_cast<int64_t>(end)*blockLength_;
     }
   }
   return res;

+ 22 - 0
test/BitfieldManTest.cc

@@ -28,6 +28,7 @@ class BitfieldManTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testGetSparseMissingUnusedIndex_withMinSplitSize);
   CPPUNIT_TEST(testIsBitSetOffsetRange);
   CPPUNIT_TEST(testGetOffsetCompletedLength);
+  CPPUNIT_TEST(testGetOffsetCompletedLength_largeFile);
   CPPUNIT_TEST(testGetMissingUnusedLength);
   CPPUNIT_TEST(testSetBitRange);
   CPPUNIT_TEST(testGetAllMissingIndexes);
@@ -62,6 +63,7 @@ public:
   void testGetSparseMissingUnusedIndex_withMinSplitSize();
   void testIsBitSetOffsetRange();
   void testGetOffsetCompletedLength();
+  void testGetOffsetCompletedLength_largeFile();
   void testGetMissingUnusedLength();
   void testSetBitRange();
   void testCountFilteredBlock();
@@ -484,6 +486,26 @@ void BitfieldManTest::testGetOffsetCompletedLength()
   CPPUNIT_ASSERT_EQUAL((int64_t)0, bt.getOffsetCompletedLength(1024*20, 1));
 }
 
+void BitfieldManTest::testGetOffsetCompletedLength_largeFile()
+{
+  // Test for overflow on 32-bit systems.
+
+  // Total 4TiB, 4MiB block
+  BitfieldMan bt(1 << 22, 1LL << 40);
+  bt.setBit(1 << 11);
+  bt.setBit((1 << 11)+1);
+  bt.setBit((1 << 11)+2);
+
+  // The last piece is missing:
+  CPPUNIT_ASSERT_EQUAL((int64_t)bt.getBlockLength()*3,
+                       bt.getOffsetCompletedLength(1LL << 33, 1 << 24));
+
+  // The first piece is missing:
+  CPPUNIT_ASSERT_EQUAL((int64_t)bt.getBlockLength()*3,
+                       bt.getOffsetCompletedLength
+		       ((1LL << 33) - bt.getBlockLength(), 1 << 24));
+}
+
 void BitfieldManTest::testGetMissingUnusedLength()
 {
   int64_t totalLength = 1024*10+10;