当前位置:  开发笔记 > 编程语言 > 正文

如何在ac/c ++程序中检测可能/潜在的堆栈溢出问题?

如何解决《如何在ac/c++程序中检测可能/潜在的堆栈溢出问题?》经验,为你挑选了5个好方法。

有没有一种标准的方法来查看您的应用程序有多少堆栈空间以及运行期间堆栈使用的最高水印?

另外在可怕的情况下实际溢出会发生什么?

它会崩溃,触发异常还是发出信号?是否有标准或在所有系统和编译器上有所不同?

我正在寻找专门针对Windows,Linux和Macintosh的.



1> jussij..:

Windows上,将生成堆栈溢出异常.

以下Windows代码说明了这一点:

#include 
#include 

void StackOverFlow()
{
  CONTEXT context;

  // we are interested control registers
  context.ContextFlags = CONTEXT_CONTROL;

  // get the details
  GetThreadContext(GetCurrentThread(), &context);

  // print the stack pointer
  printf("Esp: %X\n", context.Esp);

  // this will eventually overflow the stack
  StackOverFlow();
}

DWORD ExceptionFilter(EXCEPTION_POINTERS *pointers, DWORD dwException)
{
  return EXCEPTION_EXECUTE_HANDLER;
}

void main()
{
  CONTEXT context;

  // we are interested control registers
  context.ContextFlags = CONTEXT_CONTROL;

  // get the details
  GetThreadContext(GetCurrentThread(), &context);

  // print the stack pointer
  printf("Esp: %X\n", context.Esp);

  __try
  {
    // cause a stack overflow
    StackOverFlow();
  }
  __except(ExceptionFilter(GetExceptionInformation(), GetExceptionCode()))
  {
    printf("\n****** ExceptionFilter fired ******\n");
  }
}

运行此exe时,将生成以下输出:

Esp: 12FC4C
Esp: 12F96C
Esp: 12F68C
.....
Esp: 33D8C
Esp: 33AAC
Esp: 337CC

****** ExceptionFilter fired ******



2> adl..:

在Linux上,如果代码尝试写入堆栈,则会出现分段错误.

堆栈的大小是进程之间继承的属性.如果你可以阅读或修改它在使用类似的命令壳ulimit -s(中sh,ksh,zsh)或limit stacksize(tcsh,zsh).

从程序中,可以使用读取堆栈的大小

#include 
#include 

struct rlimit l;
getrlimit(RLIMIT_STACK, &l);
printf("stack_size = %d\n", l.rlim_cur);

我不知道获得可用堆栈大小的标准方法.

堆栈首先argc跟着argv环境的内容和副本,然后是你的变量.但是因为内核可以随机化堆栈起始位置,并且上面可能存在一些虚拟值argc,所以假设您在l.rlim_cur下面有可用字节是错误的&argc.

检索堆栈的确切位置的一种方法是查看文件/proc/1234/maps (1234程序的进程ID 在哪里).一旦了解了这些边界,就可以通过查看最新局部变量的地址来计算堆栈的使用量.



3> Kknd..:

gcc在"不安全"函数调用中的返回地址和正常变量之间放置了一个额外的内存块,就像(在这个例子中函数是void test(){char a [10]; b [20]}:

call stack:
-----------
return address
dummy
char b[10]
char a[20]

如果函数在指针'a'中写入36个字节,则溢出将"损坏"返回地址(可能的安全漏洞).但它也会改变'dummy'的值,即指针和返回地址之间的值,因此程序会崩溃并发出警告(你可以使用-fno-stack-protector禁用它)



4> Norman Ramse..:

在Linux上,Gnu libsigsegv库包含该函数stackoverflow_install_handler,该函数可以检测(并在某些情况下帮助您从中恢复)堆栈溢出.



5> deemok..:

在Windows上,堆栈(针对特定线程)按需增长,直到达到为此线程创建之前指定的堆栈大小.

按需增长是使用保护页面实现的,因为最初只有一个堆栈片段可用,然后是一个保护页面,当被命中时会触发异常 - 这个异常是特殊的,并由系统处理you - 处理增加了可用的堆栈空间(如果已达到限制,也会检查!)并重试读取操作.

一旦达到限制,就不再增长,导致堆栈溢出异常.当前堆栈基数和限制存储在线程环境块中,称为_NT_TIB(线程信息块).如果你有一个方便的调试器,这就是你看到的:

0:000> dt ntdll!_teb @$teb nttib.
   +0x000 NtTib  : 
      +0x000 ExceptionList : 0x0012e030 _EXCEPTION_REGISTRATION_RECORD
      +0x004 StackBase : 0x00130000 
      +0x008 StackLimit : 0x0011e000 
      +0x00c SubSystemTib : (null) 
      +0x010 FiberData : 0x00001e00 
      +0x010 Version : 0x1e00
      +0x014 ArbitraryUserPointer : (null) 
      +0x018 Self   : 0x7ffdf000 _NT_TIB

StackLimit属性将按需更新.如果检查此内存块上的属性,您将看到类似的内容:

0:000> !address 0x0011e000 
    00030000 : 0011e000 - 00012000
                    Type     00020000 MEM_PRIVATE
                    Protect  00000004 PAGE_READWRITE
                    State    00001000 MEM_COMMIT
                    Usage    RegionUsageStack
                    Pid.Tid  abc.560

检查旁边的页面会显示guard属性:

0:000> !address 0x0011e000-1000
    00030000 : 0011d000 - 00001000
                    Type     00020000 MEM_PRIVATE
                    Protect  00000104 PAGE_READWRITE | PAGE_GUARD
                    State    00001000 MEM_COMMIT
                    Usage    RegionUsageStack
                    Pid.Tid  abc.560

希望能帮助到你.

推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有