8

Что такое ошибка сегментации?

5

Что такое ошибка сегментации? Есть ли разница между языками C и C++ в этом контексте? Как ошибки сегментации связаны с висячими указателями?

5 ответ(ов)

9

Сегментация (segmentation fault) – это специфический вид ошибки, вызванной попыткой доступа к памяти, которая «вам не принадлежит». Это защитный механизм, который предотвращает повреждение памяти и возникновение сложных для отладки ошибок, связанных с памятью. Когда у вас происходит сегфолт, это сигнализирует о том, что вы делаете что-то неверное в работе с памятью – например, обращаетесь к переменной, которая уже была освобождена, или пытаетесь записать в область памяти, защищённую от записи и т.д. Сегментация по сути одинакова во многих языках, позволяющих управлять памятью, и нет принципиальных различий между сегфолтами в C и C++.

Существует множество способов вызвать сегфолт, особенно в языках низкого уровня, таких как C(++). Один из распространённых случаев – это разыменование нулевого указателя:

int *p = NULL;
*p = 1; // Здесь произойдёт сегфолт

Ещё одна ошибка происходит, когда вы пытаетесь записать в область памяти, отмеченную как доступная только для чтения:

char *str = "Foo"; // Компилятор помечает константную строку как доступную только для чтения
*str = 'b'; // Это недопустимо и приведёт к сегфолту

«Висячий» указатель (dangling pointer) указывает на объект, который больше не существует, как в следующем примере:

char *p = NULL;
{
    char c;
    p = &c; // p указывает на c
}
// Теперь p стал висячим

Указатель p становится висячим, потому что он указывает на переменную c, которая прекратила своё существование после завершения блока. И когда вы пытаетесь разыменовать висячий указатель (например, *p='A'), вы, вероятно, получите сегфолт.

1

Следует отметить, что ошибка сегментации (segmentation fault) не вызывается прямым доступом к памяти другого процесса (что я иногда слышу), так как это просто невозможно. Виртуальная память предоставляет каждому процессу собственное виртуальное адресное пространство, и нет способа получить доступ к пространству другого процесса, используя любое значение указателя. Исключение составляют общие библиотеки, которые имеют одно и то же физическое адресное пространство, отображенное по (возможно) разным виртуальным адресам, и память ядра, которая вообще отображается одинаково в каждом процессе (по-моему, чтобы избежать сброса кэша TLB при системных вызовах). Также есть такие вещи, как shmat 😉, которые я считаю «косвенным» доступом. Тем не менее, можно проверить, что они обычно находятся далеко от кода процесса, и мы, как правило, можем получить к ним доступ (поэтому они там и есть), но неправильный доступ к ним приведет к ошибке сегментации.

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

И все это в контексте систем виртуальной памяти.

0

Сегментация (segmentation fault) возникает, когда процесс пытается обратиться к странице, которая не указана в его таблице дескрипторов, или делает недопустимый запрос к странице, которая в таблице есть (например, попытка записи в страницу, доступную только для чтения).

Ошибочный указатель (dangling pointer) — это указатель, который может указывать на действительную страницу, но в то же время указывает на «неожиданную» область памяти.

0

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

Проблема висячей ссылки (указателя) означает, что происходит попытка доступа к объекту или переменной, содержимое которых уже было удалено из памяти. Например:

int *arr = new int[20];
delete arr;
cout << arr[1];  // проблема висячей ссылки возникает здесь

В этом примере после вызова delete arr; память, на которую указывает arr, становится невалидной, и попытка доступа к arr[1] приводит к неопределённому поведению.

0

Простыми словами: ошибка сегментации — это сигнал от операционной системы к программе, который указывает на то, что было обнаружено illegal access к памяти. В результате, программа завершает свою работу преждевременно, чтобы предотвратить повреждение памяти.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь