如何确定代码是否在信号处理程序上下文中运行?
我刚刚发现有人正在从信号处理程序调用我编写的绝对不是异步信号安全的函数。
所以,现在我很好奇:如何避免这种情况再次发生?我希望能够轻松确定我的代码是否在信号处理程序上下文中运行(语言是 C,但该解决方案不适用于任何语言吗?):
int myfunc( void ) {
if( in_signal_handler_context() ) { return(-1) }
// rest of function goes here
return( 0 );
}
这是在 Linux 下。 希望这不是一个简单的答案,否则我会觉得自己像个白痴。
I just found out that someone is calling - from a signal handler - a definitely not async-signal-safe function that I wrote.
So, now I'm curious: how to circumvent this situation from happening again? I'd like to be able to easily determine if my code is running in signal handler context (language is C, but wouldn't the solution apply to any language?):
int myfunc( void ) {
if( in_signal_handler_context() ) { return(-1) }
// rest of function goes here
return( 0 );
}
This is under Linux.
Hope this isn't an easy answer, or else I'll feel like an idiot.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
显然,较新的 Linux/x86(可能是从某些 2.6.x 内核开始)从
vdso
调用信号处理程序。您可以利用这一事实对毫无戒心的世界造成以下可怕的黑客攻击:SCNR。
Apparently, newer Linux/x86 (probably since some 2.6.x kernel) calls signal handlers from the
vdso
. You could use this fact to inflict the following horrible hack upon the unsuspecting world:SCNR.
如果我们可以假设您的应用程序不会使用 sigprocmask() 或 pthread_sigmask() 手动阻止信号,那么这非常简单:获取当前线程 ID (
tid
)。打开/proc/tid/status
并获取SigBlk
和SigCgt
的值。AND
这两个值。如果该AND
的结果非零,则该线程当前正在信号处理程序内部运行。我自己测试过这个并且有效。If we can assume your application doesn't manually block signals using
sigprocmask()
orpthread_sigmask()
, then this is pretty simple: get your current thread ID (tid
). Open/proc/tid/status
and get the values forSigBlk
andSigCgt
.AND
those two values. If the result of thatAND
is non-zero, then that thread is currently running from inside a signal handler. I've tested this myself and it works.有两种正确的方法可以解决此问题:
让您的同事停止做错误的事情。不过,祝你好运,和老板一起解决这个问题……
让你的函数可重入且异步安全。如有必要,请提供具有不同签名的函数(例如,使用广泛使用的
*_r
命名约定)以及状态保存所需的附加参数。至于执行此操作的非正确方法,在带有 GNU libc 的 Linux 上,您可以使用
backtrace()
和朋友可以查看函数的调用者列表。正确、安全或可移植并不容易,但可能会持续一段时间:在我看来,退出可能比被迫编写更好像这样的代码。
There are two proper ways to deal with this:
Have your co-workers stop doing the wrong thing. Good luck pulling this off with the boss, though...
Make your function re-entrant and async-safe. If necessary, provide a function with a different signature (e.g. using the widely-used
*_r
naming convention) with the additional arguments that are necessary for state preservation.As for the non-proper way to do this, on Linux with GNU libc you can use
backtrace()
and friends to go through the caller list of your function. It's not easy to get right, safe or portable, but it might do for a while:In my opinion, it might just be better to quit rather than be forced to write code like this.
您可以使用 sigaltstack 来解决一些问题。设置替代信号堆栈,以某种异步安全方式获取堆栈指针,如果在替代堆栈内继续,否则 abort()。
You could work out something using sigaltstack. Set up an alternative signal stack, get the stack pointer in some async-safe way, if within the alternative stack go on, otherwise abort().
我想你需要执行以下操作。这是一个复杂的解决方案,它不仅结合了编码的最佳实践,还结合了软件工程的最佳实践!
因此,所有信号处理程序都以
sighnd
开头,例如sighndInterrupt
。backtrace()
。signighd...
开头。如果是这样,那么恭喜你,你已经进入了信号处理程序!I guess you need to do the following. This is a complex solution, which combines the best practices not only from coding, but from software engineering as well!
So, all signal handlers will start with
sighnd
, likesighndInterrupt
.backtrace()
.sighnd...
. If it does, then congratulations, you're inside a signal handler!对于在 -O2 或更好(istr)优化的代码,发现需要添加 -fno-omit-frame-pointer
否则 gcc 将优化堆栈上下文信息
for code optimized at -O2 or better (istr) have found need to add -fno-omit-frame-pointer
else gcc will optimize out the stack context information