Почему при вставке больших целых чисел в мою таблицу ha sh возникает ошибка seg? - PullRequest
0 голосов
/ 29 апреля 2020

Я провел некоторое тестирование своего кода самостоятельно. Кто-нибудь знает, как избавиться от ошибок сегментации, вызванных, когда я вставляю тонну очень больших целых чисел без знака в мои списки ниже? Он не выдает ошибку сегмента, когда целые числа маленькие (я знаю, что программа работает нормально, когда я не добавляю 743677 к num в for-l oop, который я сделал в main.)

Я почти уверен, что мои forward_lists фактически не распределяются или не распределяются динамически. В моем отладчике размер lists равен нулю после выделения.

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cstdint>
#include <forward_list>
#include <cmath>
using namespace std;

class HashTable {
protected:
    uint32_t numTotalLists;
    uint64_t hashVal;
    virtual uint64_t hash(uint64_t) = 0;
public:
    HashTable();
    virtual ~HashTable() = default;
    virtual void insert(uint64_t) = 0;
};

HashTable::HashTable() {
    numTotalLists = 0;
    hashVal = 0;
}

class TrivialHashTable : public HashTable {
private:
    uint64_t hash(uint64_t) override;
    uint32_t roundUpBaseTwo(uint32_t);
    forward_list<uint64_t> * lists;
    short numBitsToMask;
public:
    explicit TrivialHashTable(uint32_t numIntegers) : HashTable() {
    //Trivial hash algorithm uses a table size that is a power of two.
    numTotalLists = numIntegers;
    numTotalLists = roundUpBaseTwo(numTotalLists);
    lists = new forward_list<uint64_t> [numTotalLists]; //Is this legal?
    numBitsToMask = log2(numTotalLists);
    }
    ~TrivialHashTable() override {
        delete [] lists;
    }
    void insert(uint64_t) override;
};

    void TrivialHashTable::insert(uint64_t val) {
        hashVal = hash(val);
        lists[hashVal].push_front(val);
    }

//Trivial Hash Algorithm: mask bottom log2(tableSize) bits out of val
uint64_t TrivialHashTable::hash(uint64_t val) {
    uint64_t mask = 1;
    for (short i = 0; i < numBitsToMask; i++) {
        mask = mask << 1;
        mask += 1;
    }
    val &= mask;
    return val;
}

//Function accepts a number, then rounds it up to the nearest number that is a power of two.
uint32_t TrivialHashTable::roundUpBaseTwo(uint32_t num) {
    num--;
    num |= num >> 1;
    num |= num >> 2;
    num |= num >> 4;
    num |= num >> 8;
    num |= num >> 16;
    num++;
    return num;
}

int main() {
    HashTable * hashTableTrivial = new TrivialHashTable(10000);

    cout << "Inserting into trivial hash table..." << endl;
    for (uint64_t num = 0; num < 1000000; num++) {
        hashTableTrivial->insert(num + 743677);
    }
    cout << "Inserted all data into trivial hash table." << endl;
    return 0;
}

1 Ответ

1 голос
/ 29 апреля 2020

Запуск вашей программы, скомпилированной с помощью g++ -g -fsanitize=address, показывает переполнение кучи:

Inserting into trivial hash table...
=================================================================
==82429==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7fae929a0808 at pc 0x559f40dfe0b9 bp 0x7ffe20f84330 sp 0x7ffe20f84328
READ of size 8 at 0x7fae929a0808 thread T0 ()
    #0 0x559f40dfe0b8 in std::_Fwd_list_node_base* std::_Fwd_list_base<unsigned long, std::allocator<unsigned long> >::_M_insert_after<unsigned long const&>(std::_Fwd_list_const_iterator<unsigned long>, unsigned long const&) /usr/include/c++/9/bits/forward_list.tcc:56
    #1 0x559f40dfddb7 in std::forward_list<unsigned long, std::allocator<unsigned long> >::push_front(unsigned long const&) /usr/include/c++/9/bits/forward_list.h:852
    #2 0x559f40dfd4ca in TrivialHashTable::insert(unsigned long) /tmp/t.cc:48
    #3 0x559f40dfd696 in main /tmp/t.cc:79
    #4 0x7fae9556abba in __libc_start_main ../csu/libc-start.c:308
    #5 0x559f40dfd209 in _start (/tmp/a.out+0x2209)

0x7fae929a0808 is located 0 bytes to the right of 131080-byte region [0x7fae92980800,0x7fae929a0808)
allocated by thread T750847 () here:
    #0 0x7fae95b3836f in operator new[](unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10936f)
    #1 0x559f40dfd97e in TrivialHashTable::TrivialHashTable(unsigned int) /tmp/t.cc:37
    #2 0x559f40dfd5f2 in main /tmp/t.cc:75
    #3 0x7fae9556abba in __libc_start_main ../csu/libc-start.c:308

Похоже, у вас возникла ошибка "по одному": в точке cra sh:

#7  0x00005555555564cb in TrivialHashTable::insert (this=0x604000000010, val=770048) at t.cc:48
48              lists[hashVal].push_front(val);
(gdb) p hashVal
$1 = 16384
(gdb) p numTotalLists
$2 = 16384
...