gtest和cstdarg之间的交互是否不好,或者我真的错过了这里的堆栈粉碎
Is there a bad interaction between gtest and cstdarg, or am I really missing the stack smash here?
下面的代码旨在成为一个简单的错误日志记录系统,其行为方式类似于printf。
我的所有代码都在gtest环境中运行良好,但现在当我退出程序中的一个确定点(我的一个测试)时,它的堆栈会崩溃。在我写这篇文章之前,我的代码一直运行得很好,这是我第一次尝试cstdarg,所以它是最可疑的。
MyMutex error_lock;
#define MAX_ERR_MSG_SIZE 128
#define MAX_ERRORS 3
class ErrorQueue
{
std::queue<char*> errors;
std::list<char*> old_errors;
public:
void push(char * msg)
{
if (errors.size() >= MAX_ERRORS)
{
pop();
}
errors.push(msg);
}
void pop()
{
if (old_errors.size() >= MAX_ERRORS)
{
delete [] old_errors.front();
old_errors.pop_front();
}
old_errors.push_back(errors.front());
errors.pop();
}
char * front()
{
return errors.front();
}
size_t size()
{
return errors.size();
}
~ErrorQueue()
{
while(!errors.empty())
{
delete [] errors.front();
errors.pop();
}
while (!old_errors.empty())
{
delete [] old_errors.front();
old_errors.pop_front();
}
}
};
static ErrorQueue errors;
void WriteCallError(const char * error_message, ...)
{
char err_buffer[MAX_ERR_MSG_SIZE];
va_list args;
va_start(args,error_message);
std::vsnprintf(err_buffer,MAX_ERR_MSG_SIZE,error_message,args);
va_end(args);
char * err_string = new char[MAX_ERR_MSG_SIZE];
memcpy(err_string,err_buffer,MAX_ERR_MSG_SIZE);
{
error_lock.Lock();
errors.push(err_string);
error_lock.Unlock();
}
}
我在代码的其他地方多次调用WriteCallError,经过一定次数后,它会吐出,并告诉我堆栈已被打碎。
我的错在哪里?cstdarg和gtest之间有一些时髦的互动吗?这里有足够的信息吗?
编辑:使用一个简单的main,我尝试隔离它:
int main (int argc, char ** argv)
{
int i = 0;
while (1)
{
WriteCallError("Breaks on %d",i++);
}
}
这不会造成堆栈粉碎。
我认为您的问题是,如果您正在写入的数据超出指定的限制,vsnprintf不会向数组写入终止nul字符。当您稍后访问这个C字符串时,由于没有终止符,它将读取超出有效数据末尾的数据并进入未知内存。
你在测试中没有发现这一点,因为你没有超过128个字符的限制。
快速修复方法是确保在使用vsnprintf:后正确终止阵列
void WriteCallError(const char * error_message, ...)
{
char err_buffer[MAX_ERR_MSG_SIZE];
va_list args;
va_start(args,error_message);
std::vsnprintf(err_buffer,MAX_ERR_MSG_SIZE,error_message,args);
va_end(args);
// Fix here
err_buffer[MAX_ERR_MSG_SIZE - 1] = 0;
char * err_string = new char[MAX_ERR_MSG_SIZE];
memcpy(err_string,err_buffer,MAX_ERR_MSG_SIZE);
{
error_lock.Lock();
errors.push(err_string);
error_lock.Unlock();
}
}
回答这样我就可以结束问题了,因为我解决了错误:
它发生在类似的代码中:
TEST(MyTest,Case1)
{
MyStruct1 object1;
memset(&object1,0,sizeof(object1));
MyStruct2 object2[1];
memset(&object2[0],0,sizeof(object1));
object1.object2_ptr = object2;
// DO SOME TESTING
}
由于对象1&对象2是堆栈变量,对象1比对象2大。当我进行memset时,我把内存设置得太远了。当我离开该函数的堆栈部分时,堆栈指针大喊发生了疯狂的事情,并告诉我我正在砸堆栈。
简单修复:
TEST(MyTest,Case1)
{
MyStruct1 object1;
memset(&object1,0,sizeof(MyStruct1));
MyStruct2 object2[1];
memset(&object2[0],0,sizeof(MyStruct2));
object1.object2_ptr = object2;
// DO SOME TESTING
}
相关文章:
- gcc 是否在 2 条短裤的过度对齐结构的比较中错过了优化机会?
- 我的C++合并排序代码不起作用。我在这里错过了什么?
- 我是否为邪恶刽子手的构造函数错过了什么?
- C++:将向量传递给函数,然后在main中调用函数.错过了什么
- 随机访问迭代器:我错过了什么?
- 当编译时已知引用占用结构中的空间时,是否错过了优化?
- std::元组大小,是不是错过了优化?
- 在这个while循环中我错过了什么?
- 编译器错过了无效的构造函数调用,并调用不存在的(或私有的)默认构造函数
- 我是否错过了什么,或者虚拟呼叫的性能并不像人们所说的那样糟糕
- C 中MAP的反向迭代错过了第一个元素
- 仅在 2 的幂上错过了 clang 中的优化
- 我错过了boost :: mpi ::请求?测试似乎改变了状态
- 我在变量上收到 3 个 C4703 错误,我认为我已经正确初始化了,但我不确定我错过了什么
- 如果这不是 boost::lockfree::d etail::freelist 中的错误,我在这里错过了什么
- 尝试使用类,但未打印任何内容.不会生成任何错误.我错过了什么吗?
- 尝试实现通过引用传递的向量以与二叉树一起使用,我错过了什么
- c recursive_directory_iterator错过了一些文件
- fgets vs. std :: fgets- fgets错过了线条
- gtest和cstdarg之间的交互是否不好,或者我真的错过了这里的堆栈粉碎