tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestBufferList.cpp (13173B)


      1 /* -*- Mode: C++; tab-width: 9; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // This is included first to ensure it doesn't implicitly depend on anything
      8 // else.
      9 #include "mozilla/BufferList.h"
     10 #include "mozilla/CheckedArithmetic.h"
     11 
     12 // It would be nice if we could use the InfallibleAllocPolicy from mozalloc,
     13 // but MFBT cannot use mozalloc.
     14 class InfallibleAllocPolicy {
     15 public:
     16  template <typename T>
     17  T* pod_malloc(size_t aNumElems) {
     18    size_t size;
     19    if (!mozilla::SafeMul(aNumElems, sizeof(T), &size)) {
     20      MOZ_CRASH("TestBufferList.cpp: overflow");
     21    }
     22    T* rv = static_cast<T*>(malloc(size));
     23    if (!rv) {
     24      MOZ_CRASH("TestBufferList.cpp: out of memory");
     25    }
     26    return rv;
     27  }
     28 
     29  template <typename T>
     30  void free_(T* aPtr, size_t aNumElems = 0) {
     31    free(aPtr);
     32  }
     33 
     34  void reportAllocOverflow() const {}
     35 
     36  bool checkSimulatedOOM() const { return true; }
     37 };
     38 
     39 typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList;
     40 
     41 int main(void) {
     42  const size_t kInitialSize = 16;
     43  const size_t kInitialCapacity = 24;
     44  const size_t kStandardCapacity = 32;
     45 
     46  BufferList bl(kInitialSize, kInitialCapacity, kStandardCapacity);
     47 
     48  memset(bl.Start(), 0x0c, kInitialSize);
     49  MOZ_RELEASE_ASSERT(bl.Size() == kInitialSize);
     50 
     51  // Simple iteration and access.
     52 
     53  BufferList::IterImpl iter(bl.Iter());
     54  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialSize);
     55  MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialSize));
     56  MOZ_RELEASE_ASSERT(!iter.HasRoomFor(kInitialSize + 1));
     57  MOZ_RELEASE_ASSERT(!iter.HasRoomFor(size_t(-1)));
     58  MOZ_RELEASE_ASSERT(*iter.Data() == 0x0c);
     59  MOZ_RELEASE_ASSERT(!iter.Done());
     60 
     61  iter.Advance(bl, 4);
     62  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialSize - 4);
     63  MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialSize - 4));
     64  MOZ_RELEASE_ASSERT(*iter.Data() == 0x0c);
     65  MOZ_RELEASE_ASSERT(!iter.Done());
     66 
     67  iter.Advance(bl, 11);
     68  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kInitialSize - 4 - 11);
     69  MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialSize - 4 - 11));
     70  MOZ_RELEASE_ASSERT(!iter.HasRoomFor(kInitialSize - 4 - 11 + 1));
     71  MOZ_RELEASE_ASSERT(*iter.Data() == 0x0c);
     72  MOZ_RELEASE_ASSERT(!iter.Done());
     73 
     74  iter.Advance(bl, kInitialSize - 4 - 11);
     75  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 0);
     76  MOZ_RELEASE_ASSERT(!iter.HasRoomFor(1));
     77  MOZ_RELEASE_ASSERT(iter.Done());
     78 
     79  // Writing to the buffer.
     80 
     81  const size_t kSmallWrite = 16;
     82 
     83  char toWrite[kSmallWrite];
     84  memset(toWrite, 0x0a, kSmallWrite);
     85  MOZ_ALWAYS_TRUE(bl.WriteBytes(toWrite, kSmallWrite));
     86 
     87  MOZ_RELEASE_ASSERT(bl.Size() == kInitialSize + kSmallWrite);
     88 
     89  iter = bl.Iter();
     90  iter.Advance(bl, kInitialSize);
     91  MOZ_RELEASE_ASSERT(!iter.Done());
     92  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() ==
     93                     kInitialCapacity - kInitialSize);
     94  MOZ_RELEASE_ASSERT(iter.HasRoomFor(kInitialCapacity - kInitialSize));
     95  MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a);
     96 
     97  // AdvanceAcrossSegments.
     98 
     99  iter = bl.Iter();
    100  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kInitialCapacity - 4));
    101  MOZ_RELEASE_ASSERT(!iter.Done());
    102  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 4);
    103  MOZ_RELEASE_ASSERT(iter.HasRoomFor(4));
    104  MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a);
    105 
    106  iter = bl.Iter();
    107  MOZ_RELEASE_ASSERT(
    108      iter.AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite - 4));
    109  MOZ_RELEASE_ASSERT(!iter.Done());
    110  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == 4);
    111  MOZ_RELEASE_ASSERT(iter.HasRoomFor(4));
    112  MOZ_RELEASE_ASSERT(*iter.Data() == 0x0a);
    113 
    114  MOZ_RELEASE_ASSERT(
    115      bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite - 1));
    116  MOZ_RELEASE_ASSERT(
    117      bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite));
    118  MOZ_RELEASE_ASSERT(
    119      !bl.Iter().AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite + 1));
    120  MOZ_RELEASE_ASSERT(!bl.Iter().AdvanceAcrossSegments(bl, size_t(-1)));
    121 
    122  // Reading non-contiguous bytes.
    123 
    124  char toRead[kSmallWrite];
    125  iter = bl.Iter();
    126  iter.Advance(bl, kInitialSize);
    127  bl.ReadBytes(iter, toRead, kSmallWrite);
    128  MOZ_RELEASE_ASSERT(memcmp(toRead, toWrite, kSmallWrite) == 0);
    129  MOZ_RELEASE_ASSERT(iter.Done());
    130 
    131  // Make sure reading up to the end of a segment advances the iter to the next
    132  // segment.
    133  iter = bl.Iter();
    134  bl.ReadBytes(iter, toRead, kInitialSize);
    135  MOZ_RELEASE_ASSERT(!iter.Done());
    136  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() ==
    137                     kInitialCapacity - kInitialSize);
    138 
    139  const size_t kBigWrite = 1024;
    140 
    141  char* toWriteBig = static_cast<char*>(malloc(kBigWrite));
    142  for (unsigned i = 0; i < kBigWrite; i++) {
    143    toWriteBig[i] = i % 37;
    144  }
    145  MOZ_ALWAYS_TRUE(bl.WriteBytes(toWriteBig, kBigWrite));
    146 
    147  char* toReadBig = static_cast<char*>(malloc(kBigWrite));
    148  iter = bl.Iter();
    149  MOZ_RELEASE_ASSERT(
    150      iter.AdvanceAcrossSegments(bl, kInitialSize + kSmallWrite));
    151  bl.ReadBytes(iter, toReadBig, kBigWrite);
    152  MOZ_RELEASE_ASSERT(memcmp(toReadBig, toWriteBig, kBigWrite) == 0);
    153  MOZ_RELEASE_ASSERT(iter.Done());
    154 
    155  free(toReadBig);
    156  free(toWriteBig);
    157 
    158  // Currently bl contains these segments:
    159  // #0: offset 0, [0x0c]*16 + [0x0a]*8, size 24
    160  // #1: offset 24, [0x0a]*8 + [i%37 for i in 0..24], size 32
    161  // #2: offset 56, [i%37 for i in 24..56, size 32
    162  // ...
    163  // #32: offset 1016, [i%37 for i in 984..1016], size 32
    164  // #33: offset 1048, [i%37 for i in 1016..1024], size 8
    165 
    166  static size_t kTotalSize = kInitialSize + kSmallWrite + kBigWrite;
    167 
    168  MOZ_RELEASE_ASSERT(bl.Size() == kTotalSize);
    169 
    170  static size_t kLastSegmentSize =
    171      (kTotalSize - kInitialCapacity) % kStandardCapacity;
    172 
    173  iter = bl.Iter();
    174  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(
    175      bl, kTotalSize - kLastSegmentSize - kStandardCapacity));
    176  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kStandardCapacity);
    177  iter.Advance(bl, kStandardCapacity);
    178  MOZ_RELEASE_ASSERT(iter.RemainingInSegment() == kLastSegmentSize);
    179  MOZ_RELEASE_ASSERT(
    180      unsigned(*iter.Data()) ==
    181      (kTotalSize - kLastSegmentSize - kInitialSize - kSmallWrite) % 37);
    182 
    183  // Clear.
    184 
    185  bl.Clear();
    186  MOZ_RELEASE_ASSERT(bl.Size() == 0);
    187  MOZ_RELEASE_ASSERT(bl.Iter().Done());
    188 
    189  // Move assignment.
    190 
    191  const size_t kSmallCapacity = 8;
    192 
    193  BufferList bl2(0, kSmallCapacity, kSmallCapacity);
    194  MOZ_ALWAYS_TRUE(bl2.WriteBytes(toWrite, kSmallWrite));
    195  MOZ_ALWAYS_TRUE(bl2.WriteBytes(toWrite, kSmallWrite));
    196  MOZ_ALWAYS_TRUE(bl2.WriteBytes(toWrite, kSmallWrite));
    197 
    198  bl = std::move(bl2);
    199  MOZ_RELEASE_ASSERT(bl2.Size() == 0);
    200  MOZ_RELEASE_ASSERT(bl2.Iter().Done());
    201 
    202  iter = bl.Iter();
    203  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3));
    204  MOZ_RELEASE_ASSERT(iter.Done());
    205 
    206  // MoveFallible
    207 
    208  bool success;
    209  bl2 = bl.MoveFallible<InfallibleAllocPolicy>(&success);
    210  MOZ_RELEASE_ASSERT(success);
    211  MOZ_RELEASE_ASSERT(bl.Size() == 0);
    212  MOZ_RELEASE_ASSERT(bl.Iter().Done());
    213  MOZ_RELEASE_ASSERT(bl2.Size() == kSmallWrite * 3);
    214 
    215  iter = bl2.Iter();
    216  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kSmallWrite * 3));
    217  MOZ_RELEASE_ASSERT(iter.Done());
    218 
    219  bl = bl2.MoveFallible<InfallibleAllocPolicy>(&success);
    220 
    221  // Borrowing.
    222 
    223  const size_t kBorrowStart = 4;
    224  const size_t kBorrowSize = 24;
    225 
    226  iter = bl.Iter();
    227  iter.Advance(bl, kBorrowStart);
    228  bl2 = bl.Borrow<InfallibleAllocPolicy>(iter, kBorrowSize, &success);
    229  MOZ_RELEASE_ASSERT(success);
    230  MOZ_RELEASE_ASSERT(bl2.Size() == kBorrowSize);
    231 
    232  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(
    233      bl, kSmallWrite * 3 - kBorrowSize - kBorrowStart));
    234  MOZ_RELEASE_ASSERT(iter.Done());
    235 
    236  iter = bl2.Iter();
    237  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kBorrowSize));
    238  MOZ_RELEASE_ASSERT(iter.Done());
    239 
    240  BufferList::IterImpl iter1(bl.Iter()), iter2(bl2.Iter());
    241  iter1.Advance(bl, kBorrowStart);
    242  MOZ_RELEASE_ASSERT(iter1.Data() == iter2.Data());
    243  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl, kBorrowSize - 5));
    244  MOZ_RELEASE_ASSERT(iter2.AdvanceAcrossSegments(bl2, kBorrowSize - 5));
    245  MOZ_RELEASE_ASSERT(iter1.Data() == iter2.Data());
    246 
    247  // RangeLength.
    248 
    249  BufferList bl12(0, 0, 8);
    250  MOZ_ALWAYS_TRUE(bl12.WriteBytes("abcdefgh", 8));
    251  MOZ_ALWAYS_TRUE(bl12.WriteBytes("12345678", 8));
    252 
    253  // |iter| is at position 0 (1st segment).
    254  iter = bl12.Iter();
    255  iter1 = bl12.Iter();
    256  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0);
    257  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    258  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4);
    259  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    260  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 8);
    261  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    262  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 12);
    263  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 3));
    264  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 15);
    265  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1));
    266  MOZ_RELEASE_ASSERT(iter1.Done());
    267 
    268  // |iter| is at position 1 (1st segment).
    269  iter = bl12.Iter();
    270  iter1 = bl12.Iter();
    271  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl12, 1));
    272  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1));
    273  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0);
    274  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    275  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4);
    276  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    277  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 8);
    278  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    279  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 12);
    280  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 2));
    281  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 14);
    282  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1));
    283  MOZ_RELEASE_ASSERT(iter1.Done());
    284 
    285  // |iter| is at position 8 (2nd segment).
    286  iter = bl12.Iter();
    287  iter1 = bl12.Iter();
    288  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl12, 8));
    289  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 8));
    290  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0);
    291  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    292  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4);
    293  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 3));
    294  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 7);
    295  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1));
    296  MOZ_RELEASE_ASSERT(iter1.Done());
    297 
    298  // |iter| is at position 9 (2nd segment).
    299  iter = bl12.Iter();
    300  iter1 = bl12.Iter();
    301  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl12, 9));
    302  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 9));
    303  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 0);
    304  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 4));
    305  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 4);
    306  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 2));
    307  MOZ_RELEASE_ASSERT(bl12.RangeLength(iter, iter1) == 6);
    308  MOZ_RELEASE_ASSERT(iter1.AdvanceAcrossSegments(bl12, 1));
    309  MOZ_RELEASE_ASSERT(iter1.Done());
    310 
    311  BufferList bl13(0, 0, 8);
    312  MOZ_ALWAYS_TRUE(bl13.WriteBytes("abcdefgh", 8));
    313  MOZ_ALWAYS_TRUE(bl13.WriteBytes("12345678", 8));
    314  MOZ_ALWAYS_TRUE(bl13.WriteBytes("ABCDEFGH", 8));
    315  MOZ_RELEASE_ASSERT(bl13.Size() == 24);
    316 
    317  // At segment border
    318  iter = bl13.Iter();
    319  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 8));
    320  MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 16);
    321  MOZ_RELEASE_ASSERT(iter.Done());
    322  MOZ_RELEASE_ASSERT(bl13.Size() == 8);
    323 
    324  // Restore state
    325  MOZ_ALWAYS_TRUE(bl13.WriteBytes("12345678", 8));
    326  MOZ_ALWAYS_TRUE(bl13.WriteBytes("ABCDEFGH", 8));
    327  MOZ_RELEASE_ASSERT(bl13.Size() == 24);
    328 
    329  // Before segment border
    330  iter = bl13.Iter();
    331  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 7));
    332  MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 17);
    333  MOZ_RELEASE_ASSERT(iter.Done());
    334  MOZ_RELEASE_ASSERT(bl13.Size() == 7);
    335 
    336  // Restore state
    337  MOZ_ALWAYS_TRUE(bl13.WriteBytes("h", 1));
    338  MOZ_ALWAYS_TRUE(bl13.WriteBytes("12345678", 8));
    339  MOZ_ALWAYS_TRUE(bl13.WriteBytes("ABCDEFGH", 8));
    340  MOZ_RELEASE_ASSERT(bl13.Size() == 24);
    341 
    342  // In last segment
    343  iter = bl13.Iter();
    344  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 20));
    345  MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 4);
    346  MOZ_RELEASE_ASSERT(iter.Done());
    347  MOZ_RELEASE_ASSERT(bl13.Size() == 20);
    348 
    349  // No-op truncate
    350  MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 0);
    351  MOZ_RELEASE_ASSERT(iter.Done());
    352  MOZ_RELEASE_ASSERT(bl13.Size() == 20);
    353 
    354  // No-op truncate with fresh iterator
    355  iter = bl13.Iter();
    356  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl13, 20));
    357  MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 0);
    358  MOZ_RELEASE_ASSERT(iter.Done());
    359  MOZ_RELEASE_ASSERT(bl13.Size() == 20);
    360 
    361  // Truncate at start of buffer
    362  iter = bl13.Iter();
    363  MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 20);
    364  MOZ_RELEASE_ASSERT(iter.Done());
    365  MOZ_RELEASE_ASSERT(bl13.Size() == 0);
    366 
    367  // No-op truncate at start of buffer
    368  iter = bl13.Iter();
    369  MOZ_RELEASE_ASSERT(bl13.Truncate(iter) == 0);
    370  MOZ_RELEASE_ASSERT(iter.Done());
    371  MOZ_RELEASE_ASSERT(bl13.Size() == 0);
    372 
    373  return 0;
    374 }