Подтвердить что ты не робот

Что может привести к ошибкам сегментации в С++?

Я заметил, что там не вопрос со списком распространенных причин ошибок сегментации в С++, поэтому я думал, что добавлю его.

Естественно, это сообщество Wiki, так как нет ни одного правильного ответа.

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

4b9b3361

Ответ 1

Ошибка сегментации вызвана плохим доступом к памяти, только если ваша ОС имеет MMU. В противном случае вы не получите его, а только странное поведение.

Виртуальная память (вся память, доступная для вас = 2 ^ sizeof(pointer type)) отображается в физическую память в единицах, называемых страницами или сегментами (пейджинг с замедленной сегментацией, но они все еще используются).

Каждая страница имеет некоторые права защиты, если вы попытаетесь прочитать со страницы без доступа к чтению, вы получите segfault. Если вы попытаетесь записать в исходное местоположение, вы получите SIGSEGV.

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

Кроме того, поскольку существует много страниц, не все из них действительно отображаются. Если вы коснетесь несвязанной страницы, вы получите segfault. Фактически, любой доступ к не сопоставленной странице должен учитывать учетную запись при записи, страницы на свопинге, ленивую загрузку, файлы с отображением памяти и другие вещи. См. в этой статье о работе с ошибками страницы, особенно вторая диаграмма, размещенная здесь ниже (но прочитайте статью для получения дополнительных пояснений)

page fault handling

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

Ответ 2

Разыменование NULL-указателей.

#include <cstddef> //For NULL.
int* p1 = NULL; //p1 points to no memory address
*p1 = 3; //Segfault.

Ответ 3

Доступ к массиву за пределами (возможно):

int ia[10];
ia[10] = 4; // Someone forgot that arrays are 0-indexed! Possible Segfault.

Ответ 4

Многие из способов "segfault" С++ не обязательно гарантировано, на самом деле, так обстоит дело с большинством приведенных здесь примеров. Это просто удача (или неудача, в зависимости от того, как вы смотрите на нее!), Если вы можете выполнять эти операции без возникновения segfault.

На самом деле это одна из вещей на С++, которая отделяет ее от других языков; undefined. Если в Java или С# вы можете получить "InvalidOperationException" или подобное, что гарантировано произойдет, когда эти операции будут выполнены; в С++ стандарт просто говорит "undefined поведение", что в основном является удачей ничьей, и вы никогда не хотите, чтобы это произошло.

Ответ 5

Один из моих любимых:

#include <iostream>
struct A {
    virtual void f() {
        std::cout << "A::f();\n";
    }
    int i;
};

struct B : A {
    virtual void f() {
        std::cout << "B::f();\n";
    }
    int j;
};

void seti(A* arr, size_t size) {
    for (size_t i = 0; i < size; ++i)
        arr[i].i = 0;
}

int main() {
    B b[10];
    seti(b, 10);
    b[3].f();
}

Как и большинство вещей, которые могут вызвать segfault, это также может не сработать. Например, на ideone b[3].f() завершается сбой, но b[2].f() работает.

Ответ 6

Очевидным ответом является "поведение undefined", но это требует вопрос для неопытного программиста и некоторые типы Поведение undefined значительно реже вызывает ошибку сегментации (или другой тип сбоя), чем другие. Наиболее частые причины ошибки сегментации обычно связаны с указателем: разыменование неинициализированный указатель, нулевой указатель или ранее освобожденный указатель; доступ за пределами конца (или перед началом, но что меньше частый) объекта (массив или другой); используя результаты незаконного pointer cast (static_cast к производному типу, когда объект не на самом деле имеют этот тип или большинство reinterpret_cast); и др.

Возможно, самым важным моментом, который следует помнить здесь, является то, что в целом, они не гарантируют причину ошибки сегментации и что часто возникает ошибка сегментации, которую они вызывают. через некоторое время, в совершенно не связанной с этим операции. Таким образом, за пределами локального массива, как правило, "работают", но будет изменять все, что происходит, чтобы следовать за массивом в стеке: некоторые другая локальная переменная (изменение vptr объекта в стеке может привести к ошибке сегментации при попытке вызвать виртуальную функция на объекте), указатель кадра вызывающей функции (что, вероятно, вызовет ошибку сегментации в этой функции, после вы вернулись) или обратный адрес (который может вызвать всевозможные странное поведение - ошибка сегментации или незаконная инструкция ловушка, вероятно, лучшее, что может произойти). Запись за пределами освобожденная память или уже освобожденный указатель, может испортить космическая арена, вызывающая ошибку сегментации в много (иногда много, много) позже распределения или бесплатно; он также может модифицировать некоторые другие, полностью несвязанный объект, развращая его vptr или какой-либо другой указатель в объект или просто некоторые случайные данные, опять же, ошибка сегментации вероятно, наилучший результат (гораздо предпочтительнее поврежденные данные).

Ответ 7

Забыть инициализировать указатели, оставив их со случайными адресами памяти. Примечание: это может быть не всегда segfault, но это возможно.

int* p1; //No initialization.
*p1 = 3; //Possible segfault.

Ответ 8

Разблокированная освобожденная память может потенциально вызвать segfault.

SomeClass* someObject = new SomeClass();
delete someObject;
someObject->someMethod();  //Could cause a segfault.

Ответ 9

Попытка изменить строковые литералы:

char* mystr = "test";
mystr[2] = 'w';

Эта CAN вызывает ошибку сегментации.