Что такое ошибка сегментации? Различие в C и С++? Как связаны связанные с сегментацией ошибки и оборванные указатели?
Ошибка сегментации - это определенная ошибка, вызванная доступом к памяти, которая "не принадлежит вам". Это вспомогательный механизм, который мешает вам разлагать память и вводить жесткие ошибки памяти. Всякий раз, когда вы получаете segfault, вы знаете, что делаете что-то не так с памятью - доступ к переменной, которая уже была освобождена, запись в часть только для чтения в памяти и т.д. Ошибка сегментации по сути одинакова на большинстве языков, которые позволяют вам возиться с управления памятью, нет принципиальной разницы между segfaults в C и С++.
Существует много способов получить segfault, по крайней мере, на языках более низкого уровня, таких как C (++). Общим способом получения segfault является разыменование нулевого указателя:
int *p = NULL;
*p = 1;
Другое segfault происходит, когда вы пытаетесь записать часть памяти, помеченную как только для чтения:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
Висячий указатель указывает на вещь, которая больше не существует, например здесь:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
Указатель p
зависает, потому что он указывает на символьную переменную c
, которая перестала существовать после завершения блока. И когда вы пытаетесь разыменовать висячий указатель (например, *p='A'
), вы, вероятно, получите segfault.
Стоит отметить, что ошибка сегментации не вызвана прямым доступом к другой памяти процесса (это то, что я иногда слышу), поскольку это просто невозможно. С виртуальной памятью каждый процесс имеет собственное виртуальное адресное пространство, и нет доступа к другому, используя любое значение указателя. Исключение из этого могут быть разделяемые библиотеки, которые представляют собой одно и то же физическое адресное пространство, сопоставляемое (возможно) с разными виртуальными адресами и памятью ядра, которые, как я думаю, даже сопоставляются одинаково в каждом процессе (во избежание TLB-промывки в syscall). И такие вещи, как shmat;) - вот что я считаю "косвенным" доступом. Тем не менее, можно проверить, что они, как правило, расположены далеко от кода процесса, и мы обычно можем получить к ним доступ (вот почему они есть, тем не менее доступ к ним ненадлежащим образом приведет к ошибке сегментации).
Тем не менее, ошибка сегментации может произойти в случае неправильного доступа к нашей собственной (процессуальной) памяти (например, попытка записи в незаписываемое пространство). Но наиболее распространенной причиной этого является доступ к части виртуального адресного пространства, которое вообще не отображается на физическое.
И все это в отношении систем виртуальной памяти.
Ошибка сегментации вызвана запросом страницы, которую процесс не указал в своей таблице дескриптора, или неверным запросом для страницы, которую она указала (например, запрос на запись на странице только для чтения).
Висячий указатель - это указатель, который может или не указывать на действительную страницу, но указывает на "неожиданный" сегмент памяти.
Честно говоря, как отмечали другие плакаты, в Википедии есть очень хорошая статья об этом так что посмотрите там. Этот тип ошибки очень часто встречаются и часто называются другими вещами, такими как Нарушение доступа или Обнаружение общей защиты.
Они ничем не отличаются на C, С++ или любом другом языке, который позволяет указывать. Такие ошибки обычно вызваны указателями
В то время как ответ Zoul объясняет, что такое ошибка сегментации, я обнаружил, что такие ошибки могут быть особенно трудно поймать, особенно если вы новичок в низкоуровневых языках, таких как С++ или C. Вот некоторые из распространенных способов для получения ошибки сегментации в вашей программе:
Неправильная строка управления форматом в операторах printf
или scanf
Строка управления форматом должна иметь одинаковое количество спецификаторов преобразования (%s
, %d
и т.д.), поскольку printf
или scanf
имеют аргументы для печати или чтения. То же самое относится к fprintf
и fscanf
.
Не использовать &
для аргументов scanf
Функция scanf
принимает в качестве аргументов строку управления форматом и адреса переменных, в которые она поместит данные, которые она читает. Оператор &
(адрес) используется для указания адреса переменной.
Ссылки на массив вне границ
Убедитесь, что вы не нарушили границы любого массива, который вы используете; т.е. вы не индексировали массив со значением, меньшим, чем индекс его самого нижнего элемента, или больше, чем индекс его самого высокого элемента. Valgrind
может оказаться полезным для обнаружения таких ссылок - вы можете использовать Valgrind
с флагом --tool=exp-sgcheck
.
Доступ к неинициализированным указателям
Перед обращением к переменной указателя должен быть присвоен действительный адрес. Убедитесь, что вы указали все указатели на допустимую область памяти.
Неправильное использование операторов &
(адрес) и *
(разыменование)
Вам нужно быть осторожным при их использовании, особенно при передаче параметров по ссылке/с помощью указателей.
Ограничения оболочки
Иногда ошибки сегментации не вызваны ошибками в программе, а вызваны тем, что ограничения системной памяти установлены слишком низко. Обычно это ограничение на размер стека вызывает такую проблему (переполнение стека). Чтобы проверить пределы памяти, используйте команду ulimit
в bash
.
Отладка с использованием gdb
Вы можете использовать отладчик gdb
, чтобы просмотреть обратную трассировку файла core
, сбрасываемого вашей программой. Всякий раз, когда программы segfault, они обычно выгружают содержимое памяти во время сбоя в файл core
(core dumped
). Скомпилируйте свою программу с помощью флага -g
, запустите в gdb
и используйте bt
(backtrace).
Согласно википедии:
Ошибка сегментации возникает, когда программа пытается получить доступ к памяти местоположение, которое не допускается доступ или попытки доступа к памяти местоположение не допускается (например, попытка написать только для чтения или для перезаписи часть операционной системы).
Ошибка сегментации также вызвана аппаратными сбоями, в этом случае память RAM. Это менее распространенная причина, но если вы не нашли ошибку в своем коде, возможно, memtest может вам помочь.
Решение в этом случае изменит ОЗУ.
изменить:
Здесь есть ссылка: Ошибка сегментации аппаратным обеспечением
Ошибка сегментации возникает, когда процесс (исполняемый экземпляр программы) пытается получить доступ к адресу памяти только для чтения или диапазону памяти, который используется другим процессом или к доступу к несуществующему (недопустимому) адресу памяти. Ошибка ссылки (указатель) означает, что попытка доступа к объекту или переменной, содержимое которой уже было удалено из памяти, например:
int *arr = new int[20];
delete arr;
cout<<arr[1]; //dangling problem occurs here
Wikipedia Segmentation_fault страница имеет очень хорошее описание об этом, просто указывая причины и причины. Посмотрите в wiki для подробного описания.
При вычислении ошибка сегментации (часто сокращается до segfault) или нарушение доступа - это ошибка, вызванная аппаратным обеспечением с защитой памяти, уведомление операционной системы (ОС) о нарушении доступа к памяти.
Ниже приводятся некоторые типичные причины ошибки сегментации:
Это, в свою очередь, часто вызвано ошибками программирования, которые приводят к недопустимому доступу к памяти:
Выделение или назначение неинициализированному указателю (дикий указатель, указывающий на случайный адрес памяти)
Разыменование или назначение освобожденному указателю (оборванный указатель, который указывает на освобожденную/удаленную память/удаленную)
Переполнение буфера.
Переполнение стека.
Попытка выполнить программу, которая не компилируется правильно. (Некоторые компиляторы выдают исполняемый файл, несмотря на наличие ошибок времени компиляции.)
Простыми словами: ошибка сегментации - это операционная система, отправляющая сигнал программе заявив, что обнаружил незаконный доступ к памяти и преждевременно прекращает программу для предотвращения память от повреждения.
В ответах есть несколько хороших объяснений "ошибки сегментации", но поскольку с ошибкой сегментации часто возникает дамп содержимого памяти, я хотел бы рассказать, где взаимосвязь между "сбрасываемой" частью в ошибке сегментации (сбрасывание ядра) и память происходит от:
С 1955 по 1975 год - до полупроводниковой памяти - в доминирующей технологии в компьютерной памяти использовались крошечные магнитные пончики, нанизанные на медные провода. Донки были известны как "ферритовые сердечники" и основная память, известная как "основная память" или "ядро".
Взято отсюда.
Ошибка сегментации или нарушение прав доступа происходит, когда программа пытается получить доступ к недоступной ячейке памяти или пытается получить доступ к ячейке памяти способом, который не разрешен.
/* "Array out of bounds" error
valid indices for array foo
are 0, 1, ... 999 */
int foo[1000];
for (int i = 0; i <= 1000 ; i++)
foo[i] = i;
Здесь я [1000] не существует, поэтому возникает segfault.
Причины сбоя сегментации:
it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.
De-referencing NULL pointers – this is special-cased by memory management hardware.
Attempting to access a nonexistent memory address (outside process’s address space).
Attempting to access memory the program does not have rights to (such as kernel structures in process context).
Attempting to write read-only memory (such as code segment).