xpcom/tests/TestPLDHash.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include <stdio.h>
michael@0 8 #include "pldhash.h"
michael@0 9
michael@0 10 // pldhash is very widely used and so any basic bugs in it are likely to be
michael@0 11 // exposed through normal usage. Therefore, this test currently focusses on
michael@0 12 // extreme cases relating to maximum table capacity and potential overflows,
michael@0 13 // which are unlikely to be hit during normal execution.
michael@0 14
michael@0 15 namespace TestPLDHash {
michael@0 16
michael@0 17 static bool test_pldhash_Init_capacity_ok()
michael@0 18 {
michael@0 19 // Try the largest allowed capacity. With PL_DHASH_MAX_SIZE==1<<26, this
michael@0 20 // will allocate 0.5GB of entry store on 32-bit platforms and 1GB on 64-bit
michael@0 21 // platforms.
michael@0 22 PLDHashTable t;
michael@0 23 bool ok = PL_DHashTableInit(&t, PL_DHashGetStubOps(), nullptr,
michael@0 24 sizeof(PLDHashEntryStub), PL_DHASH_MAX_SIZE,
michael@0 25 mozilla::fallible_t());
michael@0 26 if (ok)
michael@0 27 PL_DHashTableFinish(&t);
michael@0 28
michael@0 29 return ok;
michael@0 30 }
michael@0 31
michael@0 32 static bool test_pldhash_Init_capacity_too_large()
michael@0 33 {
michael@0 34 // Try the smallest too-large capacity.
michael@0 35 PLDHashTable t;
michael@0 36 bool ok = PL_DHashTableInit(&t, PL_DHashGetStubOps(), nullptr,
michael@0 37 sizeof(PLDHashEntryStub), PL_DHASH_MAX_SIZE + 1,
michael@0 38 mozilla::fallible_t());
michael@0 39 // Don't call PL_DHashTableDestroy(), it's not safe after Init failure.
michael@0 40
michael@0 41 return !ok; // expected to fail
michael@0 42 }
michael@0 43
michael@0 44 static bool test_pldhash_Init_overflow()
michael@0 45 {
michael@0 46 // Try an acceptable capacity, but one whose byte size overflows uint32_t.
michael@0 47 //
michael@0 48 // Ideally we'd also try a large-but-ok capacity that almost but doesn't
michael@0 49 // quite overflow, but that would result in allocating just under 4GB of
michael@0 50 // entry storage. That's very likely to fail on 32-bit platforms, so such a
michael@0 51 // test wouldn't be reliable.
michael@0 52
michael@0 53 struct OneKBEntry {
michael@0 54 PLDHashEntryHdr hdr;
michael@0 55 char buf[1024 - sizeof(PLDHashEntryHdr)];
michael@0 56 };
michael@0 57
michael@0 58 // |nullptr| for |ops| is ok because it's unused due to the failure.
michael@0 59 PLDHashTable t;
michael@0 60 bool ok = PL_DHashTableInit(&t, /* ops = */nullptr, nullptr,
michael@0 61 sizeof(OneKBEntry), PL_DHASH_MAX_SIZE,
michael@0 62 mozilla::fallible_t());
michael@0 63
michael@0 64 return !ok; // expected to fail
michael@0 65 }
michael@0 66
michael@0 67 // See bug 931062, we skip this test on Android due to OOM.
michael@0 68 #ifndef MOZ_WIDGET_ANDROID
michael@0 69 // We insert the integers 0.., so this is has function is (a) as simple as
michael@0 70 // possible, and (b) collision-free. Both of which are good, because we want
michael@0 71 // this test to be as fast as possible.
michael@0 72 static PLDHashNumber
michael@0 73 hash(PLDHashTable *table, const void *key)
michael@0 74 {
michael@0 75 return (PLDHashNumber)(size_t)key;
michael@0 76 }
michael@0 77
michael@0 78 static bool test_pldhash_grow_to_max_capacity()
michael@0 79 {
michael@0 80 static const PLDHashTableOps ops = {
michael@0 81 PL_DHashAllocTable,
michael@0 82 PL_DHashFreeTable,
michael@0 83 hash,
michael@0 84 PL_DHashMatchEntryStub,
michael@0 85 PL_DHashMoveEntryStub,
michael@0 86 PL_DHashClearEntryStub,
michael@0 87 PL_DHashFinalizeStub,
michael@0 88 nullptr
michael@0 89 };
michael@0 90
michael@0 91 PLDHashTable t;
michael@0 92 bool ok = PL_DHashTableInit(&t, &ops, nullptr, sizeof(PLDHashEntryStub), 256,
michael@0 93 mozilla::fallible_t());
michael@0 94 if (!ok)
michael@0 95 return false;
michael@0 96
michael@0 97 // Keep inserting elements until failure occurs because the table is full.
michael@0 98 size_t numInserted = 0;
michael@0 99 while (true) {
michael@0 100 if (!PL_DHashTableOperate(&t, (const void*)numInserted, PL_DHASH_ADD)) {
michael@0 101 break;
michael@0 102 }
michael@0 103 numInserted++;
michael@0 104 }
michael@0 105
michael@0 106 // We stop when the element count is 96.875% of PL_DHASH_MAX_SIZE (see
michael@0 107 // MaxLoadOnGrowthFailure()).
michael@0 108 return numInserted == PL_DHASH_MAX_SIZE - (PL_DHASH_MAX_SIZE >> 5);
michael@0 109 }
michael@0 110 #endif
michael@0 111
michael@0 112 //----
michael@0 113
michael@0 114 typedef bool (*TestFunc)();
michael@0 115 #define DECL_TEST(name) { #name, name }
michael@0 116
michael@0 117 static const struct Test {
michael@0 118 const char* name;
michael@0 119 TestFunc func;
michael@0 120 } tests[] = {
michael@0 121 DECL_TEST(test_pldhash_Init_capacity_ok),
michael@0 122 DECL_TEST(test_pldhash_Init_capacity_too_large),
michael@0 123 DECL_TEST(test_pldhash_Init_overflow),
michael@0 124 // See bug 931062, we skip this test on Android due to OOM.
michael@0 125 #ifndef MOZ_WIDGET_ANDROID
michael@0 126 DECL_TEST(test_pldhash_grow_to_max_capacity),
michael@0 127 #endif
michael@0 128 { nullptr, nullptr }
michael@0 129 };
michael@0 130
michael@0 131 } // namespace TestPLDHash
michael@0 132
michael@0 133 using namespace TestPLDHash;
michael@0 134
michael@0 135 int main(int argc, char *argv[])
michael@0 136 {
michael@0 137 bool success = true;
michael@0 138 for (const Test* t = tests; t->name != nullptr; ++t) {
michael@0 139 bool test_result = t->func();
michael@0 140 printf("%25s : %s\n", t->name, test_result ? "SUCCESS" : "FAILURE");
michael@0 141 if (!test_result)
michael@0 142 success = false;
michael@0 143 }
michael@0 144 return success ? 0 : -1;
michael@0 145 }

mercurial