来自未初始化数组的垃圾值的一致模式
Consistent pattern in garbage value from uninitialized array
据我了解,C 中未初始化的数组意味着为数组分配的内存中的垃圾值。但是当我尝试那个的时候。
所以,我尝试了这个。
#include <stdio.h>
int main (){
int j[10];
for(int k = 0; k < 10;k++){
printf("j[%d]:%d\n",k,j[k]);
}
}
这是输出:
j[0]:0
j[1]:0
j[2]:0
j[3]:0
j[4]:0
j[5]:0
j[6]:0
j[7]:0
j[8]:0
j[9]:0
我假设 clang 只是通过将默认值放入其中来修复。我在 M1 MacBook Air 上使用 Apple clang 版本 12.0.5 (clang-1205.0.22.11) 运行ning。
现在这是令人困惑的部分:
#include <stdio.h>
int main (){
int i =10;
int j[i];
for(int k = 0; k < 10;k++){
printf("j[%d]:%d\n",k,j[k]);
}
}
这是我得到的:
首先运行
j[0]:13172736
j[1]:1
j[2]:13172736
j[3]:1
j[4]:0
j[5]:0
j[6]:1865774432
j[7]:1
j[8]:48
j[9]:0
第二个运行
j[0]:72499200
j[1]:1
j[2]:72499200
j[3]:1
j[4]:0
j[5]:0
j[6]:1806906720
j[7]:1
j[8]:48
j[9]:0
第三个运行.
j[0]:8912896
j[1]:1
j[2]:8912896
j[3]:1
j[4]:0
j[5]:0
j[6]:1870689632
j[7]:1
j[8]:48
j[9]:0
第四名:
j[0]:15417344
j[1]:1
j[2]:15417344
j[3]:1
j[4]:0
j[5]:0
j[6]:1863988576
j[7]:1
j[8]:48
j[9]:0
这里好像有点规律,而且很一致,这是从哪里来的?
在main
运行s之前,启动代码运行s。当您构建 C 程序时,链接器包含 C 环境的特殊启动代码,并将程序的起始地址设置为该代码的开头。 (此代码的地址可能用符号 _start
或 start
表示。)当程序加载器完成将程序加载到内存中时,它会在该地址启动程序 运行ning。
该代码可能会初始化堆栈区域并为 printf
例程系列、malloc
例程以及 C 或您的特定操作系统的其他功能设置初始数据。为此,它使用了一些堆栈 space。您看到的留下的数据是 activity 的结果。启动代码完成后,它会调用您的 main
例程。
您看到的不同数字是因为现代通用操作系统使用 address space layout randomization 来阻止攻击者。结果是程序中某些东西的地址,例如代码的开始、静态数据或堆栈,不同于 运行 运行.
您不能依赖此数据或其中的模式。特别是,当您在编译程序时启用优化时,编译器可能会更改数组在内存中的布局位置,或者如果它发现不需要生成 C 标准所需的结果,它可能会忽略从内存中加载数据。此外,模式可能会在 C 编译器及其相关库的版本之间发生变化,包括启动代码,因为新版本的编译器可能会以不同的方式在内存中安排内容,并且新版本的启动代码可能会在执行它们时留下不同的数据工作。
据我了解,C 中未初始化的数组意味着为数组分配的内存中的垃圾值。但是当我尝试那个的时候。 所以,我尝试了这个。
#include <stdio.h>
int main (){
int j[10];
for(int k = 0; k < 10;k++){
printf("j[%d]:%d\n",k,j[k]);
}
}
这是输出:
j[0]:0
j[1]:0
j[2]:0
j[3]:0
j[4]:0
j[5]:0
j[6]:0
j[7]:0
j[8]:0
j[9]:0
我假设 clang 只是通过将默认值放入其中来修复。我在 M1 MacBook Air 上使用 Apple clang 版本 12.0.5 (clang-1205.0.22.11) 运行ning。 现在这是令人困惑的部分:
#include <stdio.h>
int main (){
int i =10;
int j[i];
for(int k = 0; k < 10;k++){
printf("j[%d]:%d\n",k,j[k]);
}
}
这是我得到的: 首先运行
j[0]:13172736
j[1]:1
j[2]:13172736
j[3]:1
j[4]:0
j[5]:0
j[6]:1865774432
j[7]:1
j[8]:48
j[9]:0
第二个运行
j[0]:72499200
j[1]:1
j[2]:72499200
j[3]:1
j[4]:0
j[5]:0
j[6]:1806906720
j[7]:1
j[8]:48
j[9]:0
第三个运行.
j[0]:8912896
j[1]:1
j[2]:8912896
j[3]:1
j[4]:0
j[5]:0
j[6]:1870689632
j[7]:1
j[8]:48
j[9]:0
第四名:
j[0]:15417344
j[1]:1
j[2]:15417344
j[3]:1
j[4]:0
j[5]:0
j[6]:1863988576
j[7]:1
j[8]:48
j[9]:0
这里好像有点规律,而且很一致,这是从哪里来的?
在main
运行s之前,启动代码运行s。当您构建 C 程序时,链接器包含 C 环境的特殊启动代码,并将程序的起始地址设置为该代码的开头。 (此代码的地址可能用符号 _start
或 start
表示。)当程序加载器完成将程序加载到内存中时,它会在该地址启动程序 运行ning。
该代码可能会初始化堆栈区域并为 printf
例程系列、malloc
例程以及 C 或您的特定操作系统的其他功能设置初始数据。为此,它使用了一些堆栈 space。您看到的留下的数据是 activity 的结果。启动代码完成后,它会调用您的 main
例程。
您看到的不同数字是因为现代通用操作系统使用 address space layout randomization 来阻止攻击者。结果是程序中某些东西的地址,例如代码的开始、静态数据或堆栈,不同于 运行 运行.
您不能依赖此数据或其中的模式。特别是,当您在编译程序时启用优化时,编译器可能会更改数组在内存中的布局位置,或者如果它发现不需要生成 C 标准所需的结果,它可能会忽略从内存中加载数据。此外,模式可能会在 C 编译器及其相关库的版本之间发生变化,包括启动代码,因为新版本的编译器可能会以不同的方式在内存中安排内容,并且新版本的启动代码可能会在执行它们时留下不同的数据工作。