Debian GNU / Linux 9システムでは、バイナリが実行されると、
- スタックは初期化されていませんが、
- ヒープはゼロで初期化されます。
どうして?
ゼロ初期化はセキュリティを向上させると思いますが、ヒープの場合はスタックもそうではないのですか?スタックもセキュリティを必要としませんか?
私の知る限り、私の質問は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の標準ライブラリに関するものでもありません。むしろ、質問はカーネルやランタイムローダーがヒープではなくスタックをゼロにしている理由に関する質問です。
別の実験
私の質問は、標準文書の要件ではなく、観察可能な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システムのどの層が観察された動作を引き起こしているのかわからないので、後者のコードがあなたのマシンでどうなるかはわかりません。試してみてください。
更新
@Kusalanandaはコメントで観察しました:
価値のあるものとして、OpenBSDで実行すると、最新のコードは異なるアドレスと(ときどき)初期化されていない(ゼロでない)データを返します。これは明らかに、Linuxで目撃している動作については何も言っていません。
私の結果がOpenBSDの結果と異なることは確かに興味深いです。どうやら、私の実験では、思ったようにカーネル(またはリンカー)セキュリティプロトコルではなく、単なる実装上の成果物を発見していました。
この観点から、@ mosvy、@ StephenKitt、@ AndreasGrapentinの以下の回答が一緒になって私の疑問を解決すると信じています。
Stack Overflowも参照してください:なぜmallocはgccで値を0に初期化するのですか?(クレジット:@bta)。
new
C ++ の演算子(「ヒープ」)はLinuxではmalloc()の単なるラッパーです。カーネルは「ヒープ」が何であるかを知りません。