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

C语言读取Shader文件时fgets触发内存访问违例错误排查

解决Shader文件读取时的内存访问违例问题

错误信息:在Project-512.exe进程的ucrtbase.dll模块中,地址0x00007FFECFCBB16B处抛出异常:0xC0000005: 写入地址0xFFFFFFFFF9CF4880时发生内存访问违例。


核心问题分析

错误触发在readShader函数的while (fgets(str, fileSize, fpointer) != NULL)行,根源在于以下几个代码缺陷:

  • 缓冲区参数错误:fgets的第二个参数需包含字符串终止符\0的空间,你传入的fileSize是文件字节数,未预留终止符位置,导致写入越界。
  • 类型溢出风险:ftell返回long类型,用int存储fileSize会在大文件场景下溢出,分配的内存远小于实际需求。
  • 无效指针访问:fgets返回NULL时,str的内容未定义,后续printf("%s", str)会访问非法内存。
  • 内存泄漏与无效返回:分配的shaderCode未写入任何数据就返回,同时str的内存未释放,造成泄漏。
  • 双重释放问题:compileShaders中重复释放已被释放的shader源指针,触发未定义行为。

修复后的代码实现

修正后的readShader函数

static char* readShader(const char path[]) {
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        printf("Current working dir: %s\n", cwd);
    } else {
        perror("getcwd() error");
        return NULL;
    }

    char full_path[512];
    snprintf(full_path, sizeof(full_path), "%s/%s", cwd, path);
    FILE* fpointer = fopen(full_path, "rb"); // 二进制模式避免换行符转换问题
    if (fpointer == NULL) {
        fprintf(stderr, "ERROR: COULD NOT LOAD SHADER: %s\n", full_path);
        return NULL;
    }

    // 获取文件大小
    fseek(fpointer, 0, SEEK_END);
    long fileSize = ftell(fpointer);
    if (fileSize < 0) {
        fprintf(stderr, "ERROR: Failed to get file size\n");
        fclose(fpointer);
        return NULL;
    }
    rewind(fpointer);

    // 分配内存,预留终止符空间
    char* shaderCode = malloc(fileSize + 1);
    if (shaderCode == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        fclose(fpointer);
        return NULL;
    }

    // 一次性读取整个文件,避免逐行读取的边界问题
    size_t bytesRead = fread(shaderCode, 1, fileSize, fpointer);
    if (bytesRead != fileSize) {
        fprintf(stderr, "ERROR: Failed to read entire shader file\n");
        free(shaderCode);
        fclose(fpointer);
        return NULL;
    }
    // 添加字符串终止符
    shaderCode[fileSize] = '\0';

    printf("Shader loaded successfully. File size: %ld bytes\n", fileSize);
    printf("Shader content:\n%s\n", shaderCode);

    fclose(fpointer);
    return shaderCode;
}

其他必要修复

  1. 删除compileShaders中的重复释放:移除函数末尾的free(vertexShaderSource);和free(fragmentShaderSource);,这两个指针已在编译后释放。
  2. 统一文件大小类型:所有存储文件大小的变量改用long类型,避免溢出。
  3. 二进制模式打开文件:用"rb"模式读取,避免Windows下文本模式将\n转换为\r\n导致的大小计算偏差。

修复原理

  • 改用一次性读取整个文件的方式,彻底规避逐行读取的缓冲区边界问题,同时提升效率。
  • 确保内存分配预留字符串终止符空间,杜绝越界写入。
  • 二进制模式读取保证文件大小计算准确,避免换行符转换导致的内容长度不符。
  • 清理无效指针访问和重复释放操作,消除未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 01:44:57