让我们假设进程在 ulimited 环境中运行:
(
ulimit ... -v ... -t ... -x 0 ...
./program
)
程序终止。
原因可能有很多:超出内存/时间/文件限制;只是简单的段错误;甚至正常终止并返回代码 0。
如何在不修改程序的情况下检查程序终止的原因?
PS我的意思是“当给出二进制时”。也许一些包装器(ptrace-ing 等)可能有帮助?
答案1
一般来说,不幸的是我认为你不能。 (某些操作系统可能会提供此功能,但我不知道哪些操作系统支持此功能。)
资源限制参考文档:getrlimit
来自 POSIX 2008。
以CPU限制为例RLIMIT_CPU
。
- 如果进程超出软限制,则会发送
SIGXCPU
- 如果进程超出硬限制,则会得到一个简单的
SIGKILL
如果你可以wait()
在你的程序上,你可以判断它是否被杀死SIGXCPU
。但你无法区分SIGKILL
因违反硬限制而被派遣的行为与来自外部的普通旧杀戮。更重要的是,如果程序处理XCPU
,您甚至不会从外部看到它。
同样的事情对于RLIMIT_FSIZE
.如果程序不处理它,您可以SIGXFSZ
从状态中看到。wait()
但是,一旦超过文件大小限制,唯一发生的事情是尝试再次测试该限制的进一步 I/O 将简单地接收EFBIG
- 这将由程序内部处理(或者不幸的是不处理)。如果程序处理SIGXFSZ
,与上面相同 - 你不会知道它。
RLIMIT_NOFILE
?好吧,你甚至没有收到信号。open
和朋友们回到EMFILE
节目中。它不会受到其他干扰,因此无论在这种情况下以何种方式编码失败,它都会失败(或不失败)。
RLIMIT_STACK
?好老了SIGSEGV
,无法与其他原因的分数区分开来。 (从状态来看,你会知道这就是杀死进程的原因wait
。)
RLIMIT_AS
并且RLIMIT_DATA
只会使malloc()
和其他一些开始失败(或者SIGSEGV
在尝试在 Linux 上扩展堆栈时达到 AS 限制时接收)。除非程序写得非常好,否则它可能会随机失败。
简而言之,一般来说,失败要么与其他进程死亡原因没有明显不同,所以你不能确定,要么可以完全从程序中处理,在这种情况下,它决定是否/何时/如何进行,而不是你从外部。
据我所知,你能做的最好的事情就是编写一些代码来分叉你的程序,等待它,然后:
- 检查退出状态以检测
SIGXCPU
(SIGXFSZ
AFAIK,这些信号只会由操作系统针对资源限制问题生成)。根据您的具体需求,您可以假设SIGKILL
和SIGSEGV
也与资源限制有关,但这有点牵强。 - 看看你可以从
getrusage(RUSAGE_CHILDREN,...)
你的实现中得到什么,以获得关于其他实现的提示。
特定于操作系统的工具可能可以在这里提供帮助(可能是ptrace
Linux 或 Solaris 上的东西dtrace
),或者可能是调试器类型的技术,但这将与您的特定实现更加相关。
(我希望其他人能回答我完全不知道的一些神奇的事情。)
答案2
我目前正在针对同一问题做一些工作。我已经能够部分解决它。我用过审计子系统。您可以在 [1] 中跟踪工作。