gpt4 book ai didi

memory - "stack overflow"是如何发生的,如何预防?

转载 作者:IT王子 更新时间:2023-10-28 23:28:20 25 4
gpt4 key购买 nike

堆栈溢出是如何发生的,确保它不会发生的最佳方法是什么,或者防止它发生的方法是什么,尤其是在 Web 服务器上,但其他示例也会很有趣?

最佳答案

堆栈

在这种情况下,堆栈是在程序运行时放置数据的后进先出缓冲区。后进先出 (LIFO) 意味着您放入的最后一个东西总是您取出的第一个东西 - 如果您将 2 个项目压入堆栈,“A”然后是“B”,那么您弹出的第一个东西堆栈外将是“B”,接下来是“A”。

当您在代码中调用函数时,函数调用之后的下一条指令将存储在堆栈中,以及可能被函数调用覆盖的任何存储空间。您调用的函数可能会为它自己的局部变量使用更多堆栈。当它完成时,它释放它使用的局部变量堆栈空间,然后返回到前一个函数。

堆栈溢出

堆栈溢出是指您为堆栈使用的内存比程序应该使用的内存多。在嵌入式系统中,您的堆栈可能只有 256 个字节,如果每个函数占用 32 个字节,那么您只能进行 8 个深度的函数调用 - 函数 1 调用函数 2 调用函数 3 调用函数 4 .... 谁调用函数 8 调用了函数 9,但函数 9 覆盖了堆栈外的内存。这可能会覆盖内存、代码等。

许多程序员通过调用函数 A,然后调用函数 B,然后调用函数 C,然后调用函数 A 来犯这个错误。它可能在大部分时间都有效,但只有一次错误的输入会导致它永远进入那个循环直到计算机识别出堆栈过度膨胀。

递归函数也是造成这种情况的一个原因,但如果您以递归方式编写(即您的函数调用自身),那么您需要注意这一点并使用静态/全局变量来防止无限递归。

通常,您使用的操作系统和编程语言管理堆栈,它不在您的掌控之中。您应该查看您的调用图(一个树结构,从您的主程序中显示每个函数调用的内容)以了解您的函数调用的深度,并检测非预期的循环和递归。故意循环和递归需要人为检查,如果它们相互调用太多次就会出错。

除了良好的编程实践、静态和动态测试之外,在这些高级系统上您无能为力。

嵌入式系统

在嵌入式世界中,尤其是在高可靠性代码(汽车、飞机、航天)中,您需要进行大量的代码审查和检查,但您还需要执行以下操作:

  • 禁止递归和循环 - 由策略和测试强制执行
  • 保持代码和堆栈远离(闪存中的代码,RAM 中的堆栈,并且永远不会相遇)
  • 在堆栈周围放置保护带 - 您用魔数(Magic Number)填充的空白内存区域(通常是软件中断指令,但这里有很多选项),并且每秒查看数百或数千次保护带以确保他们没有被覆盖。
  • 使用内存保护(即,不在堆栈上执行,不在堆栈外读取或写入)
  • 中断不调用次要函数——它们设置标志、复制数据,并让应用程序负责处理它(否则你可能在函数调用树中得到 8 个深度,有一个中断,然后在中断,导致井喷)。您有多个调用树 - 一个用于主进程,一个用于每个中断。如果你的打断可以互相打断……好吧,有龙……

  • 高级语言和系统

    但是在操作系统上运行的高级语言中:
  • 减少你的局部变量存储(局部变量存储在堆栈上——尽管编译器对此非常聪明,如果你的调用树很浅,有时会将大局部变量放在堆上)
  • 避免或严格限制递归
  • 不要将你的程序分解成越来越小的函数——即使不计算局部变量,每个函数调用在堆栈上消耗多达 64 个字节(32 位处理器,节省一半的 CPU 寄存器、标志等)
  • 保持你的调用树浅(类似于上面的语句)

  • 网络服务器

    这取决于您是否可以控制甚至查看堆栈的“沙箱”。很有可能您可以像对待任何其他高级语言和操作系统一样对待 Web 服务器 - 这在很大程度上是您无法掌控的,但请检查您正在使用的语言和服务器堆栈。它 例如,可能会炸毁 SQL 服务器上的堆栈。

    -亚当

    关于memory - "stack overflow"是如何发生的,如何预防?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26158/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com