ACE_DEBUG的溢出错误
这个bug又是inmore发现,错误定位ACE_DEBUG在字符串处理中,可能会引发abort。这个bug在5.6.X,和5.4.X(不能确认),5.7.0的版本都存在,我提交了相应的bug后,也许会在5.7.1版本修正。
我们可以用一个简单的程序验证这个BUG。
#include <conio.h>
#include <iostream>
#include <ace/Log_Msg.h>
int main(int, char **)
{
char out_string[64*1024+1];
memset(out_string,'@',sizeof(out_string));
out_string[ACE_MAXLOGMSGLEN] = '/0';
ACE_DEBUG((LM_ALERT,"%s out_string: wo ai beijing tian an
men.",out_string));
return 0;
};
其就会引发abort函数,如果从MSVC看堆栈信息如下:
msvcr71d.dll!_NMSG_WRITE(int rterrnum=10) Line 195 C
msvcr71d.dll!abort() Line 44 + 0x7 C
ACEd.dll!ACE_OS::abort() Line 39 + 0x8 C++
ACEd.dll!ACE_Log_Msg::log(const char * format_str=0x00416037,
ACE_Log_Priority log_priority=LM_ALERT, char * argp=0x0011fc78) Line 2085
C++
ACEd.dll!ACE_Log_Msg::log(ACE_Log_Priority log_priority=LM_ALERT, const
char * format_str=0x00416034, ...) Line 953 + 0x14 C++
TestLog.exe!ace_main_i(int __formal=1, int __formal=1) Line 18 + 0x77
C++
... ...
稍微浏览了一下,我认为BUG在ACE_Log_Msg::log这个地方,ACE为了输出日志信息,使用了一个长度为ACE_MAXLOGMSGLEN+1的buf作为输出的缓冲区,ACE_MAXLOGMSGLEN的默认长度是4096。但是输出处理过程中,其边界值判断存在一定的问题。其ACE 5.6.1版本的代码如下:
ssize_t
ACE_Log_Msg::log (const ACE_TCHAR *format_str,
ACE_Log_Priority log_priority,
va_list argp)
{
..............
ssize_t result = 0;
// Check that memory was not corrupted, if it corrupted we can't log anything
// anymore because all our members could be corrupted.
if (bp >= (this->msg_ + ACE_MAXLOGMSGLEN+1))
{
abort_prog = true;
ACE_OS::fprintf (stderr,
"The following logged message is too long!/n");
}
其中代码if (bp >= (this->msg_ + ACE_MAXLOGMSGLEN+1))应该修改成为if (bp > (this->msg_ + ACE_MAXLOGMSGLEN+1)),注意应该去掉=符号。如果希望确保日志的缓冲区不再溢出,在这个函数的开始阶段,应该对缓冲区的msg_进行初始化,msg_[MAXLOGMSGLEN] = '/0';
另外在这个函数中的这段代码,效率是太低了。
In fuction ACE_Log_Msg::log ,
if (!skip_nul_locate)
while (*bp != '/0') // Locate end of bp.
++bp;
大家在使用ACE_DEBUG的时候要注意使用的频度和输出信息的大小了。