close

Przepełnienie stosu

Skocz do nawigacji Skocz do wyszukiwania

W informatyce przepełnienie stosu występuje, gdy na stosie potrzeba zbyt dużej ilości pamięci .

W wielu językach programowania stos wywołań zawiera ograniczoną ilość pamięci, zwykle ustalaną podczas uruchamiania programu. Wielkość stosu zależy od wielu czynników, w tym języka programowania, architektury maszyny, zastosowania wielowątkowości oraz dostępności pamięci w systemie. Gdy w stosie jest używane zbyt dużo pamięci , mówi się, że występuje przepełnienie i następuje awaria programu [1] . Ta klasa błędów jest zwykle spowodowana jednym z dwóch typów błędów programistycznych [2] : nieskończoną rekurencją i użyciem bardzo dużych zmiennych stosu.

Nieskończona rekurencja

Najczęstszą przyczyną przepełnienia stosu jest rekursja z nadmierną lub nieskończoną głębokością.

Języki, które implementują technikę rekurencji ogonowej , takie jak język Scheme , umożliwiają konkretną nieskończoną rekurencję, która może być wykonywana bez przepełnienia stosu. Dzieje się tak, ponieważ wywołania korzystające z rekurencji końcowej nie wymagają dodatkowego miejsca na stosie [3] .

Bardzo duże zmienne stosu

Inną główną przyczyną przepełnienia stosu jest próba przydzielenia większej ilości pamięci niż jest dostępne na stosie. Dzieje się tak, gdy tworzysz bardzo dużą tablicę zmiennych lokalnych . Z tego powodu tablice większe niż kilka kilobajtów powinny być przydzielane dynamicznie , a nie przydzielane jako zmienne lokalne [4] .

Przyczyny, które mogą zmniejszyć dostępny rozmiar stosu, a tym samym zwiększyć prawdopodobieństwo przepełnienia stosu

Przepełnienia stosu są potęgowane przez wszystko, co zmniejsza efektywny rozmiar stosu programu .

Na przykład program działający jako pojedynczy wątek może działać poprawnie, ale jeśli ten sam program działa z wieloma wątkami , następuje awaria programu , ponieważ wiele programów korzystających z wątków ma mniejszy stos dostępny dla każdego pojedynczego wątku niż program. nie używa wątków.

Podobnie osobom badającym rozwój jądra odradza się stosowanie algorytmów rekurencyjnych i bardzo dużych buforów w stosie [5] [6] .

Przykłady w języku C / C++

Nieskończona rekurencja z jedną funkcją

 nieważne f () {  
   f ();
 }
 int główna ( nieważne ) {  
   f ();
   zwróć 0 ; 
 }

Ten fragment kodu wywołuje funkcję f() , a funkcja f()z kolei wywołuje samą siebie, generując w ten sposób nieskończoną rekurencję.

Nieskończona rekurencja z dwiema funkcjami

 nieważne f ( nieważne ); nieważne g ( nieważne );  
  
 
 int główna ( nieważne ) {  
   f ();
  
   zwróć 0 ; 
 }
 
 nieważne f ( nieważne ) {  
   g ();
 }
 
 nieważne g ( nieważne ) {  
   f (); }  
 

Funkcja f()i funkcja g()wywołują się nawzajem w sposób ciągły, aż do wystąpienia przepełnienia stosu.

Zbyt duża zmienna w stosie

 int główna ( nieważne ) {  
   podwójne n [ 10000000 ]; zwróć 0 ;  
    
 }

Tablica zadeklarowana w tym fragmencie kodu wymaga więcej pamięci niż jest dostępne na stosie, co powoduje przepełnienie stosu.

Notatki

  1. ^ James Craig Burley, Używanie i przenoszenie GNU Fortran , na sunsite.ualberta.ca , 1 czerwca 1991 (archiwum z 5 października 2012) .
  2. ^ Kalev Danny, Understanding Stack Overflow , devx.com , 5 września 2000 r.
  3. ^ Wprowadzenie do schematu i jego realizacji , na federated.com , 19 lutego 1997 (archiwum z oryginału w dniu 10 sierpnia 2007) .
  4. ^ Howard Feldman, Nowoczesne zarządzanie pamięcią, część 2 , na onlamp.com , 23 listopada 2005. Pobrano 10 listopada 2009 (zarchiwizowane z 20 września 2012) .
  5. ^ Przewodnik programowania jądra: Wskazówki dotyczące wydajności i stabilności , na stronie developer.apple.com , Apple Inc. , 7 listopada 2006 (zarchiwizowane od oryginału z 7 grudnia 2008) .
  6. ^ Randy Dunlap, Linux Kernel Development: Getting Started ( PDF ), na xenotime.net , 19 maja 2005 (archiwum z 27 lutego 2012) .

Powiązane pozycje