Проверка сбоя выделения стека?

#c #stack #c99 #allocation

#c #стек #c99 #распределение

Вопрос:

Есть ли способ исправить неудачное статическое выделение или программа просто завершается сбоем из-за сегментации или ошибки шины при запуске?

Пост был вдохновлен тем, как C99 допускает такие сумасшедшие вещи, как char text[n];

РЕДАКТИРОВАТЬ: Спасибо. Теперь я понимаю, что часть, выделенная жирным шрифтом, не является статическим выделением. Итак, просто чтобы проверить, если что-то вроде char text[1234]; завершится неудачей, будут ли возможные стратегии восстановления такими же?

Комментарии:

1. это не статическое распределение. Это в стеке. Если вы думаете, что это может привести к сбою, тогда используйте кучу.

2. Это не статическое распределение.

3. Заключайте код в backticks , а не двойные звездочки .

Ответ №1:

char text[n] выделяет массив переменного размера в стеке. Это просто включает в себя увеличение указателя стека на n .

Процесс пользовательского пространства мало что может сделать в случае переполнения стека — операционная система должна либо отправить сигнал процессу и завершить его, либо изменить размер стека.

Комментарии:

1. libsigsegv имеет обработчик переполнения стека для многих платформ.

2. @Chris: можно порекомендовать больше кода в стиле 1980-х, «переносимого благодаря наличию системного взлома для каждой известной системы» … 😉

3. @R .. — Я не говорил, что это хорошо , просто что это может быть актуально. Я бы не стал использовать VLA в первую очередь именно по этой причине.

Ответ №2:

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

Комментарии:

1. @ImJustALittleCatfish Опасность, Уилл Робинсон! Пожалуйста, не доверяйте сигналам как хорошей идее. Сигналы — это всегда плохая идея (можно написать целые книги о том, как сигналы и небезопасность асинхронных сигналов усложняют программирование).

2. Хм, есть разница между «сложным» и «плохим». Но я могу представить, почему использование сигналов ТАКИМ образом было бы громоздким.

3. Многие вещи «усложняют» программирование, но я бы сказал, что все серверные процессы Un * x должны перехватывать по крайней мере пару сигналов.

4. Потому что пользователи наших серверов будут настаивать на вводе kill XXXX в своих xterms? И потому, что это промышленный стандарт.

5. Что вы можете сделать в обработчике сигналов, если вы перехватываете SIGSEGV, сгенерированный системой из-за выделения памяти? Вы можете выйти — это безопасно. Вы не можете вернуться из обработчика сигнала обычным способом; вы не устранили причину сигнала. Итак, у вас остается возможность, siglongjmp() если вы ранее выполняли a, sigsetjmp() сохранить a sigjmpbuf для последующего использования. Все остальное в лучшем случае зависит от конкретной платформы и, вероятно, не очень эффективно.

Ответ №3:

Никогда не проверяйте состояние ошибки, с которым вы не знаете, как справиться.

Серьезно, что ты планируешь делать? Существует только небольшое подмножество функций, которые вам разрешено вызывать из обработчика сигналов (см. man 7 signal ), и printf и longjmp (longjmp — единственный способ, который я могу придумать для решения такой проблемы) не входят в их число. Если у вас возникнут проблемы с повторным выполнением процесса, вы могли бы также нанять няню, чтобы выполнить эту работу и избежать беспорядка.

Обратите внимание, что согласно man alloca вам на самом деле не сообщают, что «выделение» завершается с ошибкой, вы просто получаете SIGSEGV при попытке получить доступ к поврежденной памяти, и, конечно, этого может вообще не произойти в массиве text[] или, возможно, даже не в функции, которая выделяет text[] вообще.

Хотя два приведенных выше абзаца основаны на Linux, общая теория верна для всех платформ.

Используйте malloc и выполняйте чистую обработку. Будьте в здравом уме.

[ПРАВИТЬ]

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

Комментарии:

1. longjmp получение из обработчика сигналов допустимо до тех пор, пока вы можете гарантировать, что при вызове обработчика сигналов не выполнялась функция async-signal-unsafe.

2. @R.: Точно. Однако вы редко можете знать это. Любой SIGSEGV в его программе по любой причине вызвал бы проблему. Но давайте предположим, что программирование идеально и что ни одна функция ДО выделения большого объема не вызовет проблемы. Вы должны были бы убедиться, что ничто в функции, которая выполняет большое выделение, и в любой функции, которую она вызывает , не может вызвать небезопасную функцию. Хотя на самом деле текст perfect programmer дал мне идею, что это должно рассматриваться как предварительное преступление. Обновленный ответ.

Ответ №4:

Это распределение стека, а не статическое. Режим сбоя — это переполнение стека. Наиболее рациональная политика для stack overflow — рассматривать его как терминал.

Разработайте свой код так, чтобы он не переполнял стек, а не пытался сделать его устойчивым к переполнению стека.