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

Lua 5.1中自定义C版loadfile函数报错求助

问题排查:自定义Lua loadfile函数导致的EOF错误

问题场景

在Lua 5.1环境下,用C语言实现自定义loadfile函数替换原生函数后,运行测试Lua代码时出现错误:[string "custom_table":165: '<eof>' expected]。尝试在luaL_loadbuffer后调用lua_tostring,又因数据非字符串触发另一个错误。

相关代码

C实现代码

#include <stdio.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

static void panic(char* error)
{
  fprintf(stderr, "panic: %s\n", error);
  exit(1);
}

static int _custom_loadfile(lua_State* L)
{
  const char* rfile = luaL_checkstring(L, 1);
  FILE* rfile_fp = fopen(rfile, "r");
  if (rfile_fp == NULL) panic("failed to open rfile.");
  if (fseek(rfile_fp, 0, SEEK_END) != 0) panic("failed to seek to eof.");
  size_t buffersize = ftell(rfile_fp) + 1 * sizeof(char);
  char* buffer = (char*) malloc(buffersize);
  if (buffer == NULL) lua_error(L);
  if (fseek(rfile_fp, 0, SEEK_SET) != 0) panic("failed to seek to start.");
  if (fread(buffer, 1, buffersize, rfile_fp) != buffersize) panic("failed to read file");
  int error = luaL_loadbuffer(L, buffer, bufferfilesize, rfile);
  if (error) lua_error(...);
  return 1; // one value
}

// ... 省略其他代码

int main(int argc, char* argv[])
{
  lua_State* L = luaL_newstate();
  luaL_openlibs(L);

  lua_pushcfunction(L, _custom_loadfile);
  lua_setglobal(L, "loadfile");
  // ... 省略其他代码
}

Lua测试代码

example.lua

-- ... 省略其他代码
custom_table = loadfile('custom_table')
print(custom_table)
-- ... 省略其他代码

custom_table.lua

return {
  name = 'custom_table',
  other = 'lots of stuff',
  table = {},
}

错误原因分析

  • 未定义变量使用:调用luaL_loadbuffer时用了未声明的bufferfilesize,而非正确的buffersize,导致Lua读取字节数为随机值,超出文件实际长度触发EOF错误。
  • 字符串终止符缺失:计算buffersize时预留了终止符空间,但fread后未手动添加\0,Lua解析时可能读到垃圾数据。
  • 读取判断逻辑错误:文件实际大小为buffersize-1,fread最多读取buffersize-1字节,用!= buffersize判断会误判读取失败。
  • 资源未释放:打开文件后未调用fclose,存在资源泄漏;错误分支未释放已分配内存。
  • 错误处理不规范:lua_error(...)写法错误,未正确传入Lua状态机和错误信息。

修复后的代码

static int _custom_loadfile(lua_State* L)
{
  const char* rfile = luaL_checkstring(L, 1);
  // 用二进制模式打开,避免换行符转换导致的长度计算偏差
  FILE* rfile_fp = fopen(rfile, "rb"); 
  if (rfile_fp == NULL) {
    lua_pushfstring(L, "failed to open file: %s", rfile);
    lua_error(L);
  }

  if (fseek(rfile_fp, 0, SEEK_END) != 0) {
    fclose(rfile_fp);
    lua_pushstring(L, "failed to seek to eof");
    lua_error(L);
  }

  long file_size = ftell(rfile_fp);
  if (file_size < 0) {
    fclose(rfile_fp);
    lua_pushstring(L, "failed to get file size");
    lua_error(L);
  }

  size_t buffersize = (size_t)file_size + 1;
  char* buffer = (char*)malloc(buffersize);
  if (buffer == NULL) {
    fclose(rfile_fp);
    lua_pushstring(L, "failed to allocate memory");
    lua_error(L);
  }

  if (fseek(rfile_fp, 0, SEEK_SET) != 0) {
    fclose(rfile_fp);
    free(buffer);
    lua_pushstring(L, "failed to seek to start");
    lua_error(L);
  }

  size_t read_bytes = fread(buffer, 1, (size_t)file_size, rfile_fp);
  if (read_bytes != (size_t)file_size) {
    fclose(rfile_fp);
    free(buffer);
    lua_pushstring(L, "failed to read file");
    lua_error(L);
  }
  // 手动添加字符串终止符
  buffer[read_bytes] = '\0';

  // 传入实际文件长度,而非buffersize
  int error = luaL_loadbuffer(L, buffer, (size_t)file_size, rfile);
  // 及时释放资源
  fclose(rfile_fp);
  free(buffer);

  if (error) {
    lua_error(L);
  }

  return 1;
}

额外注意事项

  • 用二进制模式"rb"打开文件,避免跨系统换行符转换导致的文件长度计算错误。
  • 所有资源(文件指针、内存)在错误分支必须对应释放,防止泄漏。
  • luaL_loadbuffer的第三个参数是文件实际内容长度(不含终止符),无需传入buffersize。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:06:09