неверный указатель при запуске GTest

Проблема в следующем:

Ошибка в `./runTests': free(): неверный указатель: 0x00007fdb92fe27a0 Прервано

Набор тестов:

#include "serial/BufferWrapper.h"
#include <iostream>
#include <memory>
#include <gtest/gtest.h>


#define STREAM_LEN 128

using namespace std;

namespace {

// The fixture for testing class BufferWrapperTest.
class BufferWrapperTest : public ::testing::Test
{
public:
    // Objects declared here can be used by all tests.
    unique_ptr<serial::BufferWrapper> bw;

    BufferWrapperTest() :
        bw((unique_ptr<serial::BufferWrapper>) new serial::BufferWrapper())
    {}

    //virtual ~BufferWrapperTest(){}

    // If the constructor and destructor are not enough for setting up
    // and cleaning up each test, you can define the following methods:

    //virtual void SetUp() {
        // Code here will be called immediately after the constructor (right
        // before each test).
    //}

    //virtual void TearDown() {
        // Code here will be called immediately after each test (right
        // before the destructor).
    //}

}; // BufferWrapperTest

/*! tests that checksum works in buffer wrapper */
TEST_F(BufferWrapperTest, CheckSum) {

    std::vector<unsigned char> test_vec;

    test_vec.push_back('0');      // us1
    test_vec.push_back('0');      // us2
    test_vec.push_back('0');      // ir1
    test_vec.push_back('0');      // ir2
    test_vec.push_back('0');      // ir3
    test_vec.push_back('0');      // wheel
    test_vec.push_back('0');      // dis1
    test_vec.push_back('0');      // dis2
    test_vec.push_back('0');       // dis3
    test_vec.push_back('0');       // dis4
    test_vec.push_back('0');       // light

    ASSERT_EQ((unsigned char) 48, bw->checksum(test_vec));

    // clear after first test
    test_vec.clear();

    test_vec.push_back('2');      // us1
    test_vec.push_back('3');      // us2
    test_vec.push_back('4');      // ir1
    test_vec.push_back('5');      // ir2
    test_vec.push_back('6');      // ir3
    test_vec.push_back('0');      // wheel
    test_vec.push_back('0');      // dis1
    test_vec.push_back('0');      // dis2
    test_vec.push_back('0');       // dis3
    test_vec.push_back('0');       // dis4
    test_vec.push_back('0');       // light

    ASSERT_EQ((unsigned char) 54, bw->checksum(test_vec));
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Функция checksum:

unsigned char serial::BufferWrapper::checksum(const std::vector<unsigned char> pkt)
{
    unsigned char chksum = 0;
    if (pkt.size() == 0) return chksum;
    for (auto it = pkt.begin(); it != pkt.end(); ++it) {
        // the checksum is calculated by XOR all elements
        chksum = (unsigned char)(chksum ^ *it);
    }
    return chksum;
}

РЕДАКТИРОВАТЬ *: добавлено serial::BufferWrapper

#include <iostream>
#include <iomanip>
#include <mutex>
#include <algorithm>
#include "serial/BufferWrapper.h"
#include "containerfactory/SBDContainer.h"

using namespace std;

// append receive buffer mutex
std::mutex arb;
// append send buffer mutex
std::mutex asb;
// read send buffer mutex
std::mutex rsm;
// read receive buffer mutex
std::mutex rrm;

/*! constructor */
serial::BufferWrapper::BufferWrapper() : buffer_in({}), buffer_out({})
{
    cout << "creating buffer wrapper... ";
    cout << "[OK]" << endl;
}


/*! destructor */
serial::BufferWrapper::~BufferWrapper()
{
    cout << "destroying buffer wrapper... ";
    cout << "[OK]" << endl;
}


/*! appends a correct packet to the receive buffer */
void serial::BufferWrapper::appendReceiveBuffer(vector<unsigned char> data)
{
    // lock mutex
    arb.lock();
    // return if the length of the vedcor is too short
    if (data.size() < SBDPKTSIZE) {
        // unlock mutex
        arb.unlock();
        return;
    }
    // the vector to hold the correct packet
    vector<unsigned char> valid_pkt;
    // loop through the received data from the read and look
    // for a correct packet
    for (auto it = data.begin(); it != data.end(); it++) {
        if (it + SBDPKTSIZE > data.end()) {
            break;
        }
        if (*it == DEL_ONE && *(it+DEL_TWO_POS) == DEL_TWO &&
                *(it+DEL_DBCOLON_POS) == DEL_DBCOLON && *(it+DEL_COMMA_POS) == DEL_COMMA) {
            unsigned char us1 = *(it+US1_POS);
            //printf("US1:%i ", us1);
            unsigned char us2 = *(it+US2_POS);
            //printf("US2:%i ", us2);
            unsigned char ir1 = *(it+IR1_POS);
            //printf("IR1:%i ", ir1);
            unsigned char ir2 = *(it+IR2_POS);
            //printf("IR2:%i ", ir2);
            unsigned char ir3 = *(it+IR3_POS);
            //printf("IR3:%i ", ir3);
            unsigned char wheel = *(it+WHL_POS);
            //printf("WHEEL:%i ", wheel);
            unsigned char dis1 = *(it+DIS_POS_1);
            //printf("DIS1:%i ", dis1);
            unsigned char dis2 = *(it+DIS_POS_2);
            //printf("DIS2:%i ", dis2);
            unsigned char dis3 = *(it+DIS_POS_3);
            //printf("DIS3:%i ", dis3);
            unsigned char dis4 = *(it+DIS_POS_4);
            //printf("DIS4:%i ", dis4);
            unsigned char light = *(it+LIGHT_SEN);
            //printf("LIGHT:%i ", light);
            unsigned char check = *(it+CHK_SUM);
            //printf("CHECK:%i\n", check);
            // fill the vector
            valid_pkt = {us1, us2, ir1, ir2, ir3, wheel, dis1, dis2, dis3, dis4, light};
            // check if correct checksum
            if (check == checksum(valid_pkt)) {
                cout << "checksum OK" << endl;
                break;
            }
            else {
                cout << "checksum FAIL" << endl;
                // clear the return vector
                valid_pkt.clear();
                // find where next packet starts
                it = find(it+1, data.end(), DEL_ONE);
                // if not found, break
                if (it == data.end()) break;
            }
        }
    }
    // push in front of the buffer if valid data
    if (valid_pkt.size() != 0) {
        buffer_in.push_front(valid_pkt);
    }
    // unlock mutex
    arb.unlock();
}


/*! returns the most recent valid packet from the read buffer */
vector<unsigned char> serial::BufferWrapper::readReceiveBuffer(void)
{
    rrm.lock();
    // check for size, i.e. not empty
    if(buffer_in.size() != 0)
    {
        // get 3the most recent packet, always in first position
        std::vector<unsigned char> vec = buffer_in.at(0);
        // clear the buffer
        buffer_in.clear();
        rrm.unlock();
        return vec;
    }
    else
    {
        rrm.unlock();
        return {};
    }
}


/*! appends a correct packet to the send buffer */
void serial::BufferWrapper::appendSendBuffer(vector<unsigned char> vec)
{
    // lock mutex
    asb.lock();
    buffer_out.push_front(vec);
    // and unlock after append
    asb.unlock();
}


/*! returns the most recent valid packet from the send buffer */
vector<unsigned char> serial::BufferWrapper::readSendBuffer(void)
{
    rsm.lock();
    // check for size, i.e. not empty
    if(buffer_out.size() != 0)
    {
        // get the most recent packet, always in first position
        vector<unsigned char> v = buffer_out.at(0);
        // clear the buffer
        buffer_out.clear();
        rsm.unlock();
        return v;
    }
    else
    {
        rsm.unlock();
        return {};
    }
}


/*! calculates and returns the checksum for a valid packet */
unsigned char serial::BufferWrapper::checksum(const std::vector<unsigned char> pkt)
{
    unsigned char chksum = 0;
    if (pkt.size() == 0) return chksum;
    for (auto it = pkt.begin(); it != pkt.end(); ++it) {
        // the checksum is calculated by XOR all elements
        chksum = (unsigned char)(chksum ^ *it);
    }
    return chksum;
}

РЕДАКТИРОВАТЬ * добавил объявление:

namespace serial
{
    class BufferWrapper
    {
    public:
        /*! constructor */
        BufferWrapper();
        /*! destructor */
        ~BufferWrapper();
        /*! appends data read from the serial to the receive buffer */
        void appendReceiveBuffer(std::vector<unsigned char>);
        /*! returns a valid packet from the receive buffer */
        std::vector<unsigned char> readReceiveBuffer(void);
        /*! appends to the send buffer data to write to the serial */
        void appendSendBuffer(std::vector<unsigned char>);
        /*! returns a valid packet to write to the serial */
        std::vector<unsigned char> readSendBuffer(void);
        /*! returns the checksum for a valid packet */
        unsigned char checksum(const std::vector<unsigned char>);
    private:
        /*! the receive buffer */
        std::deque<std::vector<unsigned char>> buffer_in;
        /*! the send buffer */
        std::deque<std::vector<unsigned char>> buffer_out;
    };
}

Полная распечатка запуска теста:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from BufferWrapperTest
[ RUN      ] BufferWrapperTest.CheckSum
creating buffer wrapper... [OK]
destroying buffer wrapper... [OK]
[       OK ] BufferWrapperTest.CheckSum (1 ms)
[----------] 1 test from BufferWrapperTest (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[  PASSED  ] 1 test.
*** Error in `./runTests': free(): invalid pointer: 0x00007fdb92fe27a0 ***
Aborted

Почему это происходит, когда тест запускается и завершается, а указатель в наборе тестов создается и уничтожается?


person tik    schedule 03.05.2016    source источник
comment
Какая платформа/ОС? Использовать валгринд? Как выглядит serial::BufferWrapper? так далее   -  person paulm    schedule 03.05.2016
comment
ОС - Линукс Минт. Добавил serial::BufferWrapper.   -  person tik    schedule 03.05.2016
comment
Ошибка возникает после выполнения всего набора тестов. Попробуйте запустить тестовый исполняемый файл в gdb и посмотрите, как выглядит стек вызовов.   -  person Antonio Pérez    schedule 03.05.2016
comment
@AntonioPérez Я сделал, и проблема, похоже, в том, что deque используется в BufferWrapper. Я пытался уничтожить его с помощью ~deque(), но все равно. Как это сделать?   -  person tik    schedule 03.05.2016
comment
Не могли бы вы включить объявление класса, чтобы мы знали, какой член deque?   -  person Antonio Pérez    schedule 03.05.2016
comment
@AntonioPérez Готово. Добавил заголовочный файл.   -  person tik    schedule 03.05.2016
comment
Вам нужно запустить под valgrind, чтобы найти, когда происходит повреждение памяти, плохое освобождение - это просто симптом   -  person paulm    schedule 03.05.2016


Ответы (1)


Могу поспорить, что проблема в этой инициализации:

bw((unique_ptr<serial::BufferWrapper>) new serial::BufferWrapper())

Здесь вы выделяете один объект serial::BufferWrapper, но затем вы приводите указатель к std::unique_ptr<...> объекту, что означает, что компилятор вызовет std::unique_ptr<...> движение конструктор. Конструктор, который должен вызываться, должен принимать указатель на обернутый тип.

Итак, чтобы решить проблему, просто пропустите кастинг и сделайте

bw(new serial::BufferWrapper)

Урок здесь? Никогда никогда не использовать приведение типов C в C++.

person Some programmer dude    schedule 03.05.2016