Apakah OS menyimpan jumlah ruang virtual yang valid untuk stack atau sesuatu yang lain? Apakah saya dapat menghasilkan stack overflow hanya dengan menggunakan variabel lokal besar?
Saya telah menulis sebuah C
program kecil untuk menguji asumsi saya. Ini berjalan pada X86-64 CentOS 6.5.
#include <string.h>
#include <stdio.h>
int main()
{
int n = 10240 * 1024;
char a[n];
memset(a, 'x', n);
printf("%x\n%x\n", &a[0], &a[n-1]);
getchar();
return 0;
}
Menjalankan program memberi &a[0] = f0ceabe0
dan&a[n-1] = f16eabdf
Peta proc menunjukkan tumpukan: 7ffff0cea000-7ffff16ec000. (10248 * 1024B)
Kemudian saya mencoba meningkatkan n = 11240 * 1024
Menjalankan program memberi &a[0] = b6b36690
dan&a[n-1] = b763068f
Peta proc menunjukkan tumpukan: 7fffb6b35000-7fffb7633000. (11256 * 1024B)
ulimit -s
tercetak 10240
di PC saya.
Seperti yang Anda lihat, dalam kedua kasus ukuran tumpukan lebih besar dari yang ulimit -s
diberikan. Dan tumpukan tumbuh dengan variabel lokal yang lebih besar. Bagian atas tumpukan entah bagaimana lebih dari 3-5kB &a[0]
(AFAIK zona merah adalah 128B).
Jadi bagaimana peta tumpukan ini dialokasikan?
sumber
ulimit -s
memberikan 10.240, seperti di bawah kondisi OP, dan saya mendapatkan SIGSEGV seperti yang diharapkan (inilah yang diperlukan oleh POSIX: "Jika batas ini terlampaui, SIGSEGV akan dihasilkan untuk utas. "). Saya menduga ada bug di kernel OP.Kernel Linux 4.2
rlim[RLIMIT_STACK]
yang sesuai dengan POSIXgerlimit(RLIMIT_STACK)
acct_stack_growth
Program tes minimal
Kami kemudian dapat mengujinya dengan program NASM 64-bit minimal:
Pastikan Anda mematikan ASLR dan menghapus variabel lingkungan karena itu akan tersimpan di stack dan menghabiskan ruang:
Batasnya ada di suatu tempat sedikit di bawah saya
ulimit -s
(8MiB untuk saya). Sepertinya ini karena ekstra data yang ditentukan Sistem V pada awalnya diletakkan di tumpukan di samping lingkungan: Linux 64 parameter baris perintah di Majelis | Stack OverflowJika Anda serius tentang ini, TODO membuat gambar initrd minimal yang mulai menulis dari tumpukan atas dan turun, dan kemudian jalankan dengan QEMU + GDB . Letakkan
dprintf
di loop mencetak alamat stack, dan breakpoint diacct_stack_growth
. Itu akan mulia.Terkait:
sumber
Secara default, ukuran tumpukan maksimal dikonfigurasikan menjadi 8MB per proses,
tetapi dapat diubah menggunakan
ulimit
:Menampilkan default di kB:
Setel ke tidak terbatas:
ulimit -s unlimited
mempengaruhi shell saat ini dan subkulit dan proses anak mereka.
(
ulimit
adalah perintah shell builtin)Anda dapat menunjukkan kisaran alamat tumpukan aktual yang digunakan dengan:
cat /proc/$PID/maps | grep -F '[stack]'
di Linux.
sumber
ulimit -s
KB berlaku untuk program tersebut. Dalam kasus saya ini 10240KB. Tetapi ketika saya mendeklarasikan arraychar a[10240*1024]
dan set lokala[0]=1
, program keluar dengan benar. Mengapa?int n = 10240*1024; char a[n]; memset(a,'x',n);
... kesalahan seg.a[]
belum dialokasikan di tumpukan 10MB Anda. Kompiler mungkin telah melihat bahwa tidak mungkin ada panggilan rekursif dan telah melakukan alokasi khusus, atau sesuatu yang lain seperti tumpukan diskontinyu atau tipuan.