Stack overflow, bir programın bellekteki yığını (stack) için ayrılan alandan daha fazlasını kullanması durumudur. Tarihsel olarak, yığın, yerel değişkenler, geri dönüş adresleri ve fonksiyon çağrıları sırasında geçici verileri depolamak için kullanılmıştır. C'nin erken uygulamalarında yığın oldukça küçüktü ve sınırlara erişimden korunmuyordu.
Sorun; bir fonksiyon veya fonksiyon çağrıları zincirinin çok fazla yerel değişken kullanması veya çıkış koşulu olmayan rekürsif fonksiyonlar çağırması durumunda ortaya çıkar, bu da programın bellek alanının dışına veri yazmasına neden olarak hatalara, çöküşlere ve güvenlik açıklarına yol açar.
Çözüm; bellek kullanımı açısından düşük olan fonksiyonlar tasarlamak, derin veya sonsuz rekürsiyonlardan kaçınmak, büyük nesneleri yığın üzerinde yerleştirmemektir. İşletim sistemi, bellek segmenti koruması (guard pages) ile taşmayı önlemeye çalışabilir, ancak geliştirici taşmaya neden olmayacak şekilde kod yazmakla yükümlüdür.
Sonsuz rekürsiyon sonucu stack overflow oluşturan bir kod örneği:
void foo() { int arr[1000]; // Büyük yerel dizi sorunu artırır foo(); // Çıkış koşulu olmayan rekürsif çağrı } int main() { foo(); return 0; }
Anahtar özellikler:
Bir fonksiyon içinde çok büyük bir yerel dizi (örneğin, int arr[1000000]) oluşturursanız ne olur?
Cevap: Büyük bir yerel dizi hemen tüm yığını kullanabilir. İşletim sistemi ve derleyiciye bağlı olarak, bu fonksiyonun çağrısında çöküşe ya da programın çökmesine neden olabilir.
Kod örneği:
void func() { int arr[1000000]; // Çok fazla bellek arr[0] = 1; }
Rekürsiyon her zaman stack overflow'a yol açar mı?
Cevap: Hayır, rekürsiyon derinlik açısından sınırlı olduğu sürece faydalıdır. Taşma, yalnızca rekürsiyon derini çok fazlaysa ya da sınırlı değilse meydana gelir.
Bellek tasarrufu için fonksiyon içinde büyük statik diziler yerleştirilebilir mi?
Cevap: Hayır, büyük statik diziler fonksiyon içinde yine de bellek kullanır ama artık statik veri segmentinde, yığında değil. Bu her zaman verimli değildir, özellikle geçici yerel bellek gerekiyorsa.
Kod örneği:
void func() { static int arr[1000000]; // Yığından değil, ama statik alan her zaman doludur }
Bir programcı, derinlik sınırlaması olmadan ve çıkış koşulu kullanmadan büyük bir dizi sıralamak için rekürsiyon yoluyla hızlı sıralama algoritmasını gerçekleştirdi. Kod, gerçek veriler işlendiğinde stack overflow'a yol açtı.
Artıları:
Eksileri:
Başka bir programcı, kontrol edilen rekürsiyon derinliğiyle ve malloc ile büyük geçici diziler ayırarak kendi küçük yığınını kullanan iteratif bir uygulama kullandı.
Artıları:
Eksileri: