LINUX.ORG.RU

[C] Рекурсия и переполнение стека

 


0

0

Доброго утречка всем! Как в C контролировать переполнение стека при вызовах функций, в частности при рекурсивных вызовах? Мы ведь не знаем заранее размер стека, а часто и глубину рекурсии. То есть выходит, что все программы с рекурсией - бажные, да и вообще все программы бажные, ведь стек всегда может оказаться слишком маленьким?


Именно поэтому программы, использующие динамическое выделение памяти, тоже «бажные», ведь памяти всегда может не хватить.

mannaz
()

классическая проблема надежды на наличие ресурсов

namezys ★★★★
()

Обычно в конце стека помещают страницу памяти, недоступную для чтения/записи. В итоге конец стека -> general protection fault -> завершение программы. По крайней мере, на x86 именно так выглядят стеки thread'ов.

linuxfan
()
Ответ на: комментарий от mannaz

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

Legioner ★★★★★
()

Узнать размер стэка - getrlimit.

У меня, по умолчанию, размер стэка - 10 Мб (RHEL 5). Сколько данных ты кладешь на стэк, что приходится задумываться о его размере?

eXire ★★
()
Ответ на: комментарий от Booster

По-хорошему рекурсию нужно ограничивать.

если у рекурсии нет базиса, то это не рекурсия (а двойственная к ней корекурсия),- и смысла такая конструкция в неленивых языках не имеет

jtootf ★★★★★
()
Ответ на: комментарий от eXire

> У меня, по умолчанию, размер стэка - 10 Мб (RHEL 5). Сколько данных ты кладешь на стэк, что приходится задумываться о его размере?

Я могу не знать, сколько будет положено на стек. Если глубина рекурсии N, и это N зависит от пользовательского ввода, то злоумышленник может зафолтить программу, так ведь?

govno
() автор топика
Ответ на: комментарий от govno

Вести от Капитана: нужно ставить жесткие лимиты на вещи которые могут вызвать перерасход памяти или экспоненциальный взрыв.

dilmah ★★★★★
()
Ответ на: комментарий от govno

> То есть не использовать рекурсию на уровне языка, а организовывать свой стек?

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

Вообще нужно все ограничивать, длину слов, глубину вложенности и т.п. Скажем, недавно пробегала ссылка на бесконечный zip-архив.

dilmah ★★★★★
()
Ответ на: комментарий от govno

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

Booster ★★
()
Ответ на: комментарий от jtootf

>если у рекурсии нет базиса, то это не рекурсия (а двойственная к ней корекурсия),- и смысла такая конструкция в неленивых языках не имеет
Вы всё про функциональщину?

Booster ★★
()
Ответ на: комментарий от Legioner

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

Но стек может переполниться и без вызова malloc

madcore ★★★★★
()
Ответ на: комментарий от govno

>злоумышленник может зафолтить программу

А что, разве в этом есть что-то страшное? setjmp перед началом рекурсии и longjmp из обработчика разве не могут быть вариантом решения проблемы?

Example (писалось на коленке, проверялось только на работоспособность):

#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ALTSTK_SIZE 16384
static jmp_buf r_exit;

static void sig11_handler(int sig)
{
	longjmp(r_exit, 1);
}

int recurse(int i)
{
	char dummy[6553600];
	(void)dummy;
	return i ? i * recurse(i - 1) : 1;
}

int main()
{
	stack_t ss;
	struct sigaction sa;
	ss.ss_sp = malloc(ALTSTK_SIZE);
	ss.ss_size = ALTSTK_SIZE;
	ss.ss_flags = 0;
	if (sigaltstack(&ss, NULL) == -1) {
		perror("sigaltstk");
		exit(EXIT_FAILURE);
	}
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = sig11_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_ONSTACK;
	sigaction(11, &sa, NULL);
	if (setjmp(r_exit) != 0) {
		printf("Recursion failed!\n");
	} else {
		int result = recurse(10);
		printf("Recursion result: %d\n", result);
	}
	return 0;
}
linuxfan
()
Ответ на: комментарий от Booster

Вы всё про функциональщину?

я про вообще

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

ну мне например непонятна полностью терминология. которая в общем то не является общеизвестной терминологией. (хотя может в каком-то наборе работ она такая и есть)

Например я знаю, что такое присоединённое(двойственное) пространство (tangent space) в геометрии многообразий и физике.

я примерно помню, что понимается под коприсоединённым пространством.

однако я не могу отразить это на рекурсию и работу с ней. То же самое я уверен будет верно в отношении многих читающих.

Так же ИМХО использование усложнённой терминологии без принятия договорённости о ней (например ссылками на работы или дачей определений), а так же без необходимости показывает, то что человек не до конца разбирается в теме.

Что непонятно: базис рекурсии (тут сам виноват видел определения), твоё обозначение двойственной рекусии, твоё понимание корекурсии.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

Что непонятно: базис рекурсии (тут сам виноват видел определения), твоё обозначение двойственной рекусии, твоё понимание корекурсии.

обозначение (определение) двойственности и понимание корекурсии - общепринятые:

http://en.wikipedia.org/wiki/Corecursion

In computer science, corecursion is a type of operation that is dual to recursion

двойственность понимается категориально

базис рекурсии определяет точку выхода из неё. термин также общепринятый:

http://en.wikipedia.org/wiki/Recursive_definition

Most recursive definition have three foundations: a base case (basis), an inductive clause, and an extremal clause.

...recursive definition must always have base cases

корекурсивное определение не имеет точки выхода, потому и работа с ним имеет смысл только в ленивых языках, поддерживающих бесконечные структуры данных. ещё претензии?

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> обозначение (определение) двойственности и понимание корекурсии - общепринятые:

какое из определений двойственности общепринятое: ^_^

http://en.wikipedia.org/wiki/Duality_(mathematics)

ещё претензии?

По скольку ЛОР не является научным тематическим журналом, то до начала реального спора где есть необходимость ссылаться на источники, или использовать терминологию не допускающую двусмысленности, к тому же если ты уверен, что понимаешь правильно и те кто с тобой общаются поймут это так же как и ты, то ИМХО лучше избегать подобной терминологии :)

переводя на норм язык, а своими словами можешь описать? :)

qnikst ★★★★★
()
Ответ на: комментарий от qnikst

какое из определений двойственности общепринятое: ^_^

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

использовать терминологию не допускающую двусмысленности

контекст исключает двусмысленность. если ты можешь предложить альтернативную трактовку двойственности в контексте корекурсии, буду рад почитать

переводя на норм язык, а своими словами можешь описать? :)

ещё раз - что именно тебе непонятно? корекурсивное определение множества натуральных чисел? какой-то термин? как это использовать?

jtootf ★★★★★
()
Ответ на: комментарий от qnikst

те кто с тобой общаются поймут это так же как и ты

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

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

> даже википедийное определение корекурсии достаточно пространно расписывает этот момент

кстати оно почти никакое, и нет ссылки на работы где это описано, что грустно видеть.

контекст исключает двусмысленность.

может быть.

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

что такое монада я знаю, но разбираюсь не так хорошо как хотелосьбы

а приставку ко- в computer science я пока не осознаю :)

qnikst ★★★★★
()
Ответ на: комментарий от jtootf

> корекурсивное определение не имеет точки выхода, потому и работа с ним имеет смысл только в ленивых языках

а в Scheme есть delay, а в CL этот delay легко реализовать. в них имеет смысл? =)

korvin_ ★★★★★
()
Ответ на: комментарий от korvin_

а в Scheme есть delay, а в CL этот delay легко реализовать. в них имеет смысл? =)

ленивый eDSL в строгом языке - почему бы и нет?

jtootf ★★★★★
()

govno (26.04.2010 14:26:36)

отличный никнейм.

anonymous
()
Ответ на: комментарий от jtootf

боюсь мне пока не попути с теорией категорий, ибо и без того есть дофига чего учить :) да и «догоро(с)»

qnikst ★★★★★
()
Ответ на: комментарий от Led

То-есть gcc оптимизирует хвостовую рекурсию? Для языка C? А пруф будет?
Пока обязательную оптимизацию хвостовой рекурсии я видел только в OCaml и Scheme.

octave
()
Ответ на: комментарий от octave

> То-есть gcc оптимизирует хвостовую рекурсию? Для языка C?

Да

А пруф будет?

Вы спросили - вам ответили (коротко, конкретно и по существу). Информация - из стандартной документации. Вам нужны «пруфы» - ищите. Я «доказывать» что-либо неграмонтным студентам не собираюсь.

Led ★★★☆☆
()

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

x0r ★★★★★
()
Ответ на: комментарий от x0r

> забыть о рекурсивных вызовах нафиг, пытаться преобразовать рекурсию к хвостовой и, далее, к итерационному алгоритму

Главное - школу не прогуливать.

Led ★★★☆☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.