Trên hệ thống Debian GNU / Linux 9 của tôi, khi tệp nhị phân được thực thi,
- ngăn xếp chưa được khởi tạo nhưng
- heap là không khởi tạo.
Tại sao?
Tôi giả định rằng việc khởi tạo bằng không thúc đẩy bảo mật nhưng, nếu cho heap, thì tại sao không cho stack? Có ngăn xếp quá, không cần bảo mật?
Câu hỏi của tôi không dành riêng cho Debian theo như tôi biết.
Mã C mẫu:
#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;
}
Đầu ra:
a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0
Tất nhiên, tiêu chuẩn C không yêu cầu malloc()
xóa bộ nhớ trước khi phân bổ nó, nhưng chương trình C của tôi chỉ đơn thuần là để minh họa. Câu hỏi không phải là câu hỏi về C hay về thư viện chuẩn của C. Thay vào đó, câu hỏi là một câu hỏi về lý do tại sao kernel và / hoặc bộ tải thời gian chạy bằng 0 heap mà không phải là stack.
KINH NGHIỆM KHÁC
Câu hỏi của tôi liên quan đến hành vi GNU / Linux có thể quan sát hơn là các yêu cầu của tài liệu tiêu chuẩn. Nếu không chắc ý tôi là gì, thì hãy thử mã này, gọi ra hành vi không xác định thêm ( không xác định, nghĩa là theo tiêu chuẩn C có liên quan) để minh họa điểm:
#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;
}
Đầu ra từ máy của tôi:
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
Theo như tiêu chuẩn C có liên quan, hành vi không được xác định, vì vậy câu hỏi của tôi không liên quan đến tiêu chuẩn C. Một cuộc gọi malloc()
không cần phải trả lại cùng một địa chỉ mỗi lần, nhưng vì cuộc gọi malloc()
này thực sự xảy ra để trả lại cùng một địa chỉ mỗi lần, thật thú vị khi nhận thấy rằng bộ nhớ nằm trong heap, mỗi lần bị xóa.
Ngược lại, ngăn xếp dường như không có gì.
Tôi không biết mã sau sẽ làm gì trên máy của bạn, vì tôi không biết lớp nào của hệ thống GNU / Linux đang gây ra hành vi được quan sát. Bạn có thể nhưng hãy thử nó.
CẬP NHẬT
@Kusalananda đã quan sát trong các ý kiến:
Đối với giá trị của nó, mã gần đây nhất của bạn trả về các địa chỉ khác nhau và dữ liệu (không thường xuyên) không được khởi tạo (khác không) khi chạy trên OpenBSD. Điều này rõ ràng không nói bất cứ điều gì về hành vi mà bạn đang chứng kiến trên Linux.
Kết quả của tôi khác với kết quả trên OpenBSD thực sự thú vị. Rõ ràng, các thí nghiệm của tôi đã phát hiện ra không phải là một giao thức bảo mật kernel (hoặc trình liên kết), như tôi đã nghĩ, mà chỉ là một tạo tác triển khai.
Trong ánh sáng này, tôi tin rằng, cùng nhau, các câu trả lời dưới đây của @mosvy, @StephenKitt và @AndreasGrapentin giải quyết câu hỏi của tôi.
Xem thêm về Stack Overflow: Tại sao malloc khởi tạo các giá trị thành 0 trong gcc? (tín dụng: @bta).
new
toán tử trong C ++ (còn "đống") là trên Linux chỉ là một wrapper cho malloc (); hạt nhân không biết cũng không quan tâm "heap" là gì.