关于函数中栈内存的分配问题追踪
参考:
《如何判断栈、堆的增长方向?》 链接:http://blog.csdn.net/changyourmind/article/details/51839395
关于栈内存:
1.特意针对栈overflow的写操作,观察打印的行文:
测试代码如下:
g++ -O0与g++ -O2表现出了不同的程序执行行为;
g++ -O0 的执行结果是:
在for循环里打印的结果是,表现为递归打印一组变量;这非常奇怪;此时i的值已经乱了,无法退出循环了;
g++ -O2的执行结果是:
在for循环里打印的结果是,按照地址偏移打印,直到遇到一个PAGE的边界,才出现段错误崩溃生成coredump;
如果for只循环10次,仅仅测试刚好运行到overflow的情形,测试再函数调用结束时,却出现了stack smashing detected
的错误;生成coredump;
这说明栈的overflow,会导致程序崩溃,产生coredump。
注意栈溢出(stackoverflow),惯性的理解是尝试写入数据到当前栈的后面的地址上,
比如当前局部变量char buf[10],尝试操作char* p=&buf[10];*p=1;*(p+1)=1;这会引起stackoverflow,产生stack smashing detected;
但是如果尝试char* p=buf; *(p-1)=1;*(p-2)=1;却运行没有问题;
stack smashing detected,其崩溃的根本的原因是因为编译器检查到写一个大于当前进程最大栈地址的地址,这个地址可能就在kernelspace了,
被主动拦截abort终止进程所导致;
这也验证了栈的地址分配是从高地址往低地址分配,而大于这个高地址的地址可能根本就不在userspace里;
segment fault的根本原因尝试写一个没有提前映射到物理内存的地址;
2.定义一个类:
参考:
《如何判断栈、堆的增长方向?》 链接:http://blog.csdn.net/changyourmind/article/details/51839395
关于栈内存:
1.特意针对栈overflow的写操作,观察打印的行文:
测试代码如下:
void test2(int ss=0)
{
int ss1;
int ss2;
int ss3=12;
int ss4;
printf("ss:%p %d\n",&ss,ss);
printf("ss1:%p %d\n",&ss1,ss1);
printf("ss2:%p %d\n",&ss2,ss2);
printf("ss3:%p %d\n",&ss3,ss3);
printf("ss4:%p %d\n",&ss4,ss4);
int* p = &ss1;
for(int i=0;i<10000;++i){
*(p+i)=0;
printf("%d %p\n",i,p+i);
//sleep(1);
}
// stack smashing detected
}
g++ -O0与g++ -O2表现出了不同的程序执行行为;
g++ -O0 的执行结果是:
在for循环里打印的结果是,表现为递归打印一组变量;这非常奇怪;此时i的值已经乱了,无法退出循环了;
g++ -O2的执行结果是:
在for循环里打印的结果是,按照地址偏移打印,直到遇到一个PAGE的边界,才出现段错误崩溃生成coredump;
如果for只循环10次,仅仅测试刚好运行到overflow的情形,测试再函数调用结束时,却出现了stack smashing detected
的错误;生成coredump;
这说明栈的overflow,会导致程序崩溃,产生coredump。
注意栈溢出(stackoverflow),惯性的理解是尝试写入数据到当前栈的后面的地址上,
比如当前局部变量char buf[10],尝试操作char* p=&buf[10];*p=1;*(p+1)=1;这会引起stackoverflow,产生stack smashing detected;
但是如果尝试char* p=buf; *(p-1)=1;*(p-2)=1;却运行没有问题;
stack smashing detected,其崩溃的根本的原因是因为编译器检查到写一个大于当前进程最大栈地址的地址,这个地址可能就在kernelspace了,
被主动拦截abort终止进程所导致;
这也验证了栈的地址分配是从高地址往低地址分配,而大于这个高地址的地址可能根本就不在userspace里;
segment fault的根本原因尝试写一个没有提前映射到物理内存的地址;
2.定义一个类:
class Node
{
public:
int a;
int b;
int getNum(){return a;}
};
void test3()
{
Node* p=(Node*)0x0101;
printf("1-> %p \n",p);
int a=p->getNum();//段错误 说明0x0101是未分配的
printf("%d\n",a);
}
void test3()
{
char buf[4] ;
strcpy(buf,"11111111");//运行至此并没有任何问题;
strcpy(buf,"111111111");//却在此处:*** stack smashing detected ***
}
class Node
{
public:
int a;
int b;
int c;
int d;
int getNum(){return a;}
};
void test4()
{
char buf[4] ;
strcpy(buf,"11111111");
Node* p3=(Node*)buf;
int a = p3->a;
p3->a=0;//运行OK;假如在getNum前面加一个virtual修饰符,运行到这里就崩溃了,这说明了Node实际内存还应该包含一个虚表指针
printf("a is:%d :%p\n",a,&(p3->a));
int b = p3->b;
printf("b is:%d :%p\n",b,&(p3->b));
int c = p3->c;
p3->c=0;//stack smashing detected
printf("c is:%d :%p\n",c,&(p3->c));
}
void test5()
{
char buf1[1024*1024*5]={0};
char buf2[1024*1024*2]={1};
char buf3[1024*1015];
//printf("%p\n",buf3);
//ulimit -a查知栈空间是8M;
//如果只是做buf的声明,而不读或写,那么即便声明的SIZE大于8M,也不会段错误;
//如果声明的SIZE大于8M,一旦出现读或者写,就会出现段错误;这说明C对变量的声明,并没有做实际的内存的映射,知道读写行为
//出现的时候,才做实际的内存映射;且这个栈容量8M,是指一个栈帧的总容量,而非某个变量的容量;
}