Bagaimana stack overflow terjadi dan apa cara terbaik untuk memastikannya tidak terjadi, atau cara mencegahnya, terutama di server web, tetapi contoh lain juga akan menarik?
memory
stack-overflow
JasonMichael
sumber
sumber
Jawaban:
Tumpukan
Tumpukan, dalam konteks ini, adalah buffer yang terakhir masuk, keluar pertama tempat Anda menempatkan data saat program Anda berjalan. Last in, first out (LIFO) berarti bahwa hal terakhir yang Anda masukkan selalu hal pertama yang Anda keluarkan - jika Anda mendorong 2 item di tumpukan, 'A' dan kemudian 'B', maka hal pertama yang Anda pop dari tumpukan akan menjadi 'B', dan hal berikutnya adalah 'A'.
Saat Anda memanggil fungsi dalam kode Anda, instruksi berikutnya setelah pemanggilan fungsi disimpan di stack, dan ruang penyimpanan apa pun yang mungkin ditimpa oleh pemanggilan fungsi. Fungsi yang Anda panggil mungkin menggunakan lebih banyak tumpukan untuk variabel lokalnya sendiri. Setelah selesai, ini membebaskan ruang tumpukan variabel lokal yang digunakan, lalu kembali ke fungsi sebelumnya.
Stack overflow
Stack overflow adalah ketika Anda telah menggunakan lebih banyak memori untuk stack daripada yang seharusnya digunakan program Anda. Dalam sistem tertanam Anda mungkin hanya memiliki 256 byte untuk tumpukan, dan jika setiap fungsi membutuhkan 32 byte maka Anda hanya dapat memiliki panggilan fungsi 8 dalam - fungsi 1 memanggil fungsi 2 yang memanggil fungsi 3 yang memanggil fungsi 4 .... siapa yang memanggil fungsi 8 yang memanggil fungsi 9, tetapi fungsi 9 menimpa memori di luar stack. Ini mungkin menimpa memori, kode, dll.
Banyak programmer membuat kesalahan ini dengan memanggil fungsi A yang kemudian memanggil fungsi B, yang kemudian memanggil fungsi C, yang kemudian memanggil fungsi A. Ini mungkin bekerja hampir sepanjang waktu, tetapi hanya sekali masukan yang salah akan menyebabkannya masuk ke dalam lingkaran itu selamanya hingga komputer mengenali bahwa tumpukan terlalu banyak.
Fungsi rekursif juga merupakan penyebabnya, tetapi jika Anda menulis secara rekursif (yaitu, fungsi Anda memanggil dirinya sendiri) maka Anda perlu menyadari hal ini dan menggunakan variabel statis / global untuk mencegah rekursi tak terbatas.
Secara umum, OS dan bahasa pemrograman yang Anda gunakan mengelola tumpukan, dan itu di luar kendali Anda. Anda harus melihat grafik panggilan Anda (struktur pohon yang menunjukkan dari fungsi utama Anda apa yang dipanggil oleh setiap fungsi) untuk melihat seberapa dalam pemanggilan fungsi Anda, dan untuk mendeteksi siklus dan rekursi yang tidak dimaksudkan. Siklus dan rekursi yang disengaja perlu diperiksa secara artifisial agar error jika mereka memanggil satu sama lain terlalu sering.
Selain praktik pemrograman yang baik, pengujian statis dan dinamis, tidak banyak yang dapat Anda lakukan pada sistem tingkat tinggi ini.
Sistem tertanam
Di dunia tertanam, terutama dalam kode keandalan tinggi (otomotif, pesawat terbang, luar angkasa) Anda melakukan tinjauan dan pemeriksaan kode ekstensif, tetapi Anda juga melakukan hal berikut:
Bahasa dan sistem tingkat tinggi
Tetapi dalam bahasa tingkat tinggi dijalankan pada sistem operasi:
Server web
Itu tergantung pada 'kotak pasir' yang Anda miliki apakah Anda dapat mengontrol atau bahkan melihat tumpukan. Kemungkinannya bagus, Anda dapat memperlakukan server web seperti yang Anda lakukan pada bahasa dan sistem operasi tingkat tinggi lainnya - sebagian besar di luar kendali Anda, tetapi periksa tumpukan bahasa dan server yang Anda gunakan. Hal ini dimungkinkan untuk meledakkan tumpukan di server SQL Anda, misalnya.
-Adam
sumber
Stack overflow dalam kode nyata sangat jarang terjadi. Sebagian besar situasi di mana itu terjadi adalah rekursi di mana penghentian telah dilupakan. Namun ini mungkin jarang terjadi pada struktur yang sangat bersarang, misalnya dokumen XML yang sangat besar. Satu-satunya bantuan nyata di sini adalah memfaktor ulang kode untuk menggunakan objek tumpukan eksplisit, bukan tumpukan panggilan.
sumber
Kebanyakan orang akan memberi tahu Anda bahwa stack overflow terjadi dengan rekursi tanpa jalur keluar - meskipun sebagian besar benar, jika Anda bekerja dengan struktur data yang cukup besar, bahkan jalur keluar rekursi yang tepat tidak akan membantu Anda.
Beberapa opsi dalam kasus ini:
sumber
Limpahan tumpukan terjadi saat Jeff dan Joel ingin memberikan dunia tempat yang lebih baik untuk mendapatkan jawaban atas pertanyaan teknis. Sudah terlambat untuk mencegah tumpukan ini meluap. "Situs lain" itu bisa mencegahnya dengan tidak menjadi scuzzy. ;)
sumber
Rekursi tak terbatas adalah cara umum untuk mendapatkan kesalahan stack overflow. Untuk mencegah - selalu pastikan ada jalan keluar yang akan dilalui . :-)
Cara lain untuk mendapatkan stack overflow (setidaknya dalam C / C ++) adalah dengan mendeklarasikan beberapa variabel besar di stack.
Itu akan berhasil.
sumber
Biasanya stack overflow adalah hasil dari panggilan rekursif tak terbatas (mengingat jumlah memori yang biasa di komputer standar saat ini).
Saat Anda melakukan panggilan ke suatu metode, fungsi, atau prosedur, cara "standar" atau melakukan panggilan terdiri atas:
Jadi, biasanya ini membutuhkan beberapa byte tergantung pada jumlah dan jenis parameter serta arsitektur mesin.
Anda akan melihat bahwa jika Anda mulai membuat panggilan rekursif, tumpukan akan mulai bertambah. Sekarang, tumpukan biasanya disimpan dalam memori sedemikian rupa sehingga tumbuh berlawanan arah dengan heap sehingga, mengingat sejumlah besar panggilan tanpa "kembali", tumpukan mulai penuh.
Sekarang, di masa lalu stack overflow dapat terjadi hanya karena Anda menghabiskan semua memori yang tersedia, begitu saja. Dengan model memori virtual (hingga 4 GB pada sistem X86) yang berada di luar cakupan, biasanya, jika Anda mendapatkan kesalahan stack overflow, cari panggilan rekursif tak terbatas.
sumber
Apa? Tidak ada yang punya cinta untuk mereka yang dibungkus oleh lingkaran tak terbatas?
sumber
Selain dari bentuk stack overflow yang Anda peroleh dari rekursi langsung (misalnya
Fibonacci(1000000)
), bentuk yang lebih halus yang telah saya alami berkali-kali adalah rekursi tidak langsung, di mana suatu fungsi memanggil fungsi lain, yang memanggil fungsi lain, dan kemudian salah satu dari fungsi-fungsi itu memanggil yang pertama lagi.Hal ini biasanya dapat terjadi dalam fungsi yang dipanggil sebagai respons terhadap peristiwa, tetapi dengan sendirinya dapat menghasilkan peristiwa baru, misalnya:
Dalam hal ini, panggilan ke
ResizeWindow
dapat menyebabkanWindowSizeChanged()
callback dipicu lagi, yang memanggilResizeWindow
lagi, hingga Anda kehabisan tumpukan. Dalam situasi seperti ini, Anda sering kali perlu menunda merespons acara sampai stack frame kembali, misalnya dengan memposting pesan.sumber
Mengingat ini ditandai dengan "hacking", saya menduga "stack overflow" yang dia maksud adalah panggilan stack overflow, daripada stack overflow tingkat yang lebih tinggi seperti yang dirujuk di sebagian besar jawaban lain di sini. Itu tidak benar-benar berlaku untuk lingkungan yang dikelola atau diinterpretasikan seperti .NET, Java, Python, Perl, PHP, dll, di mana aplikasi web biasanya ditulis, jadi satu-satunya risiko Anda adalah server web itu sendiri, yang mungkin ditulis dalam C atau C ++.
Lihat utas ini:
/programming/7308/what-is-a-good-starting-point-for-learning-buffer-overflow
sumber
Saya telah membuat ulang masalah stack overflow sambil mendapatkan angka Fibonacci yang paling umum yaitu 1, 1, 2, 3, 5 ..... jadi kalkulasi untuk fib (1) = 1 atau fib (3) = 2 .. fib (n ) = ??.
untuk n, katakanlah kita akan tertarik - bagaimana jika n = 100.000 lalu berapa angka Fibonacci yang sesuai ??
Pendekatan satu putaran adalah seperti di bawah ini -
ini cukup lurus ke depan dan hasilnya -
Sekarang pendekatan lain yang telah saya terapkan adalah melalui Divide and Concur melalui rekursi
yaitu Fib (n) = fib (n-1) + Fib (n-2) dan kemudian rekursi lebih lanjut untuk n-1 & n-2 ..... hingga 2 & 1. yang diprogram sebagai -
Ketika saya menjalankan kode untuk n = 100.000 hasilnya seperti di bawah ini -
Di atas Anda dapat melihat StackOverflowError dibuat. Sekarang alasannya adalah terlalu banyak rekursi karena -
Jadi setiap entri dalam tumpukan membuat 2 entri lagi dan seterusnya ... yang direpresentasikan sebagai -
Akhirnya begitu banyak entri akan dibuat sehingga sistem tidak dapat menangani dalam tumpukan dan StackOverflowError dilemparkan.
Untuk Pencegahan: Untuk contoh perspektif diatas - 1. Hindari menggunakan pendekatan rekursi atau kurangi / batasi rekursi dengan lagi satu divisi level seperti jika n terlalu besar maka pisahkan n sehingga sistem dapat menangani dalam batasnya. 2. Gunakan pendekatan lain, seperti pendekatan loop yang saya gunakan dalam sampel kode 1. (Saya sama sekali tidak bermaksud untuk menurunkan Divide & Concur atau Rekursi karena merupakan pendekatan legendaris di banyak algoritme paling terkenal .. niat saya adalah membatasi atau menjauh dari rekursi jika saya mencurigai adanya masalah stack overflow)
sumber