Auf meinem Debian GNU / Linux 9-System, wenn eine Binärdatei ausgeführt wird,
- Der Stack ist aber nicht initialisiert
- Der Heap wird auf Null gesetzt.
Warum?
Ich gehe davon aus, dass die Nullinitialisierung die Sicherheit fördert, aber wenn für den Heap, warum dann nicht auch für den Stack? Braucht der Stack auch keine Sicherheit?
Meine Frage ist meines Wissens nicht Debian-spezifisch.
Beispiel-C-Code:
#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;
}
Ausgabe:
a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0
Der C-Standard fordert natürlich nicht malloc()zum Löschen des Speichers auf, bevor er zugewiesen wird, sondern mein C-Programm dient lediglich der Veranschaulichung. Die Frage ist keine Frage zu C oder zur Standardbibliothek von C. Die Frage ist vielmehr eine Frage, warum der Kernel und / oder der Laufzeit-Loader den Heap auf Null setzen, nicht aber den Stack.
Ein weiteres Experiment
Meine Frage bezieht sich eher auf ein beobachtbares GNU / Linux-Verhalten als auf die Anforderungen von Standarddokumenten. Wenn Sie sich nicht sicher sind, was ich meine, versuchen Sie diesen Code, der weiteres undefiniertes Verhalten aufruft ( undefiniert, das heißt, soweit der C-Standard betroffen ist), um den Punkt zu veranschaulichen:
#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;
}
Ausgabe von meiner Maschine:
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
In Bezug auf den C-Standard ist das Verhalten undefiniert, sodass meine Frage den C-Standard nicht berücksichtigt. Ein Aufruf, der malloc()nicht jedes Mal dieselbe Adresse zurückgeben muss, aber da dieser Aufruf malloc()tatsächlich jedes Mal dieselbe Adresse zurückgibt, ist es interessant zu bemerken, dass der Speicher, der sich auf dem Heap befindet, jedes Mal auf Null gesetzt wird.
Im Gegensatz dazu schien der Stapel nicht auf Null gestellt zu sein.
Ich weiß nicht, was der letztere Code auf Ihrem Computer bewirken wird, da ich nicht weiß, welche Schicht des GNU / Linux-Systems das beobachtete Verhalten verursacht. Sie können es aber versuchen.
AKTUALISIEREN
@ Kusalananda hat in Kommentaren beobachtet:
Ihr neuester Code gibt verschiedene Adressen und (gelegentlich) nicht initialisierte (von Null verschiedene) Daten zurück, wenn er unter OpenBSD ausgeführt wird. Dies sagt offensichtlich nichts über das Verhalten aus, das Sie unter Linux beobachten.
Dass sich mein Ergebnis von dem unter OpenBSD unterscheidet, ist in der Tat interessant. Anscheinend entdeckten meine Experimente kein Kernel- (oder Linker-) Sicherheitsprotokoll, wie ich gedacht hatte, sondern nur ein Implementierungsartefakt.
In diesem Licht glaube ich, dass die folgenden Antworten von @mosvy, @StephenKitt und @AndreasGrapentin zusammen meine Frage regeln.
Siehe auch Stack Overflow: Warum initialisiert malloc die Werte in gcc auf 0? (Kredit: @bta).
newOperator in C ++ (auch "Heap") ist unter Linux nur ein Wrapper für malloc (); Dem Kernel ist es egal, was der "Haufen" ist.