当前位置:文档之家› 堆栈溢出的问题

堆栈溢出的问题

堆栈溢出的问题
堆栈溢出的问题

通过堆栈溢出来获得root权限是目前使用的相当普遍的一项黑客技术。事实上这是一个黑客在系统本地已经拥有了一个基本账号后的首选攻击方式。他也被广泛应用于远程攻击。通过对daemon进程的堆栈溢出来实现远程获得rootshell的技术,已经被很多实例实现。

在windows系统中,同样存在着堆栈溢出的问题。而且,随着internet的普及,win系列平台上的internet服务程序越来越多,低水平的win程序就成为你系统上的致命伤。因为它们同样会被远程

堆栈溢出,而且,由于win系统使用者和管理者普遍缺乏安全防范的意识,一台win系统上的堆栈溢出,如果被恶意利用,将导致整个机器被敌人所控制。进而,可能导致整个局域网落入敌人之手。

本系列讲座将系统的介绍堆栈溢出的机制,原理,应用,以及防范的措施。希望通过我的讲座,大

家可以了解和掌握这项技术。而且,会自己去寻找堆栈溢出漏洞,以提高系统安全。

堆栈溢出系列讲座

入门篇

本讲的预备知识:

首先你应该了解intel汇编语言,熟悉寄存器的组成和功能。你必须有堆栈和存储分配方面的基础

知识,有关这方面的计算机书籍很多,我将只是简单阐述原理,着重在应用。

其次,你应该了解linux,本讲中我们的例子将在linux上开发。

1:首先复习一下基础知识。

从物理上讲,堆栈是就是一段连续分配的内存空间。在一个程序中,会声明各种变量。静态全局变

量是位于数据段并且在程序开始运行的时候被加载。而程序的动态的局部变量则分配在堆栈里面。

从操作上来讲,堆栈是一个先入后出的队列。他的生长方向与内存的生长方向正好相反。我们规定

内存的生长方向为向上,则栈的生长方向为向下。压栈的操作push=ESP-4,出栈的操作是

pop=ESP+4.换句话说,堆栈中老的值,其内存地址,反而比新的值要大。请牢牢记住这一点,因为这是堆栈溢出的基本理论依据。

在一次函数调用中,堆栈中将被依次压入:参数,返回地址,EBP。如果函数有局部变量,接下来,就在堆栈中开辟相应的空间以构造变量。函数执行结束,这些局部变量的内容将被丢失。但是不被清除。在函数返回的时候,弹出EBP,恢复堆栈到函数调用的地址,弹出返回地址到EIP以继续执行程序。

在C语言程序中,参数的压栈顺序是反向的。比如func(a,b,c)。在参数入栈的时候,是:先压c,再压b,最后压a.在取参数的时候,由于栈的先入后出,先取栈顶的a,再取b,最后取c。(PS:如果你看不懂上面这段概述,请你去看以看关于堆栈的书籍,一般的汇编语言书籍都会详细的讨论堆栈,必须弄懂它,你才能进行下面的学习)

2:好了,继续,让我们来看一看什么是堆栈溢出。

2.1:运行时的堆栈分配

堆栈溢出就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界。结果覆盖了老的堆栈数据。

比如有下面一段程序:

程序一:

#include

int main ( )

{

char name[8];

printf("Please type your name: ");

gets(name);

printf("Hello, %s!", name);

return 0;

}

编译并且执行,我们输入ipxodi,就会输出Hello,ipxodi!。程序运行中,堆栈是怎么操作的呢?

在main函数开始运行的时候,堆栈里面将被依次放入返回地址,EBP。我们用gcc -S 来获得汇编语

言输出,可以看到main函数的开头部分对应如下语句:

pushl %ebp

movl %esp,%ebp

subl $8,%esp

首先他把EBP保存下来,,然后EBP等于现在的ESP,这样EBP就可以用来访问本函数的局部变量。之后ESP减8,就是堆栈向上增长8个字节,用来存放name[]数组。现在堆栈的布局如下:

内存底部内存顶部

name EBP ret

<------ [ ][ ][ ]

^&name

堆栈顶部堆栈底部

执行完gets(name)之后,堆栈如下:

内存底部内存顶部

name EBP ret

<------ [ipxodi\0 ][ ][ ]

^&name

堆栈顶部堆栈底部

最后,main返回,弹出ret里的地址,赋值给EIP,CPU继续执行EIP所指向的指令。

2.2:堆栈溢出

好,看起来一切顺利。我们再执行一次,输入ipxodiAAAAAAAAAAAAAAA,执行完gets(name)之后,堆栈如下:内存底部内存顶部

name EBP ret

<------ [ipxodiAA][AAAA][AAAA].......

^&name

堆栈顶部堆栈底部

由于我们输入的name字符串太长,name数组容纳不下,只好向内存顶部继续写‘A’。由于堆栈的

生长方向与内存的生长方向相反,这些‘A’覆盖了堆栈的老的元素。如图我们可以发现,EBP,

ret都已经被‘A’覆盖了。在main返回的时候,就会把‘AAAA’的ASCII码:0x41414141作为返回

地址,CPU会试图执行0x41414141处的指令,结果出现错误。这就是一次堆栈溢出。

3:如何利用堆栈溢出

我们已经制造了一次堆栈溢出。其原理可以概括为:由于字符串处理函数(gets,strcpy等等)没

有对数组越界加以监视和限制,我们利用字符数组写越界,覆盖堆栈中的老元素的值,就可以修改

返回地址。

在上面的例子中,这导致CPU去访问一个不存在的指令,结果出错。事实上,当堆栈溢出的时候,

我们已经完全的控制了这个程序下一步的动作。如果我们用一个实际存在指令地址来覆盖这个返回

地址,CPU就会转而执行我们的指令。在UINX系统中,我们的指令可以执行一个shell,这个shell 将获得和被我们堆栈溢出的程序相同的权限。如果这个程序是setuid的,那么我们就可以获得root shell。

防止缓冲区溢出杜绝如今最常见的程序缺陷方案

什么是缓冲区溢出? 缓冲区以前可能被定义为“包含相同数据类型的实例的一个连续计算机内存块”。在 C 和 C 中,缓冲区通常是使用数组和诸如 malloc() 和 new 这样的内存分配例程来实现的。极其常见的缓冲区种类是简单的字符数组。溢出是指数据被添加到分配给该缓冲区的内存块之外。 如果攻击者能够导致缓冲区溢出,那么它就能控制程序中的其他值。虽然存在许多利用缓冲区溢出的方法,不过最常见的方法还是“stack-smashing”攻击。Elias Levy (又名为 Aleph One)的一篇经典文章“Smashing the Stack for Fun and Profit”解释了 stack-smashing 攻击,Elias Levy 是 Bugtraq 邮件列表(请参阅参考资料以获得相关链接)的前任主持人。 为了理解 stack-smashing 攻击(或其他任何缓冲区攻击)是如何进行的,您需要了解一些关于计算机在机器语言级实际如何工作的知识。在类 UNIX 系统上,每个进程都可以划分为三个主要区域:文本、数据和堆栈。文本区域包括代码和只读数据,通常不能对它执行写入操作。数据区域同时包括静态分配的内存(比如全局和静态数据)和动态分配的内存(通常称为堆)。堆栈区域用于允许函数/方法调用;它用于记录函数完成之后的返回位置,存储函数中使用的本地变量,向函数传递参数,以及从函数返回值。每当调用一个函数,就会使用一个新的堆栈帧来支持该调用。了解这些之后,让我们来考察一个简单的程序。 清单 1. 一个简单的程序 void function1(int a, int b, int c) { char buffer1[5]; gets(buffer1); /* DON'T DO THIS */ } void main() { function(1,2,3); } 假设使用 gcc 来编译清单 1 中的简单程序,在 X86 上的 Linux 中运行,并且紧跟在对 gets()的调用之后中止。此时的内存内容看起来像什么样子呢?答案是它看起来类似图 1,其中展示了从左边的低位地址到右边的高位地址排序的内存布局。 内存的底部内存的顶部 buffer1 sfp ret a b c <--- 增长 --- [ ] [ ] [ ] [ ] [ ] [ ] ... 堆栈的顶部堆栈的底部

程序溢出的基础和原理

程序溢出的基础和原理 一:基础知识 计算机内存运行分配的区域分为3个 程序段区域:不允许写的 数据段区域:静态全局变量是位于数据段并且在程序开始运行的时候被加载 堆栈区域:放置程序的动态的用于计算的局部和临时变量则分配在堆栈里面和在过程调用中压入的返回地 址数据。堆栈是一个先入后出的队列。一般计算机系统堆栈的方向与内存的方向相反。压栈的xx作push=ESP-4,出栈的xx作是pop=ESP+4. 在一次函数调用中,堆栈中将被依次压入:参数,返回地址,EBP。如果函数有局部变量,接下来,就在堆栈中开辟相应的空间以构造变量。函数执行结束,这些局部变量的内容将被丢失。但是不被清除。在函数返回的时候,弹出EBP,恢复堆栈到函数调用的地址,弹出返回地址到EIP以继续执行程序。 在C语言程序中,参数的压栈顺序是反向的。比如func(a,b,c)。在参数入栈的时候,是:先压c,再压b,最后a.在取参数的时候, 指令执行的图例: 指令区域 执行程序区 0 1 2 3 4 8 调用100处的函数,参数1(3位),2(10位) C 10 0 1 2 3 100 执行处理 104 108 10C 110 返回调用堆栈区域 0 1 2 3 如果EBP分配的空间不够xx作就是产生溢出的地方 200 保存以前的EBP4位(数据段的指针,用于可以使用局部动态 变量)现在的EBP等于当前的ESP-动态数据的大小值, ESP=200 204 0C 00 00 00 此处是程序的返回地址 208 参数1,填充1位 20C 参数2填充2位 210 讲解例子WIN下的程序DEMO,演示参数导致的返回地址的变化

如何优化单片机C程序及堆栈溢出、RAM空间优化

如何优化单片机中的C程序 堆栈溢出:在调试程序的时候有事会碰到堆栈溢出的情况,堆栈为什么会溢出呢,个人总结主要有以下几点: a、是否有修改堆栈指针; c语言编写者一般不会主动修改堆栈指针的,除非在特殊情况下才会涉及到与此相关的操作,如在扩展区独立开辟一段存储空间用于压栈时数据的存储区。 b、是否嵌套的数据保护的内容超过堆栈; 此种情况发生的几率比较多,个人估计占到80%左右,这种情况就是RAM本就不是很充足,此时又发生了中断嵌套,上一个中断占用的现场保护空间还没有释放,另一个中断又要重新占用大量空间进行现场数据的保存。这样可定会造成空间不够用,堆栈溢出是很显然的。建议避免中断嵌套(方法1:可以再优先级低的中断中先关掉优先级高的中断,这或许会影响程序的执行效果。方法2:换用RAM 比较大的IC或扩展RAM,这种方法要提高成本。) c、程序中进行的算术运算比较多 计算机最擅长的运算就是加法运算,在程序中弄了好多浮点运算、求余运算、除法运算,而且数据量很大,运算过程中是要占用很多空

间的,建议能优化算术运算的尽量优化,下面介绍如何优化程序,个人总结加上网上搜索。 优化程序: 1、选择合适的算法和数据结构 应该熟悉算法语言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机书籍上都有介绍。将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,都可以大大提高程序执行的效率。.选择一种合适的数据结构也很重要,比如你在一堆随机存放的数中使用了大量的插入和删除指令,那使用链表要快得多。 数组与指针语句具有十分密码的关系,一般来说,指针比较灵活简洁,而数组则比较直观,容易理解。对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。但是在Keil中则相反,使用数组比使用的指针生成的代码更短。 2、使用尽量小的数据类型 能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型变量定义的变量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不

缓冲区溢出攻击与防范

计算机病毒和入侵检测大作业 缓冲区溢出攻击与防范Buffer overflow attacking and prevention 学院(系):软件学院 专业:软件工程 学生姓名:刘毅超 学号:201192057 班级:软件1116 完成日期:2013年12月30日 大连理工大学 Dalian University of Technology

目录 1 引言 (3) 2 基本原理分析 (3) 3 制造缓冲区溢出 (4) 3.1 格式化字符串: (4) 3.2 堆栈缓冲区(Buffer)溢出攻击: (6) 3.3 HEAP/BSS溢出攻击: (8) 4 预防缓冲区溢出攻击 (10) 4.1 强制写正确的代码 (10) 4.2 使缓冲区不可执行 (10) 4.3 利用编译器的边界检查来实现缓冲区的保护 (10) 4.4 在程序指针失效前进行完整性检查 (11) 4.5 可不可以从根本上解决缓冲区溢出攻击 (11) 5 总结 (11) 6 参考资料 (12)

1 引言 缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,使得溢出的数据覆盖在合法数据上。在当前网络与分布式系统安全中,被广泛利用的50%以上都是缓冲区溢出,而缓冲区溢出中,最为危险的是堆栈溢出。(操作系统所使用的缓冲区又被称为"堆栈".。在各个操作进程之间,指令会被临时储存在"堆栈"当中,"堆栈"也会出现缓冲区溢出。)本文详细分析了缓冲区溢出的原理,描述了利用缓冲区溢出漏洞进行系统攻击的一般过程,最后简单讨论了几种缓冲区溢出的保护方法。 2 基本原理分析 缓冲区是内存中存放数据的地方。在程序试图将数据放到机器内存中的某一个位置的时候,因为没有足够的空间就会发生缓冲区溢出。而人为的溢出则是有一定企图的,攻击者写一个超过缓冲区长度的字符串,植入到缓冲区,然后再向一个有限空间的缓冲区中植入超长的字符串,这时可能会出现两个结果:一是过长的字符串覆盖了相邻的存储单元,引起程序运行失败,严重的可导致系统崩溃;另一个结果就是利用这种漏洞可以执行任意指令,甚至可以取得系统root特级权限。 缓冲区是程序运行的时候机器内存中的一个连续块,它保存了给定类型的数据,随着动态分配变量会出现问题。大多时为了不占用太多的内存,一个有动态分配变量的程序在程序运行时才决定给它们分配多少内存。如果程序在动态分配缓冲区放入超长的数据,它就会溢出了。一个缓冲区溢出程序使用这个溢出的数据将汇编语言代码放到机器的内存里,通常是产生root权限的地方。仅仅单个的缓冲区溢出并不是问题的根本所在。但如果溢出送到能够以root权限运行命令的区域,一旦运行这些命令,那可就等于把机器拱手相让了。 现在存在的主要的缓冲区溢出攻击有格式化串缓冲区溢出攻击,堆栈缓冲区(Buffer)溢出攻击和HEAP/BSS的缓冲区溢出。

缓冲区溢出原理及防范

摘要: 正文: 大纲: 1.引言; 随着网络安全技术的飞速发展,缓冲区溢出漏洞已经成为当前最具安全威胁的漏洞之一,缓冲区溢出攻击也成为一种非常有效而常见的攻击方法。如Internet上的第1例蠕虫(Morris)攻击,就是利用了fingerd的缓冲区溢出漏洞。SANS评选出的2005年威胁最大的20个漏洞中,有8个跟缓冲区溢出有关。根据CNCERT最近几周的计算机安全漏洞的统计数据,与缓冲区溢出有关的安全事件占了很大的比例。这些都充分说明了研究缓冲区溢出的重要性。本文主要介绍了windows下的缓冲区溢出的相关知识。 2.漏洞原因和原理; 2.1 产生原因; 当向一个已分配了确定存储空间的缓冲区内复制多于该缓冲区处理能力的数据时,就会发生缓冲区溢出,溢出包括堆溢出和堆栈溢出。它与程序在内存中的分布有关,而它产生的直接原因是由于C/C++程序中的一些函数调用时,没有进行边界检查,如C函数库中的strcpy(),strcat(),sprintf(),gets()等都是不安全的。 由上面的分析可知要产生缓冲区溢出,需要有几个条件: 1) 程序编译时在堆栈上分配了固定大小的缓冲区,并且在对缓冲区进行访问时没有提供边界检查。这条在C/C ++语言中就满足,而对于有边界检查的语言,如Pascal 等,就没有这样的溢出问题。 2) 程序调用了没有进行边界检查的函数来访问(写操作) 缓冲区,这些函数没有对访问的缓冲区的大小进行判断。由于在C语言中,字符串以0字节来标识结尾,其中没有字符串的长度信息,所以几个没有判断字符串长度的字符串拷贝函数就是容易出现问题的函数。这些函数有: strcat()、strcpy()、sprintf()等。 3) 即使程序使用了上面所说的问题函数也不一定会出现溢出漏洞,漏洞发生的最后一个条件是程序员由于粗心,未检查用户输入数据的长度就将其直接复制到缓冲区中去。虽然这看起来是一件小事,很容易杜绝。可惜的是正因为有大量粗心的程序员的存在,使得溢出漏洞变得非常的普遍。 2.2 原理; 图1 堆栈缓冲区示意图 程序的堆栈是先进后出的一种数据结构,堆栈的生长方向适合内存相反的(如图1)。当调用一个函数时,首先是函数的参数逆序进栈,然后将eip里面的内容进栈作为函数的返回地址(ret),即函数调用结束后程序跳转的地址,接着保存现在程序的栈基指针(ebp),并将当前栈顶指针(esp)拷入ebp作为新的基地址.最后将esp减去一定数值用来为本地变量留出一定空间。缓存区往往就分配在这段空间中。

Windows栈溢出利用

Windows 栈溢出分析

摘要 众所周知,缓冲区溢出是目前最为常见的漏洞利用方式,特别是栈溢出,原理简单,危害大。在Windows xp sp2以后,微软增加了许多安全检查措施来杜绝缓冲区溢出的发生。本文介绍两种Windows xp下两种常见的栈溢出利用方式,重点分析利用S.E.H进行栈溢出,并且归纳总结防范和检测方法。

第一章绪论 1.1 栈溢出定义 程序的局部变量一般都存放在栈空间内,如果用户输入的数据超过了定义的长度,就会非法覆盖栈空间的其他数据,这种现象就是栈溢出。 1.2栈溢出普通利用方式 1.2.1 利用函数返回点 函数调用约定描述了函数传递参数方式和栈协同工作的技术细节。不同的操作系统,不同的语言,不同的编译器在实现函数调用时的原理虽然基本相同,但具体的调用约定还是有差别的,包括参数传递方式,参数入栈顺序是从右向左还是从左向右,函数返回时候恢复堆栈平衡的操作在子函数进行还是在母函数中进行。下表列出了几种调用方式。 对于Visual C++,可支持以下三种函数调用约定,如下表 默认情况下,VC使用_stdcall的调用方式。本文以下讨论如不另加说明,即指这种默认的调用方式。 函数调用大致包括以下几个步骤: (1)参数入栈:将参数从右向左依次压入系统栈中; (2)返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行; (3)代码区跳转:处理器从当前代码区跳转到被调函数的入口地址; (4)栈帧调整,包括保存当前栈帧状态值,已备后面恢复本栈帧时使用。将当前栈帧切换到新栈帧。给新栈帧分配空间。 对于_stdcall调用约定,函数调用时用到的汇编指令序列如下:

关于堆栈溢出

堆栈溢出实验 原理: 堆栈是一种数据结构,物理上是一段连续分配的内存空间。当我们在一个程序中声明各种变量时,静态全局变量将位于数据段并且在程序开始运行的时候被加载,而程序的动态局部变量则分配在堆栈里面。 在堆栈的分配中,在地址上其从高向低分配空间,并且遵循“后进先出”的原则。堆栈涉及进栈和出栈的操作,堆栈的栈顶位置由寄存器ESP指定,进栈时,ESP=ESP-4,同时在ESP处存放需要压入堆栈的数据;出栈时,ESP=ESP+4,原来的栈顶数据将不再属于堆栈的范围。 当程序在进行函数调用时,往往是先通过push指令压入参数,然后通过call指令来调用相关具体函数。对于一般的函数来说,如果函数有局部变量,接下来,就在堆栈中开辟相应的空间以构造变量。函数执行结束,这些局部变量的内容将被丢失,但是不清除。在函数返回的时候,弹出ESP,恢复堆栈到函数的调用地址,弹出返回地址到EIP,恢复堆栈到函数调用的地址,弹出返回地址到EIP以继续执行程序。 常见利用方式: 一、利用JMP ESP的方式 其利用格式是NNNNNNRSSSSS,这里N=NOP,R=RET(jmp esp的地址),S=ShellCode。就是把缓冲区一直覆盖成NOP(空指令,什么都不做),直到原来的EIP位置时,我们填入系统中某个核心dll中的jmp esp的地址,紧跟后面才是我们的ShellCode。 正常情况下,函数返回时,执行RET指令,这等于POP EIP,会把保存的原来程序的EIP的值恢复,从而完成中断的返回。但在这里,我们把保存的EIP 的值覆盖了,改写成了jmp esp的地址。这样,POP EIP后,EIP = jmp esp的地址,而堆栈指针ESP会往下走,指向ShellCode的开始。程序继续执行,此时EIP里的内容是jmp esp,系统执行jmp esp,就正好就跳到我们的ShellCode的地方了. 如果ShellCode是开个端口,那我们就可以远程连上去;如果ShellCode是下载执行,那我们就可以让目标机在网页上下个文件并执行……只要你想到达的功能,都可以想办法实现。 二、利用JMP EBX的方式 其利用格式是NNNNN JESSSSSS。这里N = NOP, J = Jmp 04,E = jmp ebx 的地址,S = ShellCode。 这里的J和E的位置是关键,E是在出错处理的入口位置,而J在其前面。 在第一种方式中,我们知道将返回地址覆盖成另一个地址。但如果是个无效的地址呢?那里指向的数据或许不能读,或许不能执行,那会怎么样呢?其实相信大家都遇到过,那就是系统会弹出个对话框报错,我们点确定,就会终止运行。 这是因为作为一个系统级的程序,内部有健全的出错处理机制。简单的说,如果运行时有错误产生,windows就会跳到一个专门处理错误的地方,对应不同的错误,执行不同的代码。上面执行的代码就是弹出个对话框报错。 所以这里我们故意把返回的地址覆盖成一个错误的地址。这样出错时,

栈溢出和死循环原理

题目: ?main () ?{ ?int a[10]; ?int i; ?for (i = 0; i <= 10; i++ ){ ?a[i] = 1; ?} ?} 该代码在什么情况下有什么问题(2种情况)? 答案: 在栈空间变量按地址递增方式分配的情况下,陷入死循环。 在栈空间变量按地址递减方式分配的情况下,堆栈溢出 预备知识: 什么是堆栈? ~~~~~~~~~~~~~ 堆栈是一个在计算机科学中经常使用的抽象数据类型. 堆栈中的物体具有一个特性:最后一个放入堆栈中的物体总是被最先拿出来, 这个特性通常称为后进先处(LIFO)队列. 堆栈中定义了一些操作. 两个最重要的是PUSH和POP. PUSH操作在堆栈的顶部加入一个元素. POP操作相反, 在堆栈顶部移去一个元素, 并将堆栈的大小减一. 为什么使用堆栈? ~~~~~~~~~~~~~~~~

现代计算机被设计成能够理解人们头脑中的高级语言. 在使用高级语言构造程序时最重要的技术是过程(procedure)和函数(function). 从这一点来看, 一个过程调用可 以象跳转(jump)命令那样改变程序的控制流程, 但是与跳转不同的是, 当工作完成时,函数把控制权返回给调用之后的语句或指令. 这种高级抽象实现起来要靠堆栈的帮助. 堆栈也用于给函数中使用的局部变量动态分配空间, 同样给函数传递参数和函数返回值也要用到堆栈. 堆栈区域 ~~~~~~~~~~ 堆栈是一块保存数据的连续内存. 一个名为堆栈指针(SP)的寄存器指向堆栈的顶部.堆栈的底部在一个固定的地址. 堆栈的大小在运行时由内核动态地调整. CPU实现指令 PUSH和POP, 向堆栈中添加元素和从中移去元素. 堆栈由逻辑堆栈帧组成. 当调用函数时逻辑堆栈帧被压入栈中, 当函数返回时逻辑堆栈帧被从栈中弹出. 堆栈帧包括函数的参数, 函数地局部变量, 以及恢复前一个堆栈 帧所需要的数据, 其中包括在函数调用时指令指针(IP)的值. 堆栈既可以向下增长(向内存低地址)也可以向上增长, 这依赖于具体的实现. 在我们的例子中, 堆栈是向下增长的. 这是很多计算机的实现方式, 包括Intel, Motorola, SPARC和MIPS处理器. 堆栈指针(SP)也是依赖于具体实现的. 它可以指向堆栈的最后地址,或者指向堆栈之后的下一个空闲可用地址. 在我们的讨论当中, SP 指向堆栈的最后地址. 除了堆栈指针(SP指向堆栈顶部的的低地址)之外, 为了使用方便还有指向帧内固定地址的指针叫做帧指针(FP). 有些文章把它叫做局部基指针(LB-local base pointer). 从理论上来说, 局部变量可以用SP加偏移量来引用. 然而, 当有字被压栈和出栈后, 这些偏移量就变了. 尽管在某些情况下编译器能够跟踪栈中的字操作, 由此可以修正偏移

如何解决Sybase数据库堆栈溢出导致的异常

如何解决Sybase数据库堆栈溢出导致的异常 (v 1.0)

版本说明

目录 版本说明 (2) 故障现象: (4) 故障原因: (4) 处理方法: (4)

故障现象: SYBASE数据库异常退出,重新启动失败,访问不了数据库。查看数据库日志,出现如下系统日志:00:00000:00000:2004/10/13 23:30:00.75 kernel Stack overflow detected: limit: 0xf8446ab0, sp: 0xf845275c 00:00000:00000:2004/10/13 23:30:00.75 kernel *** Stack guardword corrupted. 00:00000:00000:2004/10/13 23:30:00.77 kernel pc: 0x006654d0 pcstkwalk+0x24(0xf8452688, 0x00000000, 0x0000270f, 0x00000002, 0xfffffff8) 00:00000:00000:2004/10/13 23:30:00.78 kernel pc: 0x006653dc ucstkgentrace+0x194(0x00040004, 0x00000000, 0x00000000, 0xf8eff590, 0x00000000) 00:00000:00000:2004/10/13 23:30:00.78 kernel pc: 0x00632300 ucbacktrace+0xa8(0xf8eff590, 0x00000001, 0x00040004, 0x00000008, 0xf845275c) 故障原因: SYBASE数据库堆栈溢出,可能是某些很长的where子句、较长的选择列表、深层嵌套的存储过程在执行时导致原来配置的堆栈大小不够用导致,需要修改堆栈大小。 处理方法: 方法一: *********************************************************************** use master go sp_configure stack go 会显示如信息: Parameter Name Default Memory Used Config Value Run Value -------------- ------- ----------- ------------ --------- esp execution stacksize 34816 0 34816 34816 stack guard size 4096 #908 4096 4096 stack size 46080 #10216 46080 46080 *********************************************************************** 注意记下上述结果中 stack size 对应的Default值(红色字体标注),用下面的命令扩大为现在的2倍。 sp_configure 'stack size', 92160

相关主题
文本预览
相关文档 最新文档