You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

fclose()在Docker容器中触发Segmentation Fault求助排查

问题:fclose()在Docker容器中触发段错误,本地运行正常

问题背景

这段C程序用于创建指定长度的空文件,在本地Ubuntu 20.04笔记本上运行正常,但在DigitalOcean的Ubuntu 22.04实例的Docker容器中执行时,fclose(outfile);行触发Segmentation Fault。文件已成功创建并最终关闭——关闭前大小显示为0,关闭后呈现指定的4GB长度,且已排除文件指针为空的常规触发情况。

GDB段错误详情

Program received signal SIGSEGV, Segmentation fault.
0x00007fe121321c70 in __GI__IO_setb (f=f@entry=0x145b210, b=b@entry=0x0, eb=eb@entry=0x0, a=a@entry=0) at ./libio/genops.c:338
338     ./libio/genops.c: No such file or directory.

相关代码

#include <stdio.h>
#include <string.h>
#include <errno.h>

size_t create_empty_file (char * out_fname, size_t file_size)
{
    FILE *outfile;
    char buf[1024];

    outfile = fopen(out_fname, "wb+");

    if (outfile == NULL) {
        strcpy(buf, strerror(errno));
        printf("%d --> %s\n", errno, buf); }

    fseek(outfile, file_size, SEEK_SET);

    if (errno != 0) {
        strcpy(buf, strerror(errno));
        printf("%d --> %s\n", errno, buf); }

    fputc('\0', outfile);

    if (errno != 0) {
        strcpy(buf, strerror(errno));
        printf("%d --> %s\n", errno, buf); }

    fclose( outfile );

    return 0;
}

排查解决思路

  • 修复错误检查逻辑:当前代码存在严重未定义行为隐患——如果fopen失败,outfile是空指针,但后续仍会执行fseek、fputc、fclose,直接操作空指针必然触发异常。另外,依赖errno判断fseek、fputc的错误不可靠:errno不会自动清零,之前的操作可能残留错误值,且这些函数本身有明确返回值(fseek返回非0表示失败,fputc返回EOF表示失败),应优先用返回值判断。修改后的错误检查逻辑:
    outfile = fopen(out_fname, "wb+");
    if (outfile == NULL) {
        snprintf(buf, sizeof(buf), "%d --> %s\n", errno, strerror(errno));
        fputs(buf, stderr);
        return -1; // 失败直接返回,避免后续操作空指针
    }
    
    if (fseek(outfile, file_size, SEEK_SET) != 0) {
        snprintf(buf, sizeof(buf), "%d --> %s\n", errno, strerror(errno));
        fputs(buf, stderr);
        fclose(outfile);
        return -1;
    }
    
    if (fputc('\0', outfile) == EOF) {
        snprintf(buf, sizeof(buf), "%d --> %s\n", errno, strerror(errno));
        fputs(buf, stderr);
        fclose(outfile);
        return -1;
    }
    
  • 替换strcpy为snprintf:strcpy没有长度限制,若strerror返回的错误信息超过buf的1024字节长度,会触发缓冲区溢出,破坏栈上的FILE*指针或其他数据,最终在fclose时引发段错误。用snprintf可以严格控制写入长度,避免溢出。
  • 检查Docker容器的文件系统限制:创建4GB文件时,需确认容器挂载目录的磁盘空间是否充足、是否有配额限制,同时检查文件系统类型是否支持大文件(比如部分老旧的overlay版本可能存在兼容性问题)。可在容器内执行df -h查看磁盘使用情况,stat -f -c %T /path/to/target查看文件系统类型。
  • 验证libc版本兼容性:Ubuntu 20.04(glibc 2.31)和22.04(glibc 2.35)的libc版本差异较大,Docker容器内的libc可能与宿主机存在兼容性问题。可尝试用静态编译方式构建程序(gcc -static your_program.c -o your_program),避免依赖宿主机的动态libc库。
  • 确认文件指针未被篡改:在fclose前添加printf("outfile address: %p\n", outfile);,打印文件指针地址,确认它没有被之前的缓冲区溢出等操作篡改。

内容的提问来源于stack exchange,提问作者RTC222

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 08:25:19