W moim systemie Debian GNU / Linux 9, gdy plik binarny jest wykonywany,
- stos jest niezainicjowany, ale
- sterta jest inicjowana zerem.
Dlaczego?
Zakładam, że inicjalizacja zera promuje bezpieczeństwo, ale jeśli dla stosu, to dlaczego nie także dla stosu? Czy stos też nie potrzebuje bezpieczeństwa?
O ile wiem, moje pytanie nie jest specyficzne dla Debiana.
Przykładowy kod 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;
}
Wynik:
a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0
malloc()
Oczywiście standard C nie wymaga wyczyszczenia pamięci przed jej przydzieleniem, ale mój program C służy jedynie do ilustracji. Pytanie nie jest pytaniem o C ani o standardową bibliotekę C. Raczej pytanie dotyczy tego, dlaczego jądro i / lub moduł ładujący w czasie wykonywania zerują stertę, ale nie stos.
KOLEJNY DOŚWIADCZENIE
Moje pytanie dotyczy obserwowalnego zachowania GNU / Linuksa, a nie wymagań dokumentów standardów. Jeśli nie jestem pewien, co mam na myśli, wypróbuj ten kod, który wywołuje dalsze niezdefiniowane zachowanie ( niezdefiniowane, to znaczy w odniesieniu do standardu C), aby zilustrować tę kwestię:
#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;
}
Dane wyjściowe z mojej maszyny:
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
Jeśli chodzi o standard C, zachowanie jest niezdefiniowane, więc moje pytanie nie dotyczy normy C. Wywołanie, które malloc()
nie musi zwracać tego samego adresu za każdym razem, ale ponieważ to wezwanie malloc()
rzeczywiście rzeczywiście zwraca ten sam adres za każdym razem, interesujące jest zauważenie, że pamięć, która jest na stercie, jest zerowana za każdym razem.
Natomiast stos nie wydawał się wyzerowany.
Nie wiem, co ten ostatni kod zrobi na twoim komputerze, ponieważ nie wiem, która warstwa systemu GNU / Linux powoduje obserwowane zachowanie. Możesz tylko spróbować.
AKTUALIZACJA
@Kusalananda zauważył w komentarzach:
Jeśli chodzi o wartość, najnowszy kod zwraca różne adresy i (sporadycznie) niezainicjowane (niezerowe) dane, gdy jest uruchamiany na OpenBSD. To oczywiście nie mówi nic o zachowaniu, którego obserwujesz w Linuksie.
To, że mój wynik różni się od wyniku na OpenBSD, jest naprawdę interesujące. Najwyraźniej moje eksperymenty odkrywały nie protokół bezpieczeństwa jądra (lub linkera), jak myślałem, ale zwykły artefakt implementacyjny.
W tym świetle uważam, że łącznie poniższe odpowiedzi @mosvy, @StephenKitt i @AndreasGrapentin rozstrzygają moje pytanie.
Zobacz także Przepełnienie stosu: dlaczego malloc inicjuje wartości na 0 w gcc? (kredyt: @bta).
new
operator C ++ (także „sterty”) jest Linux tylko owijka malloc (); jądro nie wie ani nie obchodzi, czym jest „sterta”.