❝翻译自 《SIGSEGV: Segmentation fault in Linux containers (exit code 139)》 原文链接:https://komodor.com/learn/
SIGSEGV
-segmentation-faults-signal-11-exit-code-139/ ❞
SIGSEGV
,也称为分段违规或分段错误,是基于 Unix 的操作系统(如 Linux)使用的信号。它表示程序尝试在其分配的内存之外进行写入或读取,由于编程错误、软件或硬件兼容性问题或恶意攻击(例如缓冲区溢出)。
SIGSEGV
由以下代码表示:
SIGSEGV
是操作系统信号 11SIGSEGV
错误而终止时,它会抛出退出码 139SIGSEGV
的默认操作是进程异常终止。此外,还可能发生以下情况:
SIGSEGV
信号在日志中被记录地更加详细;SIGSEGV
是 Kubernetes 中容器终止的常见原因。但是,Kubernetes 不会直接触发 SIGSEGV
。要解决此问题,您需要调试有问题的容器或底层主机。
SIGSEGV
和 SIGABRT
是两个可以导致进程终止的 Unix 信号。
SIGSEGV
由操作系统触发,它检测到一个进程存在内存违规,可能因此终止它。SIGABRT
(信号中止)是由进程本身触发的信号。它异常终止进程,关闭并刷新打开的流。一旦被触发,就不能被进程阻塞(类似于SIGKILL
,不同的是SIGKILL
是由操作系统触发的)。
在发送 SIGABRT
信号之前,进程可以:
libc
库中的 abort()
函数,解锁 SIGABRT
信号。然后进程可以通过触发 SIGABRT
自行中止assert()
宏,如果断言为假,则使用 SIGABRT
中止程序。退出码 139 和 134 与 Docker 容器中的 SIGSEGV
和 SIGABRT
并行:
SIGSEGV
SIGABRT
并被异常终止现代通用计算系统包括内存管理单元 (MMU)。MMU 可以在 Linux 等操作系统中实现内存保护,防止不同进程访问或修改彼此的内存,除非通过严格控制的 API。这简化了故障排除并使进程更具弹性,因为它们被彼此隔离开来了。
当进程尝试使用 MMU 未分配给它的内存地址时,会发生 SIGSEGV
信号或分段错误。这可能由于三个常见原因而发生:
在基于 Unix 的操作系统上,默认情况下,SIGSEGV
信号将导致违规进程异常终止。
除了终止进程外,操作系统还可以生成 core 文件来辅助调试,也可以执行其他平台相关的操作。例如,在 Linux 上,您可以使用 grsecurity
实用程序详细记录 SIGSEGV
信号,以监控相关的安全风险,例如缓冲区溢出。
在 Linux 和 Windows 上,操作系统允许进程处理它们对分段错误的响应。例如,该程序可以收集堆栈跟踪信息,其中包含处理器寄存器值和分段错误中涉及的内存地址等信息。
segvcatch
就是一个例子,它是一个支持多个操作系统的 C++ 库,能够将分段错误和其他与硬件相关的异常转换为软件语言异常。这使得使用简单的 try/catch
代码处理“硬”错误成为可能,例如分段错误。这使得软件可以识别分段错误并在程序执行期间进行纠正。
在对分段错误进行故障排除或测试程序以避免这些错误时,可能需要故意引发分段违规以调查其影响。大多数操作系统都可以以这样一种方式处理 SIGSEGV
,即使发生分段错误,它们也允许程序运行,以便进行调查和记录。
SIGSEGV
故障与 Kubernetes 用户和管理员高度相关。容器由于分段违规而失败是很常见的。
但是,与 SIGTERM
和 SIGKILL
等其他信号不同,Kubernetes 不会直接触发 SIGSEGV
信号。相反,当容器被发现执行内存违规时,Kubernetes 节点上的主机可以触发 SIGSEGV
。然后容器终止,Kubernetes 检测到这一点,并可能根据 pod 配置尝试重新启动它。
当 Docker 容器被 SIGSEGV
信号终止时,它会抛出退出码 139。这可以表明:
要调试和解决容器上的 SIGSEGV
问题,请执行以下步骤:
SIGSEGV
错误在 kubelet 日志中如下所示:[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x1bdaed0]
docker pull [image-id]
为由 SIGSEGV
终止的容器拉取镜像。curl
或 vim
)。kubectl
执行到容器中。查看您是否可以复现 SIGSEGV
错误以确认导致问题的库。上述过程可以帮助您解决直接的 SIGSEGV
错误,但在许多情况下,故障排除可能会变得非常复杂,并且需要涉及多个组件的非线性调查。