检测堆栈耗尽与Sigsegv的其他来源

发布于 2025-02-06 09:21:14 字数 353 浏览 2 评论 0原文

在POSIX环境中,当一个过程耗尽其堆栈时,它会收到sigsegv信号。

就我而言,我的程序用手工编写的递归下降解析器来解析其输入,如果输入文件具有特别深度嵌套的语法结构(想想编程语言的语法和输入文件,则可以耗尽其堆栈像f(f(f(f(f(f(f(y。))))))))。

我的程序可以选择使用此类情况以增加堆栈尺寸运行它,但是我想处理sigsegv建议当sigsegv的原因时,建议用户使用该选项。 /代码>是堆栈耗尽。

是否有任何方法可以说该程序已收到sigsegv,因为这个原因而不是其他错误?

In POSIX environments, when a process exhausts its stack it receives a SIGSEGV signal.

In my case, my program parses its input with a hand-written recursively descent parser which can exhaust its stack if the input file has a particularly deeply nested grammatical structure (think of the grammar of a programming language and an input file with very deep nested calls like f(f(f(f(f(f(....))))))).

My program has an option to run it with an increased stack size for cases like this, but I would like to handle SIGSEGV to suggest the user to use that option when the cause of the SIGSEGV is stack exhaustion.

Is there any way to tell that the program has received a SIGSEGV because of this reason instead of any other bug?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

与之呼应 2025-02-13 09:21:14

有什么方法可以说该程序已经收到了一个sigsegv,因为这个原因而不是其他错误?

是的。

  1. main(Main()中记录当前的堆栈尺寸限制,使用 getrlimit rlimit_stack,...)。将其存储在某个全球。
  2. main()中记录局部变量的地址,将其存储在另一个全局中。
  3. 输入解析器时,请在那里的某些地方进行地址。
  4. 估计当前堆栈用法(char*)ptr_to_local_in_main-(char*)ptr_to_to_local_in_parser

如果当前的堆栈使用情况在(例如)限制的4-8KIB内,则您处于危险区域。那时,您可以:

  1. 放弃解析,告诉End-user增加堆栈,或
  2. 设置全局in_danger_zone flag,请通过sigsegv处理程序检查。

另外,您只需记录ptr_to_local_in_parser,在您的信号处理程序中查看ptr_to_to_local_in_ {main,parser}之间的delta是否足够大,以至于可能堆叠堆积。

在信号处理程序中,可以检查ucontext_t传递到其中,拆卸指令,弄清楚该指令是否操纵堆栈(例如push> pushcallmov 0x ...(%rsp)等)并做出更精确的确定,但是复杂性可能是可能不值得您获得的额外准确性方式。

Is there any way to tell that the program has received a SIGSEGV because of this reason instead of any other bug?

Yes.

  1. Record the current stack size limit in main(), using getrlimit(RLIMIT_STACK, ...). Store it in some global.
  2. Record an address of a local variable in main(), store it in another global.
  3. When entering parser, take an address of some local there.
  4. Estimate current stack usage as (char*)ptr_to_local_in_main - (char*)ptr_to_local_in_parser.

IFF the current stack usage is within (say) 4-8KiB of the limit, you are in the danger zone. At that point you could:

  1. Abandon the parse, tell end-user to increase stack, or
  2. Set a global in_danger_zone flag, to be checked by SIGSEGV handler.

Alternatively, you could just record ptr_to_local_in_parser, and in your signal handler see whether the delta between ptr_to_local_in_{main,parser} is large enough that stack overflow is likely.

It's possible in the signal handler to examine ucontext_t passed into it, disassemble the instruction, figure out whether that instruction manipulates the stack (e.g. PUSH, CALL, MOV 0x...(%RSP), etc.) and make a more precise determination, but the complexity is probably not worth the additional accuracy you would get this way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文