调一个bug,lua中c++返回的字符串问题,该问题只在运行时出现,调试时不会出现,开始觉得很奇怪,还好现在用vs2003可以Attach Process。
一路跟踪代码tolua_pushstring->lua_pushstring->lua_pushlstring->luaS_newlstr->luaM_malloc(luaM_realloc_)->(*g->frealloc)->l_allocrealloc
->_realloc_base->_malloc_base->_nh_malloc_base->_heap_alloc_base->HeapAlloc
从lua跟到c++分配内存,顺便复习了一遍以前听过候捷老师的一次关于c++内存分配的讲座。
监视tolua_pushstring中的字符串地址,最后发现在分配内存时该地址被清空了。
原来是由于一个函数TYPE &info = Date.Getinfo()本应用引用而漏写了&符号,导致一个局部变量的字符串指针域被返回,重新分配内存时被覆盖。
回想起来,问题调试时不出现,只在在运行时出现可能是因为调试器的内存分配策略不同,调试时比较松散没有覆盖到原来的无效内存,而运行时分配比较集中?
开始以为是luaS_newlstr函数有问题,花了些时间看了下
TString *luaS_newlstr (lua_State *L, const char *str, size_t l)
--[[引用
在luaS_newlstr中会先计算字符串的hash值,然后遍历stringtable这个全局hash表,如果查找到对应的字符串就返回ts,否则调用newlstr重新生成一个。
而 newlstr则就是新建一个tsring然后给相应位赋值,然后计算hash值插入到全局的global_State的stringtable中。然后 每次都会比较nuse和size的大小,如果大于size则说明碰撞太严重,因此增加桶的大小。这里增加每次都是2的倍数增加。
--]]
同时了解了TString结构,
从TString取出char*的方法:
TString *ts = luaS_newlstr(L, s, len);
szStr =svalue(ts->tsv);
--等价于 szStr = (const char *)(&(luaS_newlstr(L, s, len)->tsv)+1);
#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
#define tsvalue(o) (&rawtsvalue(o)->tsv)
#define svalue(o) getstr(tsvalue(o))