Penyimpanan yang dikembalikan oleh malloc() tidak diinisialisasi nol. Jangan pernah berasumsi demikian.
Dalam program pengujian Anda, itu hanya kebetulan:Saya rasa malloc()
baru saja mendapatkan blok baru mmap()
, tapi jangan mengandalkan itu juga.
Sebagai contoh, jika saya menjalankan program Anda di mesin saya dengan cara ini:
$ echo 'void __attribute__((constructor)) p(void){
void *b = malloc(4444); memset(b, 4, 4444); free(b);
}' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so
$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036
Contoh kedua Anda hanya memperlihatkan artefak dari malloc
implementasi di glibc; jika Anda melakukannya, ulangi malloc
/free
dengan buffer yang lebih besar dari 8 byte, Anda akan melihat dengan jelas bahwa hanya 8 byte pertama yang dinolkan, seperti pada kode contoh berikut.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
const size_t n = 4;
const size_t m = 0x10;
int main()
{
for (size_t i = n; i; --i) {
int *const p = malloc(m*sizeof(int));
printf("%p ", p);
for (size_t j = 0; j < m; ++j) {
printf("%d:", p[j]);
++p[j];
printf("%d ", p[j]);
}
free(p);
printf("\n");
}
return 0;
}
Keluaran:
0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4
Terlepas dari bagaimana tumpukan diinisialisasi, Anda tidak melihat tumpukan asli, karena pustaka C melakukan beberapa hal sebelum memanggil main
, dan mereka menyentuh tumpukan.
Dengan pustaka GNU C, pada x86-64, eksekusi dimulai pada titik masuk _start, yang memanggil __libc_start_main
untuk mengatur segalanya, dan yang terakhir akhirnya memanggil main
. Namun sebelum memanggil main
, itu memanggil sejumlah fungsi lain, yang menyebabkan berbagai potongan data ditulis ke tumpukan. Konten tumpukan tidak dihapus di antara pemanggilan fungsi, jadi saat Anda masuk ke main
, tumpukan Anda berisi sisa dari pemanggilan fungsi sebelumnya.
Ini hanya menjelaskan hasil yang Anda dapatkan dari tumpukan, lihat jawaban lain terkait pendekatan dan asumsi umum Anda.
Dalam kedua kasus tersebut, Anda mendapatkan tidak diinisialisasi memori, dan Anda tidak dapat membuat asumsi apa pun tentang isinya.
Saat OS harus membagi halaman baru ke proses Anda (apakah itu untuk tumpukannya atau untuk arena yang digunakan oleh malloc()
), itu menjamin bahwa itu tidak akan mengekspos data dari proses lain; cara biasa untuk memastikannya adalah dengan mengisinya dengan nol (tetapi sama validnya untuk menimpa dengan hal lain, termasuk bahkan halaman senilai /dev/urandom
- sebenarnya beberapa debugging malloc()
implementasi menulis pola bukan nol, untuk menangkap asumsi yang salah seperti milik Anda).
Jika malloc()
dapat memenuhi permintaan dari memori yang sudah digunakan dan dirilis oleh proses ini, isinya tidak akan dihapus (sebenarnya, kliring tidak ada hubungannya dengan malloc()
dan tidak mungkin - itu harus terjadi sebelum memori dipetakan ke dalam ruang alamat Anda). Anda mungkin mendapatkan memori yang sebelumnya telah ditulis oleh proses/program Anda (misalnya sebelum main()
).
Dalam program contoh Anda, Anda melihat malloc()
wilayah yang belum ditulis oleh proses ini (yaitu langsung dari halaman baru) dan tumpukan yang telah ditulis (oleh pre-main()
kode dalam program Anda). Jika Anda memeriksa lebih banyak tumpukan, Anda akan menemukan bahwa tumpukan itu terisi nol lebih jauh ke bawah (ke arah pertumbuhannya).
Jika Anda benar-benar ingin memahami apa yang terjadi di tingkat OS, saya sarankan Anda melewati lapisan Perpustakaan C dan berinteraksi menggunakan panggilan sistem seperti brk()
dan mmap()
sebagai gantinya.