gcc 从Lua调用C函数时出现分段错误

pbwdgjma  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(121)

今天下午,我在CentOS7中重新编译了服务器,然后当我启动CentOS7时,我看到进程已被挂起。lua5.1 Static库在CentOS6中编译。CentOS6的gcc版本是4.4.7,CentOS7的gcc版本是4.8.5。然后使用gdb和gdb show进行调试:

Breakpoint 4, SGPlatformActMgr::InitDBFromConf (L=0x7fffe577901c) at gamelogic/bg/SGPlatformActMgr.cpp:454
454     ERROR_LOG("astActInfo count:%d InitActDB begin\n" , astActInfo.GetCount());
(gdb) l
449         astActInfo.Add(stActInfo);
450 
451         lua_pop(L, 1);
452     }
453 
454     ERROR_LOG("astActInfo count:%d InitActDB begin\n" , astActInfo.GetCount());
455     iRet = InitActDB(L, astActInfo);
456     if (iRet)
457     {
458         ERROR_LOG("InitActDB failed:%d\n", iRet);
(gdb) n
455     iRet = InitActDB(L, astActInfo);
(gdb) p L
$2 = (lua_State *) 0x7fffe577901c
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x000000000056b0fa in InitActDB (L=<error reading variable: Cannot access memory at address 0x7fffff5e4a48>, 
    astActInfo=<error reading variable: Cannot access memory at address 0x7fffff5e4a40>)
    at gamelogic/bg/SGPlatformActMgr.cpp:292
292 {
(gdb) print L
Cannot access memory at address 0x7fffff5e4a48

下面是可能有问题的代码,InitDBFromConf将在lua中被调用,就像InitDBFromConf(lua_act_config)一样:

int SGPlatformActMgr::InitDBFromConf(lua_State* L)
{
    //...
    //do something
    SGArray<TPlatformActInfo, 150> astActInfo;
    int iTableIdx = 1;
    int iRet = 0;
    lua_pushnil(L);
    while (lua_next(L, iTableIdx) != 0)
    {
        TPlatformActInfo stActInfo;
        iRet = TransformActInfo(L, stActInfo);
        if (iRet)
        {
            ERROR_LOG("invalid TransformActInfo failed(%d)\n", iRet);
            return 0;
        }
        astActInfo.Add(stActInfo);
        lua_pop(L, 1);
    }
    
    iRet = InitActDB(L, astActInfo);
    //do something
    //....
}

在TransformActInfo函数中:

#define ASSIGN_LUA_VALUE(L,VAR,KEY,RET_CODE)\
do \
{   \
    lua_pushstring((L), (KEY)); \
    lua_rawget((L), -2);    \
if (!lua_isnumber((L), -1)) \
{   \
    ERROR_LOG("expect number but got:%s\n", lua_typename((L), lua_type(L, -1)));    \
    return RET_CODE;    \
}   \
    (VAR) = lua_tonumber(L, -1); \
    lua_pop((L), 1);    \
} while (0)

#define ASSIGN_LUA_STR_VALUE(L,VAR,KEY,RET_CODE)\
do \
{   \
    lua_pushstring((L), (KEY)); \
    lua_rawget((L), -2);    \
if (!lua_isstring((L), -1)) \
{   \
    ERROR_LOG("expect string but got:%s\n", lua_typename((L), lua_type(L, -1)));    \
    return RET_CODE;    \
}   \
    const char* pTempStr = lua_tostring(L, -1); \
    SAFE_COPYSTR_TO_CARRAY((VAR), pTempStr); \
    lua_pop((L), 1);    \
} while (0)
int TransformActInfo(lua_State* L, TPlatformActInfo& stActInfo)
{
    if (!lua_istable(L, -1))
    {
        ERROR_LOG("expect a table but got:%s\n", lua_typename(L, lua_type(L, -1)));
        return -1;
    }

    ASSIGN_LUA_VALUE(L, stActInfo.m_uiActID, "id", -100);
        //.....
    ASSIGN_LUA_STR_VALUE(L, stActInfo.m_acExtStr, "ext_str", -112);

    return 0;
}

我尝试了以下方法来解决或调试问题:

  • 我使用gdb watch命令监视L参数的值,并在它发生变化时中断程序。我发现在SGPlatformActMgr::InitDBFromConf函数和InitActDB函数之间,没有任何代码或操作会导致L参数的值发生更改或被释放。
  • 在调用函数InitActDB之前,我使用gdb break命令设置断点并打印L参数的值。我发现它是一个有效的lua_State指针。指针
  • 我使用gdb step命令逐步执行InitActDB函数中的代码,发现在函数的第一行出现了分段错误。
  • 我可以正常调用InitActDB函数并传入有效的L和astActInfo参数。
  • 我可以在InitActDB函数中正常使用L和astActInfo参数,而不会出现分段错误或其他异常。
  • 我可以找到并解决分段故障的原因和解决方案。谢谢!
wvmv3b1j

wvmv3b1j1#

对不起,我发现是因为SGArray<TPlatformActInfo,150> astActInfo;使用了太多堆栈空间,导致堆栈溢出。经过我的计算,一个TPlatformActInfo的大小约为40 kb,150个约为6 MB,导致堆栈溢出。但我很困惑为什么它在CentOS上工作得很好。

相关问题