Di sistem Debian GNU / Linux 9 saya, ketika biner dijalankan,
- stack belum diinisialisasi tetapi
- heap diinisialisasi nol.
Mengapa?
Saya berasumsi bahwa inisialisasi nol mempromosikan keamanan tetapi, jika untuk heap, lalu mengapa tidak juga untuk stack? Apakah tumpukan juga tidak membutuhkan keamanan?
Pertanyaan saya tidak spesifik untuk Debian sejauh yang saya tahu.
Contoh kode C:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
const size_t n = 8;
// --------------------------------------------------------------------
// UNINTERESTING CODE
// --------------------------------------------------------------------
static void print_array(
const int *const p, const size_t size, const char *const name
)
{
printf("%s at %p: ", name, p);
for (size_t i = 0; i < size; ++i) printf("%d ", p[i]);
printf("\n");
}
// --------------------------------------------------------------------
// INTERESTING CODE
// --------------------------------------------------------------------
int main()
{
int a[n];
int *const b = malloc(n*sizeof(int));
print_array(a, n, "a");
print_array(b, n, "b");
free(b);
return 0;
}
Keluaran:
a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0
Standar C tidak meminta malloc()
untuk menghapus memori sebelum mengalokasikannya, tentu saja, tetapi program C saya hanya untuk ilustrasi. Pertanyaannya bukan pertanyaan tentang C atau tentang perpustakaan standar C. Sebaliknya, pertanyaannya adalah pertanyaan tentang mengapa kernel dan / atau run-time loader memusatkan perhatian pada tumpukan tetapi bukan tumpukan.
EKSPERIMEN LAIN
Pertanyaan saya mengenai perilaku GNU / Linux yang dapat diamati daripada persyaratan dokumen standar. Jika tidak yakin apa yang saya maksud, maka coba kode ini, yang memanggil perilaku tidak terdefinisi lebih lanjut ( tidak terdefinisi, yaitu sejauh menyangkut standar C) untuk menggambarkan poin:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
const size_t n = 4;
int main()
{
for (size_t i = n; i; --i) {
int *const p = malloc(sizeof(int));
printf("%p %d ", p, *p);
++*p;
printf("%d\n", *p);
free(p);
}
return 0;
}
Output dari mesin saya:
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
Sejauh menyangkut standar C, perilaku tidak terdefinisi, jadi pertanyaan saya tidak mempertimbangkan standar C. Panggilan untuk malloc()
tidak perlu mengembalikan alamat yang sama setiap kali tetapi, karena panggilan untuk malloc()
ini memang benar-benar mengembalikan alamat yang sama setiap kali, menarik untuk memperhatikan bahwa memori, yang ada di heap, adalah nol setiap kali.
Tumpukan itu, sebaliknya, tampaknya tidak memusatkan perhatian.
Saya tidak tahu apa yang akan dilakukan kode terakhir pada mesin Anda, karena saya tidak tahu lapisan mana dari sistem GNU / Linux yang menyebabkan perilaku yang diamati. Anda bisa mencobanya.
MEMPERBARUI
@ Kusalananda telah mengamati dalam komentar:
Untuk apa nilainya, kode terbaru Anda mengembalikan alamat yang berbeda dan (sesekali) data yang tidak diinisialisasi (bukan nol) ketika dijalankan di OpenBSD. Ini jelas tidak mengatakan apa-apa tentang perilaku yang Anda saksikan di Linux.
Bahwa hasil saya berbeda dengan hasil di OpenBSD memang menarik. Rupanya, percobaan saya bukan menemukan protokol keamanan kernel (atau linker), seperti yang saya pikirkan, tetapi hanya artefak implementasi.
Dalam terang ini, saya percaya bahwa, bersama-sama, jawaban di bawah @mosvy, @StephenKitt dan @AndreasGrapentin menyelesaikan pertanyaan saya.
Lihat juga di Stack Overflow: Mengapa malloc menginisialisasi nilai ke 0 dalam gcc? (kredit: @bta).
new
operator dalam C ++ (juga "tumpukan") adalah di Linux hanya bungkus untuk malloc (); kernel tidak tahu atau tidak peduli apa "heap" itu.