如何检查超出了哪个限制? (进程因 ulimit 而终止。)

如何检查超出了哪个限制? (进程因 ulimit 而终止。)

让我们假设进程在 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 限制时接收)。除非程序写得非常好,否则它可能会随机失败。

简而言之,一般来说,失败要么与其他进程死亡原因没有明显不同,所以你不能确定,要么可以完全从程序中处理,在这种情况下,它决定是否/何时/如何进行,而不是你从外部。

据我所知,你能做的最好的事情就是编写一些代码来分叉你的程序,等待它,然后:

  • 检查退出状态以检测SIGXCPUSIGXFSZAFAIK,这些信号只会由操作系统针对资源限制问题生成)。根据您的具体需求,您可以假设SIGKILLSIGSEGV也与资源限制有关,但这有点牵强。
  • 看看你可以从getrusage(RUSAGE_CHILDREN,...)你的实现中得到什么,以获得关于其他实现的提示。

特定于操作系统的工具可能可以在这里提供帮助(可能是ptraceLinux 或 Solaris 上的东西dtrace),或者可能是调试器类型的技术,但这将与您的特定实现更加相关。


(我希望其他人能回答我完全不知道的一些神奇的事情。)

答案2

我目前正在针对同一问题做一些工作。我已经能够部分解决它。我用过审计子系统。您可以在 [1] 中跟踪工作。

[1]https://github.com/PaulDaviesC/Logging-limits.conf

相关内容