Почему системные вызовы возвращают EFAULT, а не отправляют segfault? - PullRequest
9 голосов
/ 07 марта 2012

Для ясности, это вопрос дизайна, а не вопроса реализации

Я хочу знать, почему POSIX ведет себя так.Системные вызовы POSIX, когда задано неверное расположение в памяти, возвращают EFAULT вместо сбоя программы пользовательского пространства (отправляя sigsegv), что делает их поведение несовместимым с функциями пользовательского пространства.

Почему?Разве это не скрывает ошибки памяти?Это историческая ошибка или для этого есть веская причина?

Ответы [ 2 ]

4 голосов
/ 08 марта 2012

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

Конечно, само ядро, не допускается сегментирование ошибки, поэтому он должен вручную проверять все адресные области, которые выдает пользовательский процесс.В случае сбоя одной из этих проверок системный вызов завершается с EFAULT.Таким образом, в этой ситуации ошибки сегментации на самом деле не произошло - ее удалось избежать, если ядро ​​явно проверило, чтобы убедиться, что все адреса действительны.Следовательно, имеет смысл, что сигнал не отправляется.

Кроме того, если бы сигнал был отправлен, ядро ​​не могло бы присоединить значимый программный счетчик к сигналу,пользовательский процесс на самом деле не выполняется, когда выполняется системный вызов.Это означает, что пользовательский процесс не сможет произвести достойную диагностику, перезапустить сбойную инструкцию и т. Д.

Подводя итог: в основном исторический, но фактическая логика в рассуждениях существует.Как и EINTR, это не делает его менее раздражающим.

1 голос
/ 08 марта 2012

Ну, что бы вы хотели, чтобы произошло . Системный вызов - это запрос к системе. Если вы спросите: «Когда отправляется паром в Мюнхен?» Вы хотите, чтобы программа завершилась сбоем, или получить возврат = -1 с помощью errno = ENOHARBOR? Если вы попросите систему положить вашу машину в сумочку, хотите ли вы, чтобы ваша сумочка была уничтожена, или возвращение -1 с ошибкой, установленной на EBAGTOOSMALL?

Существует техническая деталь: до или после системных вызовов аргументы для / от пользователя / системы -land должны быть преобразованы (скопированы) при входе / выходе из системного вызова. Главным образом из соображений безопасности система очень неохотно пишет в пространство пользователя. (В Linux для этого есть функция copy_to_user_space (и наоборот), которая проверяет учетные данные до фактического копирования)


Почему? Разве это не скрывает ошибки памяти? `

Наоборот. Это позволяет вашей программе обработать ошибку (в данном случае это невозможно) и корректно завершиться. Но программа должна проверить возвращаемое значение из системных вызовов и проверить errno. В случае с SIGSEGVE ваша программа мало что может сделать, поэтому преобразование EINVAL в SIGSEGVE было бы плохой идеей.

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

И технический аспект может заключаться в том, что {ошибки сегментации, ошибка памяти, исключение с плавающей запятой, ...} (часто) генерируются аппаратными прерываниями.

...