Стандарт C определяет поведение переполнения стека? - PullRequest
4 голосов
/ 15 марта 2009

Есть ли определенное поведение для обработки переполнения стека?

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

Ответы [ 10 ]

14 голосов
/ 15 марта 2009

Стандарт не требует использования стека и ничего не говорит о переполнении стека.

8 голосов
/ 15 марта 2009

Стандарт C99 не определяет стек; в нем рассматривается только автоматическое или выделенное хранилище в абстрактном виде, тогда как непрерывный стек с обнаружением переполнения является лишь одним механизмом для реализации автоматического хранения.

Раздел 7.14 стандарта определяет SIGSEGV как сигнал, который поступает на «неверный доступ к хранилищу» . Реализации C не обязаны генерировать какие-либо сигналы, но реализации, использующие непрерывный стек фиксированного размера *, обычно сигнализируют SIGSEGV, если обнаружено переполнение стека.

Вы можете зарегистрировать функцию-обработчик сигнала для SIGSEGV, но она не может вернуть - "[i] f и когда функция возвращает, если значение sig равно SIGFPE, SIGILL, SIGSEGV или любой другой реализации -определенное значение, соответствующее вычислительному исключению, поведение [u] r не определено ".

(* не то чтобы я сознательно работал с реализациями C, которые этого не делают, но я ничего не знаю в стандарте C, запрещающем использование общих методов, используемых для реализации растущих автоматических доменов хранения в других средах)

4 голосов
/ 15 марта 2009

Ответы здесь верны, заявив, что это не имеет ничего общего со стандартом c, но ваше утверждение о том, что «помимо завершения процесса, кажется, что многое можно сделать», не является общность - верно.

Фактически, в большинстве систем с управлением виртуальной памятью и подкачкой по требованию выделенный стек довольно мал (обычно на 4 КБ больше, чем используется в настоящее время) и часто переполняется (что генерирует прерывание из-за ошибки страницы), а ОС просто добавляет еще одна страница памяти в стеке для потока.

Предел стека - обычно - 1 МБ - просто произвольная цифра, выбранная для защиты от сбежавших программ, и, как правило, не является абсолютным пределом (хотя он был на некоторых моделях памяти с процессорами Intel IIRC). Как правило, не имеет смысла выделять 1 МБ физической памяти каждому потоку.

4 голосов
/ 15 марта 2009

Стандарт C даже не определяет стек, поэтому он определенно не определяет, что происходит при переполнении стека.

2 голосов
/ 15 марта 2009

Согласно некоторым ответам на этот вопрос , стандартам C даже нечего сказать о существовании стека, не говоря уже о переполнении стека.

1 голос
/ 15 марта 2009

Как уже упоминали другие, стандарт ничего не говорит о стеке.

Но, я думаю, это было бы для определения поведения переполнения стека, стандарт сказал бы, что это приводит к неопределенному поведению.

:: Rimshot ::

1 голос
/ 15 марта 2009

Это зависит от операционной системы. Однако многие операционные системы допускают перезапись размера стека по умолчанию. Например, в Windows вы можете использовать этот флаг компоновщика , чтобы увеличить размер стека с 1 МБ до более высокого значения.

1 голос
/ 15 марта 2009

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

0 голосов
/ 26 февраля 2015

Стандарт C противоречив в этом отношении. Рассмотрим следующую программу:

void foo(uintptr_t n)
{
    int a;
    printf("%p\n", (void *)&a);
    if (n+1) foo(n+1);
}
int main()
{
    int a;
    printf("%p\n", (void *)&a);
    foo(0);
}

Эта программа идеально соответствует и не нарушает ни одного из минимальных пределов перевода, и, как говорили другие, в стандарте нет ничего о пределях стека / переполнении. Однако он создает UINTPTR_MAX + 2 объекта a (на каждом уровне вызова), чьи времена жизни перекрываются, каждый с разными адресами. Это невозможно путем простого подсчета аргументов.

0 голосов
/ 25 февраля 2015

В некоторых системах обеспечение любого предсказуемого преимущества после переполнения стека добавляло бы значительную нагрузку на каждый вызов функции; таким образом, стандарт вполне разумно рассматривает переполнение стека как неопределенное поведение. Это вполне уместно, если целью является максимизация эффективности, с которой реализация может запускать легитимные программы.

Стандарт также не требует, чтобы в системах было достаточно стека для поддержки любых нетривиальных вызовов глубины функций. Учитывая, что некоторые полезные программы (особенно в мире встраиваемых систем) могут обойтись менее чем с 16 байтами стека и могут не обязательно быть в состоянии сэкономить больше оперативной памяти, чем это, требование наличия большого стека нарушит философию не платите за то, что вам не нужно ".

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

...