SIGSEGV в дестукторе вектора при некорректном смещении итератора

128
10 декабря 2019, 23:40

В программе была найдена причина Segmentation Fault при освобождении памяти (в деструкторе вектора). Как оказалось, происходило смещение begin-итератора на отрицательное число с последующей записью данных по нему.

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

Код, воспроизводящий ошибку:

#include <vector>
#include <iostream>
int main()
{
    std::vector <unsigned> vec;
    vec.assign(5, 42);
    auto it = vec.begin();    
    std::advance(it, -1);
    std::fill(it, vec.end(), 10);
    for (const auto &item: vec) {
        std::cout << item << " ";
    }
    std::cout << std::endl;
    // наличие вывода показывает, что ошибка не на этапе записи
    return 0;
}
Answer 1

Понимаете, вы получаете UB - неопределенное поведение. А значит, может произойти что угодно и когда угодно.

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

Программа отработала. Выход, вызов деструкторов. В деструкторе нужно освободить память - а освободить из-за нарушенной служебной информации невозможно - почему именно - зависит от конкретной реализации, испорченных данных и т.д. Да это и неважно - как именно испорчено...

Вот и получается, что ошибка (вернее, UB) проявилась вот так, через какое-то время после того, как была сделана.

Answer 2

Если вы хотите представить, что могло случиться, то как говорится, под капотом этой ситуации с неопределенным поведением, может происходить следующее.

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

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

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

READ ALSO
Отправка GET/POST-запроса средствами чистого C++

Отправка GET/POST-запроса средствами чистого C++

Как реализовать простой GET/POST запрос без использования сторонних библиотек?

102
Как сделать текст курсивным в Qt

Как сделать текст курсивным в Qt

В продолжении вопроса

129
Какой лучше выставить glOrtho для 3d?

Какой лучше выставить glOrtho для 3d?

Для 2d я выставлял glOrtho так, чтобы начало координат было от левого нижнего угла и размером в размер экранаА в 3d я помню как то читал старую книгу...

96
C++ вопрос по CIN

C++ вопрос по CIN

Есть маленькая прогаммка, все ничего, но столкнулся с одной странной трудностьюПриложен код простой менюшки, которая обёрнута в цикл do while и через...

144