[C++] "Łapanie" przepełnienia stosu

0

Cześć,

Mam w swoim programie funkcje rekurencyjną które może wywoływać samą siebie od kilku razy po tysiące. Zależy to od podanych argumentów. Mógłbym ją napisać tak, aby nie była to funkcja rekurencyjna ale jest to program dla kolegi i on musi mieć funkcje w takiej formie. Czasami sie zdąża, że program wyrzuca błąd Stack overflow, żeby zabezpieczyć się przed tym objąłem kod w bloku __try (__try jest rozszerzeniem Visual C++). Niestety program będzie testowany na kompilatorze MinGW i użycie tych tagów odpada. Czy jest jakiś prosty (prosty, bo niechce do 30 linijkowego programu wrzucać potężnego systemu) sposób na wyłapanie błędu Stack Overflow bez użycia bloków __try. Szukałem w Googole pod mn. takim hasłem http://www.google.pl/search?hl=pl&client=firefox-a&rls=org.mozilla%3Apl%3Aofficial&q=catch+stack+overflow+c%2B%2B+OR+cpp&btnG=Szukaj&lr= ale nic interesującego nie znalazłem. Jeśli był podobny temat to przepraszam, nie znalazłem go.

Z góry dziękuje za odpowiedzi.

0

a zwykłe try nie starczy?

0

proszę o wywalenie poprzedniego

int g=0;
#define XXX 1234
// XXX to liczba magiczna i specyficzna
...
f(int k){
     ...
     g++ 
     if (g<XXX) f(y); else ....
     g--
     ...
}
0
MDobak napisał(a)

Czasami sie zdąża, że program wyrzuca błąd Stack overflow

to znaczy ze
*) albo Twoj kumpel zawalil sprawe
*) albo podczas buildu ustawiony jest za maly rodzaj stosu

w pierwszym przypadku - znajdz i napraw blad
w drugim - przejrzyj opcje mingwa i zwieksz obszar stosu na wiekszy

ah i jeszcze jedno.. owo __try lapiace wyjatek StackOverflow to w ogole jest rozszerzenie runtime'u dostepne na windozie, nazywa sie SEH czyli StructuredExceptionHandling. W tradycyjnym (czyt: normalnym) srodowisku, napotkanie StackOverflow konczy sie tak samo jak odwolanie sie do nullpointera: program mowi dowidzenia. natychmiast i nieodwlolalnie.. jesli piszesz docelowo na linuxa i dlatego mingwa uzywasz, zapomnij o SEH

0

Dzięki za odpowiedz, ale...

quetzalcoatl napisał(a)

to znaczy ze
*) albo Twoj kumpel zawalil sprawe
*) albo podczas buildu ustawiony jest za maly rodzaj stosu

Po części masz racje, funkcja jest źle napisana, ale to dlatego bo jak już pisałem kolega kazał ją tak napisać, funkcja musi być rekurencyjna (wymóg kolegi), gdybym użył pętli nie miałbym problemu z Stack Overflow, do funkcji mogą być podane dowolne parametry, funkcja wywołuje samą siebie aż wykona odpowiednie obliczenia (raczej nie możliwe jest przewidzenie ile będzie musiała sie wykonać dla danych parametrów) więc zwiększenie rozmiaru stosu nic nie da. Pod VC++ gdzie mam __try w bloku __except umieściłem kod, który zwraca aktualny stan wyniku (jest to możliwe bo funkcja z każdym wywołaniem zwiększa tylko dokładność wyniku).

quetzalcoatl napisał(a)

ah i jeszcze jedno.. owo __try lapiace wyjatek StackOverflow to w ogole jest rozszerzenie runtime'u dostepne na windozie, nazywa sie SEH czyli StructuredExceptionHandling. W tradycyjnym (czyt: normalnym) srodowisku, napotkanie StackOverflow konczy sie tak samo jak odwolanie sie do nullpointera: program mowi dowidzenia. natychmiast i nieodwlolalnie.. jesli piszesz docelowo na linuxa i dlatego mingwa uzywasz, zapomnij o SEH

Tak wiem, ale MinGW jest kompilatorem Windowsowym na podstawie kompilatora GCC. Więc GCC i MinGW to nie jest to samo. A skoro pisze na MinGW to pisze na Windowsie :-). Z tego co wiem, MinGW ma też i swoje rozszerzenia i zastanawiam się czy z ich pomocą (a może i bez nich) możliwe jest wyłapanie tego błędu. Z tego co słyszałem to silnik Unreal w przypadku błędu Stack Overflow nie wyłącza się (całkowicie), a tworzy okienko z informacja o błędzie. Silnik Unreal jest dostępny na linuxa więc im chyba udało się wyłapać te błędy. No chyba że użyli jakiegoś innego rozwiązania. Ogólnie rozwiązanie problemu nie jest mi bardzo potrzebne, bo kolega mówi ze to nic ze czasem wyskakuje Stack Overflow, ale ja sam jestem ciekawe jest sie przed tym zabezpieczyć.

0

MinGW dla Windows zawiera obsługę SEH .
plik excpt.h a w środku handler prototyp :

excpt.h
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_HANDLER)
		(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);

EXCEPTION_DISPOSITION ExceptionFun(_EXCEPTION_RECORD*, void*, _CONTEXT*, void*)
{
...
return enumy EXCEPTION_DISPOSITION
}

instalacja handlera :

__try1(ExceptionFun) ;

czy,...,możliwe jest wyłapanie tego błędu ,...,

tak , tylko co dalej ... może trzeba go usunąć ? ;-)
Dodatkowo po zdefiniowaniu na początku programu :

#define __SEH_NOOP 
#include <windows.h>

pozwala na obsługę tak jak w VC++ czyli :

__try{
         }
     __except( EX..........)
        { }

itp .
Tyle że Handler __try1(ExceptionFun) ; w moim super programie testowym napisanym z bardzo wielkim
wysiłkiem zawierającym 3 linijki pewnej funkcji w postaci czystego bezbłędnego kodu rozmieszczonego bardzo proporcjonalnie w edytorze wyświetlanym na ekranie łapie Overflow
a __try - except jakoś nie bardzo [green] , nie zamierzam nad tym specjalnie rozmyślać...

0

@dzejo
Wielkie dzięki za odpowiedź! O to mi chodziło, ale mógłbyś wrzucić ten swój wrzucić ten swój super testowy program, bo mi program nadal po prostu sie wyłącza. Coś muszę źle robić.

0

ten swój super testowy program

żartowałem , rozwiązanie nie jest moje ani bardzo super ... tylko takie typowe.

Wielkie dzięki
Obawiam się ze nie ma za co :-D .
Jak napisałem , wszystko jest pięknie ale w MinGw __try i __except nie działa prawidłowo

Widocznie pomimo obecności pewnych wpisów w plikach nagłówkowych MinGW,
kompilator nie wspiera obsługi wyjątków w stylu __try __except w Windows .

[ program sie kompiluje ale źle działa i nie łapie wyjątku ]

w MVC++ 2005 Express natomiast ten kod działa:

#include <windows.h>
#include <iostream>
using namespace std ;

// rekurencyjna funkcja przepełniająca stos .
// Na podstawie "Programowanie Aplikacji dla Microsoft Windows"  
unsigned int Suma(unsigned int ile)
{
	 return ((ile==0)? 0 : (ile+Suma(ile-1)));
}

//--------------------------------------------------
long __stdcall FiltrWyjatku(DWORD ExcptCode)
{
	
	       if(ExcptCode == STATUS_STACK_OVERFLOW)
		   { return EXCEPTION_EXECUTE_HANDLER;}    // wykonaj naszą obsługę
		   else{ 
			     return EXCEPTION_CONTINUE_SEARCH; // szukaj innego handlera
		         }
}
//--------------------------------------------------
// fnkcja z łapaniem Overflow
// Jeśli zostanie przechwycony wyjątek funkcja zwraca 0
// jeśli nie ,sumę liczb od wartości zadanej do 0
unsigned int __stdcall SumaKontrolowana(unsigned int ile)
{
	unsigned int suma = ile;
	unsigned int suma_ret = 0 ;

       __try{

                   suma_ret = Suma(suma);
		   
               }
	   __except(FiltrWyjatku(GetExceptionCode()))
	   {
		   cout << "Zlapano Overflow" << endl ;
		   cin.get();
	   }
	
	     return  suma_ret ; 
}
//--------------------------------------------------------
int main(int argc,char**param)
{

int return_code ;
 if( 0 == (return_code = SumaKontrolowana(6000000)))
 {
	 cout << "Funkcja Przepelnila STOS ." << endl;
 }else{
	       cout << "Funkcja nie przepelnila STOSU. " << endl ;
               cout << "Wartosc powrotu = " << return_code << endl;
        }

cout << "Po wykonaniu SumaKontrolowana();" << endl ; 
cout << "Dalszy Kod - tu jestesmy bezpieczni, do czasu :-). " << endl ;
	cin.get();
	return 0 ;
}

Przy zastosowaniu instalacji Handlera ( ten co działa ) w MinGW -> __try1(ExceptionFun) ;
nie bardzo widzę możliwość dalszego wykonania programu po mimo przechwycenia
wyjątku , ale może ktoś rzuci jakieś rozwiązanie , chwilowo nie mam czasu , ... ,
Acha można sprawdzić jeszcze inne rozwiązania z Handlerami SEH Windows oprócz zwykłego
__try except .....

ps. Przy zastosowaniu -_try funkcja może pozostawic jakąś wartość w zmiennej globalnej przed
rzuceniem wyjątku .
Jeśli stosujemy Handler można spróbować tak samo , jednak dalsze wykonanie kodu
będzie wymagać 'naprawienia wadliwego ' w czasie wykonania po wybraniu EXCEPTION_CONTINUE_EXECUTION
lub nadpisania kodu poprzez Handler i przekierowanie do innej funkcji lub jej całkowitego ominięcia .
Czyli trzeba rozwinąć kod :

#include <excpt.h>
#include <iostream.h>


EXCEPTION_DISPOSITION  ExceptionFun (EXCEPTION_RECORD *ExceptionRecord,
       void * EstablisherFrame,CONTEXT *ContextRecord,void * dispatcherContext)
{
	cout << "Wyjatek Overflow" << endl ;
	return ExceptionContinueExecution;
}

//-------------------------------------------------------------------
unsigned int Suma(unsigned int ile)
{
	 return ((ile==0)? 0 : (ile+Suma(ile-1)));
}

//--------------------------
int main(int count,char**param)
{

	__try1(ExceptionFun);

	Suma(600000);
                    

                          // to sie jednak nie wykona 
	cout << "Po wyjatku..." << endl ; // brak rozwiązania
	                                                 // brak kolejnego Handlera 

	cin.get();
	return 0 ;
}

i dopisać treść Handlera ...
EXCEPTION_CONTINUE_EXECUTION wraca wykonanie programu do instrukcji która spowodowała
wyjątek , nie sądzę jednak aby to było pierwsze wywołanie fun. Suma , czyli znajdziemy
sie w samym środku bałaganu , jak to odkręcić bez wywalenia programu to nie mam pojęcia ...

Albo dołączyć coś takiego [masakra] :
http://www.programmingunlimited.net/siteexec/content.cgi?page=mingw-seh
nie sprawdzałem działania ...

1 użytkowników online, w tym zalogowanych: 0, gości: 1