บนระบบ Debian GNU / Linux 9 ของฉันเมื่อทำการไบนารี่
- สแต็กถูกกำหนดค่าเริ่มต้น แต่
- ฮีปจะถูกกำหนดค่าเริ่มต้นเป็นศูนย์
ทำไม?
ฉันสมมติว่า zero-initialization ส่งเสริมความปลอดภัย แต่ถ้าฮีปแล้วทำไมไม่สแต็กล่ะ? สแต็กก็เช่นกันไม่ต้องการความปลอดภัยหรือไม่?
คำถามของฉันไม่เฉพาะเจาะจงกับ Debian เท่าที่ฉันรู้
ตัวอย่างรหัส 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;
}
เอาท์พุท:
a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0
มาตรฐาน C ไม่ได้ขอmalloc()
ให้ล้างหน่วยความจำก่อนที่จะทำการจัดสรร แต่โปรแกรม C ของฉันเป็นเพียงภาพประกอบเท่านั้น คำถามไม่ใช่คำถามเกี่ยวกับ C หรือเกี่ยวกับไลบรารีมาตรฐานของ C แต่คำถามเป็นคำถามเกี่ยวกับสาเหตุที่เคอร์เนลและ / หรือตัวโหลดรันไทม์กำลัง zeroing ฮีป แต่ไม่ใช่กองซ้อน
ประสบการณ์อื่น ๆ
คำถามของฉันเกี่ยวกับพฤติกรรม GNU / Linux ที่สังเกตเห็นได้มากกว่าความต้องการของเอกสารมาตรฐาน หากไม่แน่ใจในสิ่งที่ฉันหมายถึงให้ลองใช้โค้ดนี้ซึ่งเรียกใช้พฤติกรรมที่ไม่ได้กำหนดเพิ่มเติม ( ไม่ได้กำหนดนั่นคือเท่าที่เกี่ยวข้องกับมาตรฐาน C) เพื่อแสดงให้เห็นถึงจุด:
#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;
}
เอาท์พุทจากเครื่องของฉัน:
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
เท่าที่เกี่ยวข้องกับมาตรฐาน C พฤติกรรมยังไม่ได้กำหนดดังนั้นคำถามของฉันไม่เกี่ยวกับมาตรฐาน C การเรียกร้องให้malloc()
ไม่จำเป็นต้องส่งคืนที่อยู่เดิมทุกครั้ง แต่เนื่องจากการโทรmalloc()
นี้เกิดขึ้นเพื่อส่งคืนที่อยู่เดิมทุกครั้งเป็นที่น่าสนใจที่จะสังเกตเห็นว่าหน่วยความจำซึ่งอยู่ในกองนั้นมีค่าเป็นศูนย์ทุกครั้ง
ในทางกลับกันสแต็คดูเหมือนจะไม่ถูกทำให้เป็นศูนย์
ฉันไม่รู้ว่าโค้ดหลังจะทำอะไรในเครื่องของคุณเนื่องจากฉันไม่รู้ว่าเลเยอร์ของระบบ GNU / Linux ใดที่ทำให้เกิดพฤติกรรมที่สังเกตได้ คุณสามารถลองได้
UPDATE
@ Kusalananda ได้สังเกตในความคิดเห็น:
สำหรับสิ่งที่คุ้มค่ารหัสล่าสุดของคุณจะส่งคืนที่อยู่ที่แตกต่างกันและ (ไม่เป็นศูนย์) ข้อมูล (ไม่เป็นศูนย์) เมื่อเรียกใช้บน OpenBSD สิ่งนี้ไม่ได้พูดอะไรเกี่ยวกับพฤติกรรมที่คุณเห็นบน Linux
ว่าผลลัพธ์ของฉันแตกต่างจากผลลัพธ์ใน OpenBSD แน่นอนน่าสนใจ เห็นได้ชัดว่าการทดลองของฉันไม่ได้ค้นพบโปรโตคอลความปลอดภัยของเคอร์เนล (หรือตัวเชื่อมโยง) ตามที่ฉันคิด แต่เป็นเพียงเครื่องมือในการใช้งานเท่านั้น
ในแง่นี้ฉันเชื่อว่าพร้อมกันคำตอบด้านล่างของ @mosvy, @StephenKitt และ @AndreasGrapentin ชำระคำถามของฉัน
ดูเพิ่มเติมที่ Stack Overflow: ทำไม malloc เริ่มต้นค่าเป็น 0 ใน gcc (เครดิต: @bta)
new
ดำเนินการใน C ++ (เช่นเดียวกับ "heap") อยู่บน Linux ซึ่งเป็นตัวห่อสำหรับ malloc (); เคอร์เนลไม่ทราบและไม่สนใจว่า "กอง" คืออะไร