#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()
сохранить asigjmpbuf
для последующего использования. Все остальное в лучшем случае зависит от конкретной платформы и, вероятно, не очень эффективно.
Ответ №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 — рассматривать его как терминал.
Разработайте свой код так, чтобы он не переполнял стек, а не пытался сделать его устойчивым к переполнению стека.