好吧,我昨天问了Stackoverflow和bufferoverflow之间的区别,几乎被投票遗忘,没有新的信息.
所以它让我思考,我决定重新解释我的问题,希望得到答复,这实际上解决了我的问题.
所以这里什么都没有.
我知道有四个内存段(如果我错了,请纠正我).代码,数据,堆栈和堆.现在AFAIK代码段存储代码,而数据段存储与程序相关的数据.让我严重困惑的是堆栈和堆的目的!
根据我的理解,当你运行一个函数时,函数的所有相关数据都存储在堆栈中,当你递归调用函数内部的函数时,函数内部...当函数在输出上等待时在上一个函数中,函数及其必要的数据不会从堆栈中弹出.所以最终会出现堆栈溢出.(如果我错了,请再次纠正我)
我也知道堆的用途.正如我在某处所读到的,它用于在程序执行时动态分配数据.但这提出了更多解决我问题的问题.我最初在代码中初始化变量时会发生什么..它们是在代码段中还是在数据段中还是在堆中?数组存储在哪里?是在我的代码执行后,我的堆中的所有内容都被删除了吗?总而言之,请以更简单的方式告诉我有关堆的问题,请参阅malloc和alloc,因为我不确定我完全理解这些术语是什么!
我希望人们在回答这些问题时不要迷失在技术性方面,并且可以让这些术语变得简单,以便外行人理解(即使所描述的概念不是非常流行),并且随着我们的进展继续教育我们技术术语.我也希望这不是一个太大的问题,因为我认真地认为他们不能单独询问!
什么是堆栈?
每个程序都由函数/子程序/任何您选择的语言调用它们组成.几乎总是,这些功能有一些本地状态.即使在一个简单的for循环中,你需要在某个地方跟踪循环计数器,对吧?那必须存储在某个地方的内存中.
关于函数的事情是,他们几乎总是做的另一件事是调用其他函数.那些其他函数有自己的本地状态 - 它们的局部变量.您不希望本地变量干扰调用者中的本地变量.另一件必须发生的事情是,当FunctionA调用FunctionB然后必须执行其他操作时,您希望FunctionA中的局部变量仍然存在,并且在完成FunctionB时具有相同的值.
跟踪这些局部变量是堆栈的用途.每个函数调用都是通过设置所谓的堆栈帧来完成的.堆栈帧通常包括调用者的返回地址(对于函数完成时),任何方法参数的值以及任何局部变量的存储.
当调用第二个函数时,会创建一个新的堆栈帧,将其推送到堆栈的顶部,然后发生调用.新功能可以很好地消除它的堆栈帧.当第二个函数返回时,它的堆栈框架被弹出(从堆栈中移除),并且调用者的框架就像以前一样回到原位.
这就是堆栈.那堆是什么?它有类似的用途 - 存储数据的地方.但是,通常需要比单个堆栈帧更长寿的数据.它不能进入堆栈,因为当函数调用返回时,它的堆栈框架被清理并且繁荣 - 那里有你的数据.所以你把它放在堆上.堆是一个基本上非结构化的内存块.你要求x个字节,然后你就可以得到它,然后可以派对它.在C/C++中,堆内存保持分配状态,直到您显式解除分配.在垃圾收集语言(Java/C#/ Python /等)中,当内存上的对象不再使用时,将释放堆内存.
从上面解决您的具体问题:
堆栈溢出和缓冲区溢出之间有什么不同?
它们都是超过内存限制的情况.堆栈溢出特定于堆栈; 你已经编写了代码(递归是常见的,但不是唯一的原因),因此它有太多的嵌套函数调用,或者你在堆栈中存储了很多大的东西,并且它的空间不足.大多数操作系统都限制了堆栈可以达到的最大大小,当你达到这个限制时,你会得到堆栈溢出.现代硬件可以检测到堆栈溢出,并且通常会使您的进程崩溃.
缓冲区溢出有点不同.所以第一个问题 - 什么是缓冲?嗯,这是一个有限的记忆块.该内存可以在堆上,也可以在堆栈上.但重要的是你有X字节,你知道你有权访问.然后编写一些代码,将X +更多字节写入该空间.编译器可能已经将缓冲区之外的空间用于其他事情,并且通过编写太多,你已经覆盖了其他东西.缓冲区溢出通常不会立即显示,因为在尝试对已被删除的其他内存执行某些操作之前,您不会注意到它们.
还记得我提到过返回地址也存储在堆栈中吗?由于缓冲区溢出,这是许多安全问题的根源.您的代码使用堆栈上的缓冲区并具有溢出漏洞.一个聪明的黑客可以构造溢出缓冲区的数据来覆盖该返回地址,指向缓冲区本身的代码,这就是它们如何获得执行代码.这很讨厌.
我最初在代码中初始化变量时会发生什么..它们是在代码段中还是在数据段中还是在堆中?
我将在这里谈谈C/C++的观点.假设你有一个变量声明:
int i;
这保留了(通常)堆栈上的四个字节.相反,你有:
char*buffer = malloc(100);
这实际上保留了两块内存.对malloc的调用在堆上分配100个字节.但是你还需要存储指针,缓冲区.该存储再次位于堆栈上,而在32位机器上将是4个字节(64位机器将使用8个字节).
数组存储在哪里...... ???
这取决于你如何声明它们.如果你做一个简单的数组:
char str [128];
例如,它将在堆栈上保留128个字节.除非你通过调用像malloc这样的分配方法明确地要求它,否则C永远不会到达堆.
如果您声明一个指针(如上面的缓冲区),则指针的存储位于堆栈上,该数组的实际数据位于堆上.
是在我的代码执行后,我的堆中的所有内容都被删除了...... ???
基本上,是的.操作系统将在进程退出后清理进程使用的内存.堆是您进程中的一块内存,因此操作系统将清理它.虽然这取决于你的意思是"清理它".操作系统将这些RAM块标记为现在可用,稍后将重复使用.如果你有明确的清理代码(比如C++析构函数),你需要确保调用它们,操作系统不会为你调用它们.
总而言之,请以更简单的方式告诉我堆栈,而不仅仅是malloc和alloc?
堆就像它的名字一样,是一堆免费字节,你可以一次抓取一块,做任何你想要的东西,然后扔回去用于别的东西.你通过调用malloc来获取一大块字节,然后通过调用free来将其丢回.
你为什么要这样做?嗯,有几个常见的原因:
在运行时(例如,基于用户输入),您不知道需要多少事情.因此,您可以根据需要在堆上动态分配.
您需要大型数据结构.例如,在Windows上,线程的堆栈默认限制为1 meg.例如,如果您正在处理大型位图,那么这将是一种快速的方法来炸毁堆栈并获得堆栈溢出.所以你抓住堆的空间,这通常比堆栈大得多.
代码,数据,堆栈和堆?
这不是一个问题,但我想澄清一下."代码"段包含应用程序的可执行字节.通常,代码段在内存中是只读的,以帮助防止篡改.数据段包含编译到代码中的常量 - 代码中的字符串或数组初始化程序之类的东西需要存储在某个地方,数据段就是它们的位置.同样,数据段通常是只读的.
堆栈是可写的内存部分,通常具有有限的大小.操作系统将初始化堆栈,C启动代码会为您调用main()函数.堆也是可写的内存部分.它由操作系统保留,并且像malloc和free管理功能可以从中获取块并将它们放回原处.
那就是概述.我希望这有帮助.