Введение
В вычислительной технике, ошибка сегментации (часто сокращается до segfault) или нарушение доступа – это ошибка или состояние сбоя, генерируемое аппаратным обеспечением с защитой памяти, уведомляющее операционную систему (ОС) о том, что программное обеспечение предприняло попытку доступа к запрещенной области памяти (нарушение доступа к памяти). На стандартных компьютерах x86 это является формой общей ошибки защиты. Ядро операционной системы в ответ обычно выполняет корректирующие действия, как правило, передавая ошибку нарушившему процессу, отправляя процессу сигнал. Процессы в некоторых случаях могут установить собственный обработчик сигналов, позволяя им самостоятельно восстанавливаться, но в противном случае используется обработчик сигналов по умолчанию ОС, что обычно приводит к аварийному завершению процесса (сбою программы), а иногда и к созданию дампа памяти. Ошибки сегментации – это распространенный класс ошибок в программах, написанных на языках, таких как C, которые предоставляют доступ к памяти низкого уровня и практически не осуществляют проверок безопасности. Они возникают главным образом из-за ошибок при использовании указателей для адресации виртуальной памяти, особенно при незаконном доступе. Другой тип ошибки доступа к памяти – ошибка шины, которая также имеет различные причины, но в настоящее время встречается гораздо реже; она возникает в основном из-за некорректной адресации физической памяти или из-за невыровненного доступа к памяти – это ссылки на память, которые аппаратное обеспечение не может адресовать, а не ссылки, к которым процесс не имеет права доступа. Многие языки программирования имеют механизмы, предназначенные для предотвращения ошибок сегментации и повышения безопасности памяти. Например, Rust использует модель, основанную на владении, для обеспечения безопасности памяти. Другие языки, такие как Lisp и Java, используют сборку мусора, что позволяет избежать определенных классов ошибок памяти, которые могут привести к ошибкам сегментации.
In computing, a segmentation fault (often shortened to segfault) or access violation is a fault, or failure condition, raised by hardware with memory protection, notifying an operating system (OS) the software has attempted to access a restricted area of memory (a memory access violation). On standard x86 computers, this is a form of general protection fault. The operating system kernel will, in response, usually perform some corrective action, generally passing the fault on to the offending process by sending the process a signal. Processes can in some cases install a custom signal handler, allowing them to recover on their own, but otherwise the OS default signal handler is used, generally causing abnormal termination of the process (a program crash), and sometimes a core dump. Segmentation faults are a common class of error in programs written in languages like C that provide low level memory access and few to no safety checks. They arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access. Another type of memory access error is a bus error, which also has various causes, but is today much rarer; these occur primarily due to incorrect physical memory addressing, or due to misaligned memory access – these are memory references that the hardware cannot address, rather than references that a process is not allowed to address. Many programming languages have mechanisms designed to avoid segmentation faults and improve memory safety. For example, Rust employs an ownership based model to ensure memory safety. Other languages, such as Lisp and Java, employ garbage collection, which avoids certain classes of memory errors that could lead to segmentation faults.
Обзор
Ошибка сегментации возникает, когда программа пытается получить доступ к области памяти, к которой у неё нет прав доступа, или пытается получить доступ к области памяти недопустимым способом (например, пытается записать в область, предназначенную только для чтения, или перезаписать часть операционной системы). Термин "сегментация" имеет различные значения в информатике; в контексте "ошибки сегментации" он относится к адресном пространству программы. При использовании защиты памяти доступно только собственное адресное пространство программы, и в нём только стек и область данных, доступная для чтения и записи, могут быть изменены. Данные, выделенные в сегменте `const` и сегменте кода, не могут быть изменены. Таким образом, попытка чтения за пределами адресного пространства программы или запись в сегмент адресного пространства, доступный только для чтения, приводит к ошибке сегментации, отсюда и название. В системах, использующих аппаратную сегментацию памяти для реализации виртуальной памяти, ошибка сегментации возникает, когда аппаратное обеспечение обнаруживает попытку обратиться к несуществующему сегменту, к области за пределами границ сегмента или обратиться к области способом, запрещённым разрешениями, установленными для этого сегмента. В системах, использующих только страничную организацию памяти, недействительная ошибка страницы обычно приводит к ошибке сегментации, и ошибки сегментации и ошибки страницы – это оба типа ошибок, генерируемых системой управления виртуальной памятью. Ошибки сегментации могут возникать и независимо от ошибок страниц: несанкционированный доступ к существующей странице является ошибкой сегментации, но не ошибкой недействительной страницы, а ошибки сегментации могут возникать в середине страницы (следовательно, без ошибки страницы), например, при переполнении буфера, которое остаётся в пределах страницы, но незаконно перезаписывает память. На аппаратном уровне ошибка первоначально генерируется блоком управления памятью (MMU) при несанкционированном доступе (если запрошенная область памяти существует) в рамках его функции защиты памяти, или при недействительной ошибке страницы (если запрошенная область памяти не существует). Если проблема заключается не в недействительном логическом адресе, а в недействительном физическом адресе, возникает ошибка шины, хотя эти ошибки не всегда различаются. На уровне операционной системы эта ошибка перехватывается, и сигнал отправляется нарушившему процесс, активируя обработчик этого сигнала в процессе. Различные операционные системы используют разные имена сигналов для обозначения ошибки сегментации. В Unix-подобных операционных системах нарушившему процессу отправляется сигнал SIGSEGV (сокращение от segmentation violation). В Microsoft Windows нарушающий процесс получает исключение STATUS ACCESS VIOLATION.
Обработка
Действие по умолчанию при ошибке сегментации или ошибке шины – это ненормальное завершение процесса, который её вызвал. Для облегчения отладки может быть создан дамп памяти, а также могут выполняться другие действия, зависящие от платформы. Например, системы Linux с патчем grsecurity могут регистрировать сигналы SIGSEGV для мониторинга возможных попыток вторжения, использующих переполнение буфера. На некоторых системах, таких как Linux и Windows, программа может самостоятельно обрабатывать ошибку сегментации. В зависимости от архитектуры и операционной системы, работающая программа может не только обработать событие, но и извлечь информацию о своём состоянии, например, получить трассировку стека, значения регистров процессора, строку исходного кода, вызвавшую ошибку, адрес памяти, к которой был осуществлён недопустимый доступ, и тип операции – чтение или запись. Хотя ошибка сегментации обычно указывает на наличие ошибки в программе, которую необходимо исправить, её также можно намеренно вызывать для тестирования, отладки и эмуляции платформ, требующих прямого доступа к памяти. В последнем случае система должна позволять программе продолжать работу даже после возникновения ошибки. Если система это позволяет, можно обработать событие и увеличить счётчик команд процессора, чтобы "перескочить" через проблемную инструкцию и продолжить выполнение.