Comparing the general static analysis inVisual Studio 2010 and PVS-Studio byexamples of errors detected in five opensource...
Visual Studio: warning C6054: String szwThemeFile might not bezero-terminated. c:emuleplusdialogmintraybtn.hpp 445WCHAR sz...
HRESULT hr = pNSC->AddPortMapping(   riPortRule.m_strRuleName.AllocSysString(), riPortRule.m_byProtocol,   riPortRule.m_nP...
CFontPreviewCombo::CFontPreviewCombo(){    ...    m_clrSample = GetSysColor(COLOR_WINDOWTEXT);    m_clrSample = RGB(60,0,0...
There must be something else here. By the way, here you a general note on fixing errors detected by astatic analyzer. Whil...
...}Having deep nesting, the alloca call might cause stack overflow.VirtualDubThe total number of messages generated by th...
BOOL fClip;};static unsigned long __fastcall do_conv(    unsigned long *data,    const ConvoluteFilterData *cfd,    long s...
PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the || operator: c == } || c == }ccrys...
switch (ch){    case 0xB7:    case 0xBB:      strHTML += ch;      strHTML += _T("<wbr>");      bLastCharSpace = FALSE;    ...
}bool CCrystalTextView::IsValidTextPosY (const CPoint &point){    return GetLineCount () > 0 && m_nTopLine >= 0 &&        ...
case OUTPUT_CONTEXT:enum and switch types were a bit mixed up. But its alright, isnt it?PVS-Studio: V530 The return value ...
{    int firstDiff = GetFirstDifferentItem();    if (firstDiff > -1)     pCmdUI->Enable(TRUE);    else     pCmdUI->Enable(...
Again empty() does not empty the string at all.PVS-Studio: V510           The Format function is not expected to receivecl...
}The analyzer found a suspicious loop. This code is prone to Access Violation. The loop must go on until itfinds the > cha...
successively. Perhaps this is a mistake. resizedlg.cpp 244m_xSt = CST_RESIZE;m_xSt = CST_RESIZE;Judging by the code, there...
m_styBottom == CST_DELTA_ZOOM)    ...}Perhaps the code must look this way:HDWP CItemCtrl::OnSize(...){    ...    if (m_sty...
Upcoming SlideShare
Loading in …5
×

Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by examples of errors detected in five open source projects

564 views

Published on

The article demonstrates errors detected with the static code analyzer integrated into Visual Studio 2010. The research was performed on five open source projects. The same projects were also checked with PVS-Studio. Results of comparing these two tools are presented at the end of the article.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

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

No notes for slide

Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by examples of errors detected in five open source projects

  1. 1. Comparing the general static analysis inVisual Studio 2010 and PVS-Studio byexamples of errors detected in five opensource projectsAuthors: Evgeniy RyzhkovDate: 20.04.2011AbstractThe article demonstrates errors detected with the static code analyzer integrated into Visual Studio2010. The research was performed on five open source projects. The same projects were also checkedwith PVS-Studio. Results of comparing these two tools are presented at the end of the article.IntroductionThe article "Difficulties of comparing code analyzers, or dont forget about usability" [1] tells that it isnot so easy to compare two tools as it may seem because the parameter of usability is also highlysignificant besides the technical characteristics proper.Still we cannot do without comparing tools by errors they can detect. Of course, there is no sense in justcalculating the number of errors. So we decided to carry out a practical experiment of error detection inreal projects.We checked five random open source projects with the static analyzer integrated into Visual Studio2010 Premium. We looked through the whole message list and chose explicit errors. Then we made thesame steps with PVS-Studio.Here is a list of projects which participated in the research: • eMule Plus; • Pixie; • VirtualDub; • WinMerge; • XUIFramework.Lets go!eMule PlusThe total number of messages generated by the Visual Studio static analyzer is 237, 4 of them being realerrors.The total number of messages generated by PVS-Studio is 68, 3 of them being real errors.
  2. 2. 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)Indeed, a line may not end with 0, which will cause potential problems. But in this particular case, thiserror is not likely to reveal itself.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++;The programmer here "is not good at" using the (*ptr)++ expression. Although this construct seems tobe rather safe, still this error is widespread.Visual Studio: warning C6298: Argument 6: using a read-only stringas a writable string argument. This will attempt to write into staticread-only memory and cause random crashes.c:emuleplusfirewallopener.cpp 183
  3. 3. HRESULT 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);Although it is not an error, the analyzer-generated message is fair. In general, this is a problem of all thestatic analyzers. They produce absolutely correct messages but they are far not always real errors. Doesit mean that such tools and messages are useless? No, it does not, because fixing even such warningshelps to increase an overall quality of code.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));Here (because of the constructs complexity) we have wrong priorities of operators. For how long it hasbeen said... Who prevented the programmer from arranging this code in several separate expressionsinstead of writing everything in one line (as it was done in the original program)? No, programmerswould always want to "write it smart".PVS-Studio: V519 The m_clrSample object is assigned values twicesuccessively. Perhaps this is a mistake. fontpreviewcombo.cpp 61
  4. 4. CFontPreviewCombo::CFontPreviewCombo(){ ... m_clrSample = GetSysColor(COLOR_WINDOWTEXT); m_clrSample = RGB(60,0,0); ...}Perhaps the developers wanted to see how the RGB(60,0,0) color would look and forgot to remove it.PixieThe total number of messages generated by the Visual Studio static analyzer is 18, 0 of them being realerrors.The total number of messages generated by PVS-Studio is 65, 5 of them being real errors.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++;}Oh, how suspicious it is when numRays is first initialized by one value and then by another. Is it an erroror not? Only the codes author knows exactly. But it alerts me!PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the | operator: PARAMETER_DPDU | PARAMETER_DPDUquadrics.cpp 880if (up & (PARAMETER_DPDU | PARAMETER_DPDU)) {
  5. 5. There must be something else here. By the way, here you a general note on fixing errors detected by astatic analyzer. While in some cases correction is obvious and anyone can fix an error, in some othercases only the author of the code can make out what exactly was intended there. It is on the question ifone could create a tool that can correct errors "like in Word".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 mentioned twice in such a context certainly signals an error.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]); ... } while(sVertex != loops[i]); ... }
  6. 6. ...}Having deep nesting, the alloca call might cause stack overflow.VirtualDubThe total number of messages generated by the Visual Studio static analyzer is 24 messages, 0 of thembeing real errors.The total number of messages generated by PVS-Studio is 41, 2 of them being real errors.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"); ...}The code will never be called because the expression is always false.PVS-Studio: V557 Array overrun is possible. The 9 index is pointingbeyond array bound. f_convolute.cpp 73struct ConvoluteFilterData { long m[9]; long bias; void *dyna_func; DWORD dyna_size; DWORD dyna_old_protect;
  7. 7. 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]; ...}A trivial array overflow.WinMergeThe total number of messages generated by the Visual Studio static analyzer is 343, 3 of them being realerrors.The total number of messages generated by PVS-Studio is 69, 12 of them being real errors.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());}Not very lucky condition. Of course, the programmer wanted to write something different, but ithappened that way.Visual Studio: warning C6287: Redundant code: the left and rightsub-expressions are identical.c:winmergesrceditlibccrystaleditview.cpp 1560
  8. 8. PVS-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 (>);}Not all the parentheses types are checked. Why? It is usual that "Copy-paste-technology" leads toerrors.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;Another unlucky condition and again it seems to be the copy-pastes fault.PVS-Studio: V551 The code under this case label is unreachable.The value range of signed char type: [-128, 127].ccrystaltextview.cpp 1646TCHAR ch = strText[i];
  9. 9. switch (ch){ case 0xB7: case 0xBB: strHTML += ch; strHTML += _T("<wbr>"); bLastCharSpace = FALSE; nNonbreakChars = 0; break;And here we have a sample of code which will never be used. Everything seems alright, case is writtenand all, but it will never get control because the value range is too narrow. TCHAR in this case is the chartype.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){ return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 && point.y >= 0 && point.y < GetLineCount () && point.x >= 0 && point.x <= GetLineLength (point.y);
  10. 10. }bool CCrystalTextView::IsValidTextPosY (const CPoint &point){ return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 && point.y >= 0 && point.y < GetLineCount ();}These are very similar functions... The developers copy-pasted again and again and forgot to fix theresult. The IsValidTextPosX() function performs an excess check.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;Who can look at the code and say exactly to what if else refers? Was it the thing the programmerwanted to do? Are you sure?PVS-Studio: V556 The values of different enum types are compared:switch(ENUM_TYPE_A) { case ENUM_TYPE_B: ... }. diffwrapper.cpp 956enum output_style {}...enum DiffOutputType m_outputStyle;switch (m_options.m_outputStyle){
  11. 11. case OUTPUT_CONTEXT:enum and switch types were a bit mixed up. But its alright, isnt it?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();The case when empty() does not empty. This is an example of an extremely wrong name for a method.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 pCmdUI->Enable(FALSE);}void CDirView::OnUpdateFirstdiff(CCmdUI* pCmdUI)
  12. 12. { int firstDiff = GetFirstDifferentItem(); if (firstDiff > -1) pCmdUI->Enable(TRUE); else pCmdUI->Enable(FALSE);}Two more very similar functions...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)){Either this or that... Or not? Perhaps there must be pView2 here.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; m_fvalue = 0; m_svalue.empty(); m_tvalue = 0;}
  13. 13. Again empty() does not empty the string at all.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) );When various emergencies occur, WinMerge will try to inform the user about errors but in some cases itwill fail. At first sight everything looks OK but actually the "String" type is just "std::wstring". Thereforewe will print rubbish at best or get an Access Violation error at worst. The correct code must have a callof 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++) { if (src[k]==>) break; } ...
  14. 14. }The analyzer found a suspicious loop. This code is prone to Access Violation. The loop must go on until itfinds the > character or a string with the length of srclen characters comes to an end. But theprogrammer by accident used the k variable instead of i for comparison. If the > character is notfound, everything will be sad.XUIFrameworkThe total number of messages generated by the Visual Studio static analyzer is 93, 2 of them being realerrors.The total number of messages generated by PVS-Studio is 30, 5 of them being real errors.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++)Again the programmer is not good at using *ptr++. As I have said above, this is a widespread error.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;The programmer confuses delete and delete[]. This causes issues which may occur and may not. But youshould not do so anyway.PVS-Studio: V519 The m_xSt object is assigned values twice
  15. 15. successively. Perhaps this is a mistake. resizedlg.cpp 244m_xSt = CST_RESIZE;m_xSt = CST_RESIZE;Judging by the code, there must be m_ySt here. But we cannot keep from using copy-paste again andagain, right?V531 It is odd that a sizeof() operator is multiplied by sizeof().pphtmldrawer.cpp 258DWORD dwLen = ::LoadString(hInstDll, dwID, szTemp, (sizeof(szTemp) * sizeof(TCHAR)));There must be sizeof(szTemp) / sizeof(TCHAR) .PVS-Studio: V556 The values of different enum types are compared:enuHAlign == Center. cxstatic.cpp 151if (enuHAlign == Center)There must be enuHAlign == Midle. There is also if in the code nearby (enuVAlign == Middle) though itmust be Center. Confusion with enum, in short.PVS-Studio: V501 There are identical sub-expressions to the left andto the right of the || operator. resizedlg.cpp 157HDWP CItemCtrl::OnSize(...){ ... if (m_styTop == CST_ZOOM || m_styTop == CST_ZOOM || m_styBottom == CST_DELTA_ZOOM ||
  16. 16. m_styBottom == CST_DELTA_ZOOM) ...}Perhaps the code must look this way:HDWP CItemCtrl::OnSize(...){ ... if (m_styTop == CST_ZOOM || m_styTop == CST_DELTA_ZOOM || m_styBottom == CST_ZOOM || m_styBottom == CST_DELTA_ZOOM) ...}Comparison resultsWe do not draw any certain conclusions. One of the tools was better in some projects and the other toolwas better in others.References 1. Andrey Karpov, Evgeniy Ryzhkov. Difficulties of comparing code analyzers, or dont forget about usability. http://www.viva64.com/en/a/0071/.

×