Повреждение кучи в C ++, но только в модульном тестовом проекте - PullRequest
2 голосов
/ 08 октября 2019

Я реализую собственный стек с шаблонами. Но я столкнулся с проблемой, заставляющей меня сомневаться в безопасности памяти. Деструктор работает нормально при обычном использовании, но вызывает модульное тестирование повреждения кучи. Специально для тестов, которые ожидают исключения.

Весь код стека.

#pragma once
#include "StackOverflowException.h"
#include "StackEmptyException.h"

template <class T>
class Stack
{
public:
    const static int MAX_SIZE = 1000;

    Stack() : m_array(new T[MAX_SIZE]), m_size(0), m_top(0) {};
    Stack(const Stack<T>& _other)
    {
        m_array = new T[MAX_SIZE];
        for(auto i = 0; i < _other.size(); ++i)
        {
            m_array[i] = _other.m_array[i];
        }
        m_size = _other.size();
        m_top = _other.m_top;
    }

    ~Stack()
    {
        delete[] m_array;
    }

    void push(T _item)
    {
        if (m_size + 1 == MAX_SIZE + 1)
        {
            throw StackOverflowException();
        }
        m_array[++m_top] = _item;
        ++m_size;
    }

    T pop()
    {
        if(m_top != 0)
        {
            --m_size;
            T item =  m_array[m_top];
            --m_top;
            return item;
        }
        throw StackEmptyException();
    }

    T peek() const
    {
        if (m_size == 0) throw StackEmptyException();
        T item = m_array[m_top];
        return item;
    }

    bool empty() const
    {
        return m_size == 0;
    }

    size_t size() const
    {
        return m_size;
    }
private:
    T* m_array;
    size_t m_size;
    int m_top;
};

Модульные тесты, вызывающие повреждение кучи.


        TEST_METHOD(CustomStackPopException)
        {
            Stack<int> stack;
            Assert::ExpectException<StackEmptyException>([&] { stack.pop(); });
        }

        TEST_METHOD(CustomStackPeekException)
        {
            Stack<int> stack;
            Assert::ExpectException<StackEmptyException>([&] { int a = stack.peek(); });
        }

        TEST_METHOD(CustomStackOverflowException)
        {
            Stack<int> stack;
            const auto functor = [&]
            {
                for(auto i = 0; i <= Stack<int>::MAX_SIZE; ++i)
                {
                    stack.push(i);
                }
            };
            Assert::ExpectException<StackOverflowException>(functor);
        }

Когдаон достигает первого из этих тестов, выдает всплывающее предупреждение:

HEAP CORRUPTION DETECTED: after Normal block(#279) at 0x0000020298CBC60.
CRT detected that the application wrote to memory after end of heap buffer.

Я пытался создать объекты стека в куче, но это приводит к той же ошибке.

Ответы [ 3 ]

3 голосов
/ 08 октября 2019

Эта функция-член

void push(T _item)
{
    if (m_size + 1 == MAX_SIZE + 1)
    {
        throw StackOverflowException();
    }
    m_array[++m_top] = _item;
    ++m_size;
}

уже неверна. Предположим, что MAX_SIZE равен 1, а m_size равен 0. В этом случае m_size + 1 не равен MAX_SIZE + 1, и за выделенным массивом есть запись

    m_array[1] = _item;

.

Редактировать: после того, как вы изменили метод следующим образом

  void push(T _item)
    {
        if (m_size + 1 > MAX_SIZE)
        {
            throw StackOverflowException();
        }
        m_array[++m_top] = _item;
        ++m_size;
    }

после того, как я указал на проблему с ним, на самом деле метод имеет ту же проблему. На самом деле вы ничего не похитили.

Также ваш стек не заполняет элемент с индексом 0. Так что в конструкторе

Stack(const Stack<T>& _other)
{
    m_array = new T[MAX_SIZE];
    for(auto i = 0; i < _other.size(); ++i)
    {
        m_array[i] = _other.m_array[i];
    }
    m_size = _other.size();
    m_top = _other.m_top;
}

есть доступ к элементу с неопределенным значением впозиция 0

Нажатие функции-члена должно быть определено как

void push( const T &_item)
{
    if (m_size == MAX_SIZE)
    {
        throw StackOverflowException();
    }
    m_array[m_top++] = _item;
    ++m_size;
}

, а другие функции-члены должны быть изменены в соответствии с нажимом функции-члена.

0 голосов
/ 08 октября 2019

Благодаря комбинации пользователей проблема была исправлена. Это была функция push, которая вызвала ошибку.

Функция push была изменена с:

  void push(T _item)
    {
        if (m_size + 1 == MAX_SIZE + 1)
        {
            throw StackOverflowException();
        }
        m_array[++m_top] = _item;
        ++m_size;
    }

На:

    void push(T _item)
    {
        if (m_size == MAX_SIZE)
        {
            throw StackOverflowException();
        }
        m_array[m_size] = _item;
        ++m_size;
        ++m_top;
    }

Конструктор был изменен с:

    Stack() : m_array(new T[MAX_SIZE]), m_size(0), m_top(0) {};

до

    Stack() : m_array(new T[MAX_SIZE]), m_size(0), m_top(-1) {};

Теперь размер и вершина больше не совпадают, и m_top фактически указывает на вершину стека.

0 голосов
/ 08 октября 2019

Используйте номер выделения

HEAP CORRUPTION DETECTED: after Normal block(#279) at 0x0000020298CBC60.
CRT detected that the application wrote to memory after end of heap buffer.

Затем куда-нибудь при запуске вставьте

_CrtSetBreakAlloc(279);

Это покажет вам, где выделена память, и должно дать большой совет о том, где повреждениеis.

Зачем самому управлять им?

Не реализовывать stack себя

STL уже имеет этот контейнер

template <class T>
using my_stack = std::stack< T, std::vector<T> >;
...