Сравнение статического анализаобщего назначения из Visual Studio2010 и PVS-Studio на примереобнаруженных ошибок в пятиоткр...
eMule PlusВсего сообщений от статического анализатора Visual Studio – 237. Из них реальных ошибок – 4.Всего сообщений от P...
read-only memory and cause random crashes.c:emuleplusfirewallopener.cpp 183HRESULT hr = pNSC->AddPortMapping(  riPortRule....
PVS-Studio: V519 The m_clrSample object is assigned values twicesuccessively. Perhaps this is a mistake. fontpreviewcombo....
quadrics.cpp 880if (up & (PARAMETER_DPDU | PARAMETER_DPDU)) {Явно здесь должно быть что-то еще. Кстати общее замечание по ...
...        } while(sVertex != loops[i]);        ...    }    ...}Из-за большой вложенности вызов alloca может привести к пе...
long bias; void *dyna_func; DWORD dyna_size; DWORD dyna_old_protect; BOOL fClip;};static unsigned long __fastcall do_conv(...
Visual Studio: warning C6287: Redundant code: the left and rightsub-expressions are identical.c:winmergesrceditlibccrystal...
ccrystaltextview.cpp 1646TCHAR ch = strText[i];switch (ch){    case 0xB7:    case 0xBB:     strHTML += ch;     strHTML += ...
return GetLineCount () > 0 && m_nTopLine >= 0 &&            m_nOffsetChar >= 0 && point.y >= 0 &&            point.y < Get...
enum DiffOutputType m_outputStyle;switch (m_options.m_outputStyle){    case OUTPUT_CONTEXT:Немножечко попутали тип enum в ...
pCmdUI->Enable(FALSE);}void CDirView::OnUpdateFirstdiff(CCmdUI* pCmdUI){    int firstDiff = GetFirstDifferentItem();    if...
m_fvalue = 0;    m_svalue.empty();    m_tvalue = 0;}И опять empty() вовсе не очищает строку.PVS-Studio: V510        The Fo...
if (src[k]==>)          break;    }    ...}Анализатор нашел подозрительный цикл. Этот код предрасположен к Access Violatio...
Путают люди delete и delete[]. Это приводит к проблемам. Иногда проблемы проявляются, иногданет. Но так делать не надо.PVS...
if (m_styTop == CST_ZOOM ||          m_styTop == CST_ZOOM ||          m_styBottom == CST_DELTA_ZOOM ||          m_styBotto...
Upcoming SlideShare
Loading in …5
×

Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-Studio на примере обнаруженных ошибок в пяти открытых проектах

469 views

Published on

В статье показаны ошибки, выявленные с помощью статического анализатора кода, встроенного в Visual Studio 2010. Исследование проводилось на пяти open source проектах. Эти же проекты были проверены с помощью PVS-Studio. Приведены результаты сравнения этих двух инструментов.

Published in: Technology, Art & Photos
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
469
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-Studio на примере обнаруженных ошибок в пяти открытых проектах

  1. 1. Сравнение статического анализаобщего назначения из Visual Studio2010 и PVS-Studio на примереобнаруженных ошибок в пятиоткрытых проектахАвторы: Евгений РыжковДата: 20.04.2011АннотацияВ статье показаны ошибки, выявленные с помощью статического анализатора кода, встроенного вVisual Studio 2010. Исследование проводилось на пяти open source проектах. Эти же проекты былипроверены с помощью PVS-Studio. Приведены результаты сравнения этих двух инструментов.ВведениеВ статье "Трудности сравнения анализаторов кода или не забывайте об удобстве использования"[1] говорится о том, что сравнить между собой два инструмента не так просто как кажется, потомучто помимо собственно технических характеристик анализаторов очень большое значение имееттакой параметр как удобство использования.Но все-таки от сравнения по обнаруживаемым ошибкам никуда не деться. Естественно, простопосчитать их количество – смысла нет. Поэтому мы решили провести практический экспериментпо обнаружению ошибок в реальных проектах.Мы проверили пять случайных open source проектов сначала c помощью статическогоанализатора, встроенного в Visual Studio 2010 Premium. Просмотрели весь список сообщений ивыбрали явные ошибки. Затем также поступили с PVS-Studio.Вот список проектов, участвовавших в исследовании: • eMule Plus; • Pixie; • VirtualDub; • WinMerge; • XUIFramework.Итак, поехали!
  2. 2. eMule PlusВсего сообщений от статического анализатора Visual Studio – 237. Из них реальных ошибок – 4.Всего сообщений от PVS-Studio – 68. Из них реальных ошибок – 3.Visual Studio: warning C6054: String szwThemeFile might not bezero-terminated. c:emuleplusdialogmintraybtn.hpp 445WCHAR szwThemeFile[MAX_PATH];WCHAR szwThemeColor[256];if (m_themeHelper.GetCurrentThemeName(szwThemeFile, ARRSIZE(szwThemeFile), szwThemeColor, ARRSIZE(szwThemeColor), NULL, 0) != S_OK) return NULL;WCHAR *p;if ((p = wcsrchr(szwThemeFile, L)) == NULL)Действительно строка может не заканчиваться на 0, что приведет к потенциальным проблемам.Однако в данном случае эта ошибка не проявит себя, скорее всего.Visual Studio: warning C6269: Possibly incorrect order of operations:dereference ignored. c:emulepluscustomautocomplete.cpp 277PVS-Studio: V532 Consider inspecting the statement of *pointer++pattern. Probably meant: (*pointer)++. customautocomplete.cpp 277if (pceltFetched != NULL) *pceltFetched++;Здесь программист "не умеет" пользоваться выражением (*ptr)++. Хотя, казалось бы, такаяконструкция выглядит достаточно безобидно, тем не менее, подобная ошибка оченьраспространена.Visual Studio: warning C6298: Argument 6: using a read-only stringas a writable string argument. This will attempt to write into static
  3. 3. read-only memory and cause random crashes.c:emuleplusfirewallopener.cpp 183HRESULT hr = pNSC->AddPortMapping( riPortRule.m_strRuleName.AllocSysString(), riPortRule.m_byProtocol, riPortRule.m_nPortNumber, riPortRule.m_nPortNumber, 0, L"127.0.0.1", ICSTT_IPADDRESS, &pNSPM);Хотя это и не ошибка, но сообщение анализатора справедливое. Вообще это проблема всехинструментов статического анализа. Они выдают совершенно корректные сообщения, но далеконе всегда это действительно ошибки. Означает ли это, что инструменты и подобные сообщениябесполезны? Нет, не означает, поскольку исправление даже подобных замечаний в целомповышает качество кода.Visual Studio: warning C6314: Incorrect order of operations: bitwise-or has higher precedence than the conditional-expression operator.Add parentheses to clarify intent. c:emuleplussearchlistctrl.cpp 659PVS-Studio: V502 Perhaps the ?: operator works in a different waythan it was expected. The ?: operator has a lower priority than the| operator. searchlistctrl.cpp 659menuSearchFile.AppendMenu( MF_STRING | ((iSelectionMark != -1) && (dwSelectedCount > 0) && g_App.m_pServerConnect->IsConnected() && ((pCurServer = g_App.m_pServerConnect->GetCurrentServer())!= NULL)&& (pCurServer->GetTCPFlags() & SRV_TCPFLG_RELATEDSEARCH)) ? MF_ENABLED : MF_GRAYED, MP_SEARCHRELATED, GetResString(IDS_SEARCHRELATED));Здесь (из-за сложности конструкции) получился неправильный приоритет операторов. Уж сколькораз твердили миру... Ну вот кто мешал писать это все не в одну строку (как в оригинальнойпрограмме), а разбить на несколько отдельных выражений? Нет же, программисты часто хотят"записать красиво".
  4. 4. PVS-Studio: V519 The m_clrSample object is assigned values twicesuccessively. Perhaps this is a mistake. fontpreviewcombo.cpp 61CFontPreviewCombo::CFontPreviewCombo(){ ... m_clrSample = GetSysColor(COLOR_WINDOWTEXT); m_clrSample = RGB(60,0,0); ...}Возможно, попробовали как будет смотреться цвет RGB(60,0,0) и забыли убрать.PixieВсего сообщений от статического анализатора Visual Studio – 18. Из них реальных ошибок – 0.Всего сообщений от PVS-Studio – 65. Из них реальных ошибок – 5.PVS-Studio: V519 The numRays object is assigned values twicesuccessively. Perhaps this is a mistake. bundles.cpp 579void CGatherBundle::post() { numRays = last; numRays = 0; last = 0; depth++;}Ой, как подозрительно, что сначала numRays инициализируется одним значением, а затемдругим. Ошибка? Или нет? Знает только автор кода. Но настораживает!PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the | operator: PARAMETER_DPDU | PARAMETER_DPDU
  5. 5. quadrics.cpp 880if (up & (PARAMETER_DPDU | PARAMETER_DPDU)) {Явно здесь должно быть что-то еще. Кстати общее замечание по исправлению ошибок,обнаруженных статическим анализатором. Если в каких-то случаях исправление очевидно и егоможет сделать любой, то в каких-то лишь автор кода может разобраться с тем, что же он хотелнаписать. Это к вопросу о том, а нельзя ли сделать инструмент, который предлагает исправлениеошибок "как в Ворде".PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the | operator: SLC_VECTOR | SLC_VECTORexpression.cpp 2604lock(N, getConversion(SLC_VECTOR | SLC_VECTOR,parameters[2]));Дважды упомянутый SLC_VECTOR в подобном контексте – конечно же, признак ошибки.PVS-Studio: V505 The alloca function is used inside the loop.This can quickly overflow stack. polygons.cpp 1120inline void triangulatePolygon(...) { ... for (i=1;i<nloops;i++) { ... do { ... do { ... CTriVertex *snVertex = (CTriVertex *) alloca(2*sizeof(CTriVertex)); ... } while(dVertex != loops[0]);
  6. 6. ... } while(sVertex != loops[i]); ... } ...}Из-за большой вложенности вызов alloca может привести к переполнению стека.VirtualDubВсего сообщений от статического анализатора Visual Studio – 24. Из них реальных ошибок – 0.Всего сообщений от PVS-Studio – 41. Из них реальных ошибок – 2.PVS-Studio: V547 Expression c < 0 is always false.Unsigned type value is never < 0. lexer.cpp 279typedef unsigned short wint_t;wint_t lexgetescape() { wint_t c = lexgetc(); if (c < 0) fatal("Newline found in escape sequence"); ...}Код никогда не будет вызван, поскольку выражение всегда false.PVS-Studio: V557 Array overrun is possible. The 9 index is pointingbeyond array bound. f_convolute.cpp 73struct ConvoluteFilterData { long m[9];
  7. 7. long bias; void *dyna_func; DWORD dyna_size; DWORD dyna_old_protect; BOOL fClip;};static unsigned long __fastcall do_conv( unsigned long *data, const ConvoluteFilterData *cfd, long sflags, long pit){ long rt0=cfd->m[9], gt0=cfd->m[9], bt0=cfd->m[9]; ...}Банальный выход за границы массива.WinMergeВсего сообщений от статического анализатора Visual Studio – 343. Из них реальных ошибок – 3.Всего сообщений от PVS-Studio – 69. Из них реальных ошибок – 12.Visual Studio: warning C6313: Incorrect operator: zero-valued flagcannot be tested with bitwise-and. Use an equality test to check forzero-valued flags. c:winmergesrcbcmenu.cpp 1489else if (nFlags&MF_STRING){ ASSERT(!(nFlags&MF_OWNERDRAW)); ModifyMenu(pos,nFlags,nID,mdata->GetString());}Неудачно записано условие. Хотели, конечно записать другое, но уж "что получилось".
  8. 8. Visual Studio: warning C6287: Redundant code: the left and rightsub-expressions are identical.c:winmergesrceditlibccrystaleditview.cpp 1560PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the || operator: c == } || c == }ccrystaleditview.cpp 1560boolisclosebrace (TCHAR c){ return c == _T (}) || c == _T (}) || c == _T (]) || c == _T (>);}Не все типы скобочек проверяются. Почему? "Copy-paste-technology", как это нередко бывает,приводит к ошибкам.Visual Studio: warning C6287: Redundant code: the left and rightsub-expressions are identical. c:winmergesrcmergedoc.cpp 1165PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the || operator. mergedoc.cpp 1165if ((m_nBufferType[nBuffer] == BUFFER_UNNAMED) || (m_nBufferType[nBuffer] == BUFFER_UNNAMED)) nSaveErrorCode = SAVE_NO_FILENAME;Опять неудачное условие. И опять, похоже, из-за копи-паста.PVS-Studio: V551 The code under this case label is unreachable.The value range of signed char type: [-128, 127].
  9. 9. ccrystaltextview.cpp 1646TCHAR ch = strText[i];switch (ch){ case 0xB7: case 0xBB: strHTML += ch; strHTML += _T("<wbr>"); bLastCharSpace = FALSE; nNonbreakChars = 0; break;А вот здесь пример кода, который никогда не будет использован. Вроде бы и case написан, даникогда он не получит управление. Потому что диапазон значений слишком узкий. TCHAR вданном случае представляет собой тип char.PVS-Studio: V524 It is odd that the body of IsValidTextPosX functionis fully equivalent to the body of IsValidTextPos function(ccrystaltextview.cpp, line 3700). ccrystaltextview.cpp 3707bool CCrystalTextView::IsValidTextPos (const CPoint &point){ return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 && point.y >= 0 && point.y < GetLineCount () && point.x >= 0 && point.x <= GetLineLength (point.y);}bool CCrystalTextView::IsValidTextPosX (const CPoint &point){
  10. 10. return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 && point.y >= 0 && point.y < GetLineCount () && point.x >= 0 && point.x <= GetLineLength (point.y);}bool CCrystalTextView::IsValidTextPosY (const CPoint &point){ return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 && point.y >= 0 && point.y < GetLineCount ();}Крайне похожие функции... Снова и снова копи-пастили и забыли поправить результат. ФункцияIsValidTextPosX() делает лишнюю проверку.PVS-Studio: V563 It is possible that this else branch must apply tothe previous if statement. bcmenu.cpp 1852if(IsLunaMenuStyle()) if(!xp_space_accelerators)return;else if(!original_space_accelerators)return;Кто, глядя на код, точно скажет, к какому if относится else? А это ли хотел сделать программист? Авы уверены?PVS-Studio: V556 The values of different enum types are compared:switch(ENUM_TYPE_A) { case ENUM_TYPE_B: ... }. diffwrapper.cpp 956enum output_style {}...
  11. 11. enum DiffOutputType m_outputStyle;switch (m_options.m_outputStyle){ case OUTPUT_CONTEXT:Немножечко попутали тип enum в switch. Но это ведь не страшно? Или страшно?PVS-Studio: V530 The return value of function empty is required tobe utilized. diractions.cpp 1307void CDirView::GetItemFileNames(int sel, String& strLeft, String& strRight) const{ UINT_PTR diffpos = GetItemKey(sel); if (diffpos == (UINT_PTR)SPECIAL_ITEM_POS) { strLeft.empty(); strRight.empty();Тот случай, когда empty() не делает empty. Пример крайне неудачного названия метода.PVS-Studio: V524 It is odd that the body of OnUpdateLastdifffunction is fully equivalent to the body of OnUpdateFirstdifffunction (DirView.cpp, line 2189). dirview.cpp 2220void CDirView::OnUpdateLastdiff(CCmdUI* pCmdUI){ int firstDiff = GetFirstDifferentItem(); if (firstDiff > -1) pCmdUI->Enable(TRUE); else
  12. 12. pCmdUI->Enable(FALSE);}void CDirView::OnUpdateFirstdiff(CCmdUI* pCmdUI){ int firstDiff = GetFirstDifferentItem(); if (firstDiff > -1) pCmdUI->Enable(TRUE); else pCmdUI->Enable(FALSE);}Еще две крайне похожие функции...PVS-Studio: V501 There are identical sub-expressionspView1->GetTextBufferEol (line) to the left and to the right ofthe != operator. mergedoclinediffs.cpp 216if (pView1->GetTextBufferEol(line) != pView1->GetTextBufferEol(line)){Или то, или то... Или не то? Наверное, здесь должно быть pView2.PVS-Studio: V530 The return value of function empty is required tobe utilized. varprop.cpp 133void VariantValue::Clear(){ m_vtype = VT_NULL; m_bvalue = false; m_ivalue = 0;
  13. 13. m_fvalue = 0; m_svalue.empty(); m_tvalue = 0;}И опять empty() вовсе не очищает строку.PVS-Studio: V510 The Format function is not expected to receiveclass-type variable as N actual argument". PropShel 105String GetSysError(int nerr);...CString msg;msg.Format( _T("Failed to open registry key HKCU/%s:nt%d : %s"), f_RegDir, retVal, GetSysError(retVal) );При возникновении различных аварийных ситуаций WinMerge попробует сообщить об ошибках,но в некоторых случаях у него это плохо получится. На первый взгляд все хорошо. Вот только тип"String" есть не что иное как "std::wstring". А, следовательно, в лучшем случае мы распечатаемабракадабру, а в худшем произойдет ошибка доступа к памяти (Access Violation). Корректный коддолжен содержать вызов c_str().PVS-Studio: V534 It is likely that a wrong variable is being comparedinside the for operator. Consider reviewing i." BinTrans.cpp 357// Get length of translated array of bytes from text.int Text2BinTranslator::iLengthOfTransToBin( char* src, int srclen ){ ... for (k=i; i<srclen; k++) {
  14. 14. if (src[k]==>) break; } ...}Анализатор нашел подозрительный цикл. Этот код предрасположен к Access Violation. Циклдолжен продолжаться пока не найдется символ > или не закончится строка длиной в srclenсимволов. Вот только случайно для сравнения использована переменная i, а не k. Если символ> найден не будет, то все вероятно закончится печально.XUIFrameworkВсего сообщений от статического анализатора Visual Studio – 93. Из них реальных ошибок – 2.Всего сообщений от PVS-Studio – 30. Из них реальных ошибок – 5.Visual Studio: warning C6269: Possibly incorrect order of operations:dereference ignoredc:xui-gui frameworkwidgetscstatichtmlppdrawmanager.cpp 298PVS-Studio: V532 Consider inspecting the statement of *pointer++pattern. Probably meant: (*pointer)++. ppdrawmanager.cpp 298for (DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, *pBits++)Опять кто-то не умеет пользоваться *ptr++. Как говорилось выше, ошибка распространенная.Visual Studio: warning C6283: pBuffer is allocated with array new[],but deleted with scalar delete.c:xui-gui frameworkwidgetscxstaticcxstatic.cpp 544BYTE* pBuffer = new BYTE [ nBufferLen ];...delete pBuffer;
  15. 15. Путают люди delete и delete[]. Это приводит к проблемам. Иногда проблемы проявляются, иногданет. Но так делать не надо.PVS-Studio: V519 The m_xSt object is assigned values twicesuccessively. Perhaps this is a mistake. resizedlg.cpp 244m_xSt = CST_RESIZE;m_xSt = CST_RESIZE;Судя по коду, там должно быть m_ySt. Но от копи-паста ведь снова и снова не удержаться, да?V531 It is odd that a sizeof() operator is multiplied by sizeof().pphtmldrawer.cpp 258DWORD dwLen = ::LoadString(hInstDll, dwID, szTemp, (sizeof(szTemp) * sizeof(TCHAR)));Должно быть sizeof(szTemp) / sizeof(TCHAR) .PVS-Studio: V556 The values of different enum types are compared:enuHAlign == Center. cxstatic.cpp 151if (enuHAlign == Center)Должно быть enuHAlign == Midle. И в коде рядом есть еще if (enuVAlign == Middle), хотя должнобыть Center. Попутали enum, короче.PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the || operator. resizedlg.cpp 157HDWP CItemCtrl::OnSize(...){ ...
  16. 16. if (m_styTop == CST_ZOOM || m_styTop == CST_ZOOM || m_styBottom == CST_DELTA_ZOOM || m_styBottom == CST_DELTA_ZOOM) ...}Вероятно, код должен выглядеть так:HDWP CItemCtrl::OnSize(...){ ... if (m_styTop == CST_ZOOM || m_styTop == CST_DELTA_ZOOM || m_styBottom == CST_ZOOM || m_styBottom == CST_DELTA_ZOOM) ...}Результаты сравненияМы не делаем никаких конкретных выводов. В каких-то проектах лучше себя показал одининструмент, в каких-то – другой.Библиографический список 1. Андрей Карпов, Евгений Рыжков. Трудности сравнения анализаторов кода или не забывайте об удобстве использования. http://www.viva64.com/ru/a/0071/.

×