我们的代码记录各种有意义的事件。通常日志记录工作得很好,但今天日志功能在返回时导致访问冲突。我猜测堆以某种方式损坏了,但我不太清楚为什么。日志功能几乎在所有情况下都能工作,但现在我记录的文件名稍长一些。我哪里没看到问题?
std::string Format(const char* fmt, ...)
{
char buf[1 << 16]; // 65536
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
return std::string(buf);
} // <-- Access Violation (0xC0000005) upon returning
#define LOG_DEBUG(fmt, ...) \
{ \
ILogger* logger = LoggerFactory::GetLogger(); \
if (logger) \
{ \
std::string log = Format(fmt, ##__VA_ARGS__); \
logger->WriteLog(LOG_LEVEL_DEBUG, log.c_str()); \
} \
}
static int doSomething(char* szMsg, const int nLength, ...)
{
// Normally, this executes just fine.
LOG_DEBUG("Message = %s, length = %d", szMsg, nLength);
// ... do some things
}
程序退出并显示消息:
0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
。该地址对我来说似乎很可疑,为什么它会被最大化?
对于它的价值来说,
szMsg
被分配给一个非常长的字符串,其形式为:
application_specific_data\rϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷ
ϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷ
ϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷ
ϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷ
ϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷϷ
并且
nLength
是 65536
。
无论如何,我不太确定如何思考此类问题,即使对于这个确切的场景没有明确的答案,我该如何调试呢?我应该注意什么?我可以忽略什么?
返回时的访问冲突几乎总是破坏不是堆的结果,而是堆栈。
具体来说,在这种情况下,堆栈上的返回地址已被0xffffffff覆盖。当本地缓冲区溢出时,这种情况经常发生。
显然,溢出的缓冲区是
char buf[1 << 16];
如果您有一个比缓冲区大小长的字符串,则可能会发生这种情况,而如果您不小心有一个忘记以空终止的字符串,则很容易发生这种情况。
为了保护自己免受此问题影响永远不要使用
vsprintf()
(在我看来该功能甚至不应该存在)始终使用vsnprintf()
。这不会修复创建非常长的字符串的错误,但它可以避免您的程序因该错误而崩溃和烧毁。