SIGSEGV 故障排除:Linux 容器中的分段错误(返回代码 139)
段错误”这个术语可能看起来很模糊,但从技术上讲,它是一种非常简单的现象。当一个进程试图读取或写入未经授权的内存位置时,就会收到 SIGSEGV 信号。通常,内核会终止该进程以防止内存损坏。这种行为可以通过在程序代码中显式处理该信号来修改。段错误之所以如此命名,是因为它们会破坏先前精心定义的内存分区顺序。数据段存储可在编译时确定的值,文本段包含程序指令,而堆段封装在运行时创建并动态分配的变量。实际生
大家好!我是大聪明-PLUS!

Linux 中使用的 SIGSEGV 信号表示正在运行的进程中出现段错误。当程序尝试访问尚未分配的内存时,就会发生段错误。这可能是由于代码中意外引入的错误或系统内的恶意活动引起的。SIGSEGV
信号发生在操作系统级别,但在 Docker 和Kubernetes等容器技术环境中也可能遇到。当容器终止并返回代码 139 时,这是因为它收到了 SIGSEGV 信号。操作系统会终止容器进程以防止内存损坏。
如果您的容器反复以返回代码终止,则调查段错误的原因非常重要。通常,这些痕迹会导致允许直接访问内存的语言的编程错误。如果此错误发生在运行第三方镜像的容器中,则可能是由于第三方软件中的错误或镜像与环境不兼容造成的。
本文将解释什么是 SIGSEGV 信号以及它如何影响在 Kubernetes 上运行的 Linux 容器。我还将解释如何调试应用程序中的分段错误,以及如果发生分段错误,该如何处理。
❯ 什么是分段错误?
“段错误” 这个术语可能看起来很模糊,但从技术上讲,它是一种非常简单的现象。当一个进程试图读取或写入未经授权的内存位置时,就会收到 SIGSEGV 信号。通常,内核会终止该进程以防止内存损坏。这种行为可以通过在程序代码中显式处理该信号来修改。
段错误之所以如此命名,是因为它们会破坏先前精心定义的内存分区顺序。数据段存储可在编译时确定的值,文本段包含程序指令,而堆段封装在运行时创建并动态分配的变量。
实际生活中遇到的大多数段错误都属于第三类。这些操作包括错误定义指针、尝试写入只读内存、越界数组访问以及尝试访问堆外的内存等。
以下是一个遇到段错误的 C 程序的简单示例:
int main() {
char *buffer;
buffer[0] = 0;
return 0;
}
让我们按原样保存程序hello-world.c并使用以下命令进行编译make:
$ make hello-world
现在让我们运行编译后的二进制文件:
$ ./hello-world
Segmentation fault (core dumped)
如你所见,程序立即终止并报告段错误。检查返回码,你会发现它是 139,表示出现了段错误:
$ echo $?
139
为什么会发生这种情况?程序创建了一个变量buffer,但未为其分配内存。赋值操作导致buffer[0] = 0写入未分配的内存。您可以通过确保缓冲区足够大以容纳所有必需的数据来修复该程序:
int main() {
char *buffer[1];
buffer[0] = 0;
return 0;
}
如果您分配一个buffer1字节的缓冲区,那么该内存肯定足够处理分配的值。该程序成功终止,返回代码为0。
❯ 容器中的分段错误
现在让我们考虑一下如果容器中发生段错误会发生什么。这是Dockerfile上面崩溃的应用程序的一个简单文件:
FROM alpine:latest
RUN apk install --upgrade build-base
COPY hello-world.c .
RUN make hello-world && mv hello-world /usr/bin/hello-world
CMD ["hello-world"]
让我们使用以下命令构建容器镜像:
$ docker build -t segfault:latest .
现在让我们运行容器:
$ docker run segfault:latest
容器将启动,执行命令,然后立即退出。使用docker ps-a 标志可检索有关已停止容器的详细信息:
$ docker ps -a
这里我们得到返回代码 139,因为应用程序遇到了分段错误。
❯ 调试 Kubernetes 中的分段错误
您还可以调试 Kubernetes 容器中的段错误。使用MicroK8s或K3s 之类的项目在您的机器上启动本地Kubernetes集群。接下来,使用您的镜像作为基础,创建一个运行该容器的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: segfault
spec:
containers:
- name: segfault
image: segfault:latest
使用kubectl向您的集群添加一个 pod:
$ kubectl apply -f pod.yaml
现在让我们取出吊舱部件:
$ kubectl get pod/segfault它不断崩溃并不断重启。我们将使用以下命令describe来找出问题所在:
$ kubectl describe pod/segfault
Name: segfault
Namespace: default
...
Containers:
segfault:
...
Last State: Terminated
Reason: Error
Exit Code: 139
在这种情况下,我们得到返回代码 139,这意味着容器内的应用程序遇到了分段错误,这就是导致容器崩溃的原因。
❯ 应对分割错误
一旦确认容器崩溃是由于分段错误导致的,您就可以开始调试并防止其再次发生。
如果错误发生在容器中包含的第三方镜像中,您的选择将非常有限。您可以报告问题,希望开发人员能够彻底调查意外内存访问的原因。如果问题出在您自己的代码中,您可以尝试调试特定区域以确定问题所在。
❯ 识别有问题的代码
首先,查找代码中可能存在分片问题的最明显区域。您可以检查容器日志来重建导致错误的事件序列:
$ docker logs my-container
$ kubectl logs pod/my-pod
根据容器中发生的情况自行确定错误来源。是数组访问、指针引用、不受保护的内存写入?还是其他问题?
❯ 与环境不兼容
此问题的另一个常见原因是共享库更新导致与现有二进制文件不兼容。如果加载的版本超出兼容范围,则可能导致内存访问冲突。
请尝试还原容器依赖项的所有最新更改。这可以消除由第三方库更新引起的问题。
极少数情况下,可能会发生无法解释的不可恢复的分段错误。在这种情况下,问题可能是由于硬件与特定计算机不兼容造成的。此类错误也可能是内存故障的症状。在 Kubernetes 集群中,此类问题不太可能发生。请尝试运行memtester来排除可能的硬件问题,这些问题可以通过正确组织硬件支持来解决。
❯ 有针对性的调试
Linux 有一些工具可以让你专门调试 SIGSEGV 信号。任何分段错误都会反映在内核日志消息中。由于容器在主机内核中以进程的形式运行,因此即使错误发生在容器内部,这些消息也会显示出来。
要检查系统日志,只需查看以下内容/var/log/syslog:
$ sudo tail -f /var/log/syslog
此命令将向控制台输出连续的日志流,直到您使用 Ctrl+C 取消操作。现在尝试重现导致分段错误的事件。SIGSEGV 信号在日志中将如下所示:
hello-world[2631584]: segfault at 7f4624c6cfe0 ip 000055730c3621ed sp 00007ffce90e35f0 error 7 in hello-world[55730c362000+1000]
您可以这样解读此日志:
at <_address_>:您的代码尝试访问的内存地址是非法的。ip <_pointer_>:有问题的代码在内存中的地址。sp <_pointer_>:本次操作的堆栈指针,从中我们可以了解程序在此堆栈上发出的最后一个请求的地址。error <_code_>:错误代码标识程序尝试的操作类型。常见代码包括:6(写入未分配区域);7(写入可读但不可写的区域);4(从未分配区域读取);以及 5(从只写区域读取)。
通过分析内核日志,您可以更好地了解错误发生时代码正在执行的操作。虽然无法从容器内部直接访问此日志,但如果您拥有主机的管理权限,仍然可以提取有关分段错误的详细信息。
❯ 优雅地处理分段错误
处理段错误的另一种方法是在代码中谨慎处理它们。您可以使用segvcatch之类的库来捕获 SIGSEGV 信号并将其转换为程序异常。然后,您可以像处理其他异常一样处理它们,例如,在您选择的错误监控平台上记录详细信息,并在不导致崩溃的情况下恢复。
虽然谨慎处理 SIGSEGV 是避免硬崩溃的好方法,但仍然建议您彻底调查并解决每个段错误实例。段错误表明您的程序正在执行 Linux 内核明确禁止的某些操作。这可能表明您的代码存在严重的安全性或可靠性问题。
简单地捕获并忽略此类信号可能会导致程序出现进一步的问题。这些问题通常涉及超出允许范围的读取或写入。
❯ 结论
当程序尝试使用未经授权访问的内存时,就会发生段错误。尝试将数据写入只读内存或反之亦然时,也可能发生段错误。本文演示了在代码中引入可能导致此类问题的错误是多么容易。我们还讨论了如何识别由容器崩溃引起的段错误,以及在程序中出现此类问题时如何调试此类错误。主动预防此类错误将确保您的应用程序可靠运行,几乎不会中断。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)