C/C++100个典型的Bugs(二)

2014-11-24 00:04:30 · 作者: · 浏览: 13
for (i = 0; i < sizeof(doserrors); i++)
{
if (doserrors[i].winerr == e)
{
errno = doserrors[i].doserr;
return;
}
}
}
作者原本意图la_dosmaperr中for循环的次数等于数组的元素个数,但sizeof(doserrors)返回的却是数组占用的字节个数,这远远大于数组元素个数,因此造成数组越界。正确的写法:
for (i = 0; i < sizeof(doserrors) / sizeof(*doserrors); i++)
[#10] CPU Identifying Tool项目 – 打印到自身的字符串
char * OSDetection ()
{
sprintf(szOperatingSystem,
"%sversion %d.%d %s (Build %d)",
szOperatingSystem,
osvi.dwMajorVersion,
osvi.dwMinorVersion,
osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);
sprintf (szOperatingSystem, "%s%s(Build %d)",
szOperatingSystem, osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);
}
通过sprintf,szOperatingSystem字符串将自己打印到自己里面,这是十分危险的,将导致无法预知的错误结果,可能会导致栈溢出等严重问题。
[#12] Notepad++项目 – 数组局部clear
#define CONT_MAP_MAX 50
int _iContMap[CONT_MAP_MAX];
DockingManager::DockingManager()
{
memset(_iContMap, -1, CONT_MAP_MAX);
}
代码的原本试图将数组_iContMap清零,但memset的第三个参数CONT_MAP_MAX并不能代表数组的真正大小,而只是数组的元素个数而已,显然其忘记乘以sizeof(int)了。
二、未定义行为
在C/C++的语言规范中,我们常常能看到“xx is undefined”。规范中并没有明确表明这类错误是什么样子的,只是说取决于Compiler的实现,也许Compiler会给出正确的结果,但这么使用却是不可移植的。
[#1] Chromium项目 – 智能指针的误用
void AccessibleContainsAccessible(…)
{
auto_ptr child_array(new VARIANT[child_count]);
}
这里的问题在于使用new[]分配的内存,在智能指针释放时却用了delete,这将会导致未定义行为。看看autoptr的destructor就知道了:
~auto_ptr() {
delete _Myptr;
}
我们可以找一些更合适的类来fix这个问题,比如boost::scopedarray。
[#2] IPP Sample项目 – 经典未定义行为
template void HadamardFwdFast(…)
{
Ipp32s *pTemp;
for(j=0;j<4;j++) {
a[0] = pTemp[0*4] + pTemp[1*4];
a[1] = pTemp[0*4] – pTemp[1*4];
a[2] = pTemp[2*4] + pTemp[3*4];
a[3] = pTemp[2*4] – pTemp[3*4];
pTemp = pTemp++;
}
}
很多人一眼就看到了"pTemp = pTemp++"这行,对于这个代码编译器会产生两种结果截然不同的翻译:
pTemp = pTemp + 1;
pTemp = pTemp;
TMP = pTemp;
pTemp = pTemp + 1;
pTemp = TMP;
到底是哪种呢?依赖于编译器的实现,甚至是优化级别的设定。
三、与运算优先级相关的错误
[#1] MySQL工程 – !和&的运算优先级
int ha_innobase::create(…)
{
if (srv_file_per_table
&& !mysqld_embedded
&& (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
}
这段代码原意是想测试create_info->options变量中几个bit位的值是否set了,即!(create_info->options & HA_LEX_CREATE_TMP_TABLE),但由于!的运算优先级高于&,实际逻辑变成了(!create_info->options) & HA_LEX_CREATE_TMP_TABLE了。如果想要这段代码如期工作,就不要吝啬小括号了。
[#2] Emule工程 – *和++的运算优先级
STDMETHODIMP
CCustomAutoComplete::Next(…, ULONG *pceltFetched)
{
if (pceltFetched != NULL)
*pceltFetched++;
}
显然作者原意是想对pceltFetched所指向的long型变量进行++操作,但由于*和++的运算优先级没有搞对,导致实际上执行了*(pceltFetched++)的操作,而不是(*pceltFetched)++操作。
[#3] Chromium项目 – &和!=的运算优先级
#define FILE_ATTRIBUTE_DIRECTORY 0×00000010
bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
info->is_directory =
file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;
}
这个程序员的意图是通过测试file_info.dwFileAttributes的几个bit位的值来判定是否是目录,逻辑上应该是(file_