Explanations to the article on Copy-Paste

300 views

Published on

Many readers liked my article "Consequences of using the Copy-Paste method in C++ programming and how to deal with it" [1]. Scott Meyers [2] noticed it too and asked me how static analysis proper helped us to detect the errors described in 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
300
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Explanations to the article on Copy-Paste

  1. 1. Explanations to the article on Copy-PasteAuthor: Andrey KarpovDate: 28.06.2011Many readers liked my article "Consequences of using the Copy-Paste method in C++ programming andhow to deal with it" [1]. Scott Meyers [2] noticed it too and asked me how static analysis proper helpedus to detect the errors described in the article. This is his letter:Your article on copy-paste of code fragments at http://www.viva64.com/en/a/0068/ was interesting,but its not clear how most of the errors you use as examples could be detected by static analysis. Theonly one I see that looks like a good candidate for static analysis is the assignment of too many elementsto invModulate. How could static analysis detect the others?I wrote an answer to the letter and then decided to arrange it as a blog-post. Perhaps other readers willalso find it interesting to know how the described errors were found.This is my answer:I have found all the samples of errors given in the article on "Copy-Paste" while investigating codes of projectsusing the PVS-Studio analyzer. Each error was detected by a certain diagnostic rule.The first four errors were detected by the V501 diagnostic rule. To put it in simpler words, this warning isgenerated when there are identical subexpressions standing to the left and to the right of operators &&, ||, -, /and the like. Besides, there are a lot of exceptions to reduce the number of false alarms. For instance, the warningwill not be produced for this code line: if (*p++ == *a++ && *p++ == *a++).Now lets consider the samples from the article.sampleCount VoiceKey::OnBackward (...) { ... int atrend = sgn( buffer[samplesleft - 2]-buffer[samplesleft - 1]); int ztrend = sgn( buffer[samplesleft - WindowSizeInt-2]- buffer[samplesleft - WindowSizeInt-2]); ...}This is how PVS-Studio diagnoses it:V501 There are identical sub-expressions to the left and to the right of the - operator. Audacityvoicekey.cpp 304inline_ bool Contains(const LSS& lss){ // We check the LSS contains the two // spheres at the start and end of the sweep return Contains(Sphere(lss.mP0, lss.mRadius)) && Contains(Sphere(lss.mP0, lss.mRadius));}
  2. 2. This is how PVS-Studio diagnoses it:V501 There are identical sub-expressions to the left and to the right of the && operator. plgcsopcodeicelss.h 69void COX3DTabViewContainer::OnNcPaint(){ ... if(rectClient.top<rectClient.bottom && rectClient.top<rectClient.bottom) { dc.ExcludeClipRect(rectClient); } ...}This is how PVS-Studio diagnoses it:V501 There are identical sub-expressions to the left and to the right of the && operator. UTox3dtabview.cpp 230void uteTestRunner::StressBayer(uint32 iFlags){ ... static EPixelFormat ms_pfList[] = { PF_Lub, PF_Lus, PF_Li, PF_Lf, PF_Ld }; const int fsize = sizeof(ms_pfList) / sizeof(ms_pfList); static EBayerMatrix ms_bmList[] = { BM_GRBG, BM_GBRG, BM_RGGB, BM_BGGR, BM_None }; const int bsize = sizeof(ms_bmList) / sizeof(ms_bmList); ...}This is how PVS-Studio diagnoses it:V501 There are identical sub-expressions to the left and to the right of the / operator: sizeof(ms_pfList) / sizeof (ms_pfList) IFF plugins engine.cpp 955V501 There are identical sub-expressions to the left and to the right of the / operator: sizeof(ms_bmList) / sizeof (ms_bmList) IFF plugins engine.cpp 958The next two samples are diagnosed by the V517 rule. The check detects sequences of the "if(A)... elseif(A)..." kind. This is a bit simplified too, of course, and there are also special exceptions to the rule.string TimePeriod::toString() const{ ... if (_relativeTime <= 143) os << ((int)_relativeTime + 1) * 5 << _(" minutes"); else if (_relativeTime <= 167)
  3. 3. os << 12 * 60 + ((int)_relativeTime - 143) * 30 << _(" minutes"); else if (_relativeTime <= 196) os << (int)_relativeTime - 166 << _(" days"); else if (_relativeTime <= 143) os << (int)_relativeTime - 192 << _(" weeks"); ...}This is how PVS-Studio diagnoses it:V517 The use of if (A) {...} else if (A) {...} pattern was detected. There is a probability of logical errorpresence. GSM gsm_sms_codec.cc 175void DXUTUpdateD3D10DeviceStats(...){ ... else if( DeviceType == D3D10_DRIVER_TYPE_SOFTWARE ) wcscpy_s( pstrDeviceStats, 256, L"WARP" ); else if( DeviceType == D3D10_DRIVER_TYPE_HARDWARE ) wcscpy_s( pstrDeviceStats, 256, L"HARDWARE" ); else if( DeviceType == D3D10_DRIVER_TYPE_SOFTWARE ) wcscpy_s( pstrDeviceStats, 256, L"SOFTWARE" ); ...}This is how PVS-Studio diagnoses it:V517 The use of if (A) {...} else if (A) {...} pattern was detected. There is a probability of logical errorpresence. TickerTape dxut.cpp 6217The next error was detected by the analyzer with the help of the V523 rule. It is odd that the then andelse branches of a condition perform the same actions.BOOL CGridCellBase::PrintCell(...){ ... if(IsFixed()) crFG = (GetBackClr() != CLR_DEFAULT) ? GetTextClr() : pDefaultCell->GetTextClr(); else crFG = (GetBackClr() != CLR_DEFAULT) ? GetTextClr() : pDefaultCell->GetTextClr(); ...}This is how PVS-Studio diagnoses it:V523 The then statement is equivalent to the else statement. GridCtrl gridcellbase.cpp 652
  4. 4. The next sample has an obvious "Copy-Paste" error. But it is detected by a rule which is not intended tofind misprints. We can say that the error is detected indirectly. And it is detected because an obviousarray overrun occurs. The V557 diagnostic rule is responsible for detecting this error.void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors ) { ... unsigned char invModulate[3]; ... invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0]; invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1]; invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2]; invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; ...}This is how PVS-Studio diagnoses it:V557 Array overrun is possible. The 3 index is pointing beyond array bound. renderer tr_shade_calc.c679The last sample is the most interesting one. It is detected by the V525 diagnostic. We have developedthis rule intentionally to detect similar code fragments where a misprint is highly probable.Schematically, its working principle is the following. Assume we have a code like this:if (A == 1) Q = A + X;if (A == 2) Q = A + Y;if (A == 3) Q = A + Y;The three statements have an identical structure. So lets consider this code fragment as a tableconsisting of names and numbers with the dimension 5x3:A 1 Q A XA 2 Q A YA 3 Q A YWhile investigating this table, the analyzer resorts to a heuristic algorithm to suppose that somethingelse must stand in the place of the last Y. Remember that it is just a very rough description.Unfortunately, I have to admit that this check often gives false reports and we do not know how toeliminate them. Because of this we had to set the third relevance level for the V525 warning. However,sometimes it lets you find very interesting errors like the one cited in the article:void KeyWordsStyleDialog::updateDlg(){ ...
  5. 5. Style & w1Style = _pUserLang->_styleArray.getStyler(STYLE_WORD1_INDEX); styleUpdate(w1Style, _pFgColour[0], _pBgColour[0], IDC_KEYWORD1_FONT_COMBO, IDC_KEYWORD1_FONTSIZE_COMBO, IDC_KEYWORD1_BOLD_CHECK, IDC_KEYWORD1_ITALIC_CHECK, IDC_KEYWORD1_UNDERLINE_CHECK); Style & w2Style = _pUserLang->_styleArray.getStyler(STYLE_WORD2_INDEX); styleUpdate(w2Style, _pFgColour[1], _pBgColour[1], IDC_KEYWORD2_FONT_COMBO, IDC_KEYWORD2_FONTSIZE_COMBO, IDC_KEYWORD2_BOLD_CHECK, IDC_KEYWORD2_ITALIC_CHECK, IDC_KEYWORD2_UNDERLINE_CHECK); Style & w3Style = _pUserLang->_styleArray.getStyler(STYLE_WORD3_INDEX); styleUpdate(w3Style, _pFgColour[2], _pBgColour[2], IDC_KEYWORD3_FONT_COMBO, IDC_KEYWORD3_FONTSIZE_COMBO, IDC_KEYWORD3_BOLD_CHECK, IDC_KEYWORD3_BOLD_CHECK, IDC_KEYWORD3_UNDERLINE_CHECK); Style & w4Style = _pUserLang->_styleArray.getStyler(STYLE_WORD4_INDEX); styleUpdate(w4Style, _pFgColour[3], _pBgColour[3], IDC_KEYWORD4_FONT_COMBO, IDC_KEYWORD4_FONTSIZE_COMBO, IDC_KEYWORD4_BOLD_CHECK, IDC_KEYWORD4_ITALIC_CHECK, IDC_KEYWORD4_UNDERLINE_CHECK); ...}This is how PVS-Studio diagnoses it:V525: The code containing the collection of similar blocks. Check items 7, 7, 6, 7 in lines 576, 580,584, 588The rest of the letter is not relevant to the matter and I wont cite the complete text. I have to admitthat the post is a bit boring but it shows well that static analysis can be successfully used to detect errorsin copy-pasted code. And these errors can be found both by specialized rules like V501 or V517 and in anindirect way, for example, by the V557 rule.If you want to know about other diagnostics implemented in PVS-Studio, please visit our documentationpage.References: 1. Andrey Karpov. Consequences of using the Copy-Paste method in C++ programming and how to deal with it. http://www.viva64.com/en/a/0068/ 2. Wikipedia. Scott Meyers. http://www.viva64.com/go.php?url=702

×