100 bugs in Open Source C/C++ projectsAuthors: Andrey Karpov, Evgeniy RyzhkovDate: 16.03.2012AbstractThis article demonstr...
•     Fennec Media Project - http://fennec.sourceforge.net/    •     G3D Content Pak - http://sourceforge.net/projects/g3d...
The error was found through the V568 diagnostic: Its odd that the argument of sizeof() operator is the&itemInfo expression...
Depth=0;    }};The error was found through the V579: diagnostic The memset function receives the pointer and its sizeas ar...
Example 5. VirtualDub project. Array overrun (explicit index).struct ConvoluteFilterData { long m[9]; long bias; void *dyn...
...    findWhat[FINDBUFFLEN] = 0;    ...}The error was found through the V557 diagnostic: Array overrun is possible. The 6...
Example 8. Miranda IM project. Only part of a string is copied.typedef struct _textrangew{    CHARRANGE chrg;    LPWSTR lp...
static voidla_dosmaperr(unsigned long e){    ...    for (i = 0; i < sizeof(doserrors); i++)    {        if (doserrors[i].w...
osvi.dwBuildNumber & 0xFFFF);    ...    sprintf (szOperatingSystem, "%s%s(Build %d)",                szOperatingSystem, os...
...DockingManager::DockingManager(){    ...    memset(_iContMap, -1, CONT_MAP_MAX);    ...}The error was found through the...
...}The error was found through the V554 diagnostic: Incorrect use of auto_ptr. The memory allocated withnew [] will be cl...
by one or not. Two actions of changing pTemp variables value are located in one sequence point. Itmeans that the compiler ...
}The error was found through the V567 diagnostic: Undefined behavior. The s variable is modified whilebeing used twice bet...
{    ...    if (pceltFetched != NULL)      *pceltFetched++;    ...}The error was found through the V532 diagnostic: Consid...
file_info.dwFileAttributes & (0x00000010 != 0);Lets simplify the expression:info->is_directory = file_info.dwFileAttribute...
return;    } else {        if(!original_space_accelerators) return;    }}Example 5. IPP Samples project. Priorities of ?: ...
(den > dgFloat32 (0.0f)) ?               dgFloat32 (1.0f) : dgFloat32 (-1.0f);    ...}The error was found through the V502...
The fprinf() function must print a character of the char type. But the third argument is a character of theWCHAR type. The...
The error was found through the V576 diagnostic: Incorrect format. A different number of actualarguments is expected while...
This is the correct code:t.printf("%10.5f, %10.5f, %10.5f,n             %10.5f, %10.5f, %10.5f,n             %10.5f, %10.5...
...}The error was found through the V570 diagnostic: The mii->cch variable is assigned to itself. user32menu.c 4347The val...
The error was found through the V501 diagnostic: There are identical sub-expressions to the left and tothe right of the &&...
PassRefPtr<Structure>Structure::getterSetterTransition(Structure* structure){    ...    transition->m_propertyStorageCapac...
The error was found through the V568 diagnostic: Its odd that the argument of sizeof() operator is thesizeof (SECURITY_ATT...
}The error was found through the V560 diagnostic: A part of conditional expression is always true: 0xff.notepadPlus babygr...
All the C and C++ programmers know how dangerous an extra semicolon ; is. Unfortunately, thisknowledge does not prevent th...
if (ret=0) {return (0);}    ...}The error was found through the V559 diagnostic: Suspicious assignment inside the conditio...
m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][2];        iRefNum += 1;    }    if (m_pMbInfo->predType[3] & predType)    {   ...
...    q1_allocatedbspmem +=      Q1_MAX_MAP_CLIPNODES * sizeof(q1_dclipnode_t);    ...    q1_allocatedbspmem +=      Q1_M...
Many errors in software are caused by misprints. There are much more errors of this kind thanprogrammers think. We could g...
{    ...    ignoredprops = UTF8ToWide(st.c_str());    // remove all escape chars ()    std::remove(ignoredprops.begin(), i...
The error here is this: the vector::empty() function is called by mistake instead of vector::clear(), and thearrays conten...
...          do {              ...              CTriVertex     *snVertex =              (CTriVertex *)alloca(2*sizeof(CTri...
The memset function handles 0 items, i.e. actually does nothing. The reason is in mixed up arguments.This is how the corre...
{    ...    switch(LOWORD(wParam))    {        case (IDOK || IDCANCEL):          EndDialog(hDlg,TRUE);          return(TRU...
...    lon = (y == 0 && x == 0) ? 0.0 : rtd(atan2(y, x));}The error was found through the V550 diagnostic: An odd precise ...
&& !hasPrefix(doc, length, end, QLatin1String("<td"))        && !hasPrefix(doc, length, end, QLatin1String("</tr"))       ...
{    ...    for (i = 0; i < num_tbl; i++) {        *tbl++;    }    ...}The error was found through the V532 diagnostic: Co...
...}The error was found through the V547 diagnostic: Expression pBytes [ 0 ] == 0xEF is always false. Thevalue range of si...
...    }    ...}The error was found through the V547 diagnostic: Expression * utf8CheckBuf == 0xC0 is always false.The val...
// Socket creation    if ( (m_socketHandle = socket(AF_INET,SOCK_STREAM,0)) < 0)    {        continue;    }    ...}The err...
Example 6. ICU project. Error in condition.U_CDECL_BEGIN static const char* U_CALLCONV_processVariableTop(...){    ...    ...
}The error was found through the V547 diagnostic: Expression --size >= 0 is always true. Unsigned typevalue is always >= 0...
{    ...    if (S_OK)      AddRef();    return hr;}The error was found through the V545 diagnostic: Such conditional expre...
typedef UINT_PTR SOCKET;static unsigned int __stdcall win9x_accept(void * dummy){    SOCKET csd;    ...    do {          c...
...}The error was found through the V517 diagnostic: The use of if (A) {...} else if (A) {...} pattern wasdetected. There ...
{    ...    if (*m_szPassword != 0)Example 2. Chromium project. Null pointer handling.bool ChromeFrameNPAPI::Invoke(...){ ...
}The error was found through the V512 diagnostic: A call of the memset function will lead to a bufferoverflow or underflow...
The error is completely identical to the previous one. The sizeof operator calculates the pointer size. Tofix it, we must ...
if (key_len > 79)    {        png_warning(png_ptr, "keyword length must be 1 - 79 characters");        new_key[79] = 0;   ...
options->delivery_password) {Example 9. Ultimate TCP/IP project. Incorrect handling of empty strings.void CUT_StrMethods::...
...    UINT nOldLength = GetLength();    if (nOldLength < 0)    {        // protects from underflow        nOldLength = 0;...
The error was found through the V547 diagnostic: Expression len < 0 is always false. Unsigned typevalue is never < 0. apru...
}The error has been found with rule V597: The compiler could delete the memset function call, which isused to flush kappa ...
The error was found through the V525 diagnostic: The code containing the collection of similar blocks.Check items 11, 12, ...
Example 3. TortoiseSVN project. File name not corrected.BOOL GetImageHlpVersion(DWORD &dwMS, DWORD &dwLS){    return(GetIn...
void clearBottomUpPointers() {    PerPtrTopDown.clear();}void clearTopDownPointers() {    PerPtrTopDown.clear();}The error...
t=y1; y1=y2; y2=t;Example 6. Crystal Space 3D SDK project. Identical subexpressions.inline_ bool Contains(const LSS& lss){...
Style & w3Style =      _pUserLang->_styleArray.getStyler(STYLE_WORD3_INDEX);    styleUpdate(w3Style, _pFgColour[2], _pBgCo...
...);By mistake, IDC_KEYWORD3_BOLD_CHECK is used instead of IDC_KEYWORD3_ITALIC_CHECK.Example 8. ReactOS object. Choosing ...
m_pContext->m_seqLayerHeader->heightMB)    ...}The error was found through the V501 diagnostic: There are identical sub-ex...
standard situation. Instead of correctly processing a null pointer in normal mode, an Access Violationwill occur and an ex...
If buf equals NULL, an exception will be thrown instead of returning the error code. And if exceptionsare not used, the pr...
The error has been found with rule V595: The player pointer was utilized before it was verified againstnullptr. Check line...
Example 2. IPP Samples project. One variable for two loops.JERRCODE CJPEGDecoder::DecodeScanBaselineNI(void){    ...    fo...
int Notepad_plus::getHtmlXmlEncoding(....) const{    ...    if (langT != L_XML && langT != L_HTML && langT == L_PHP)     r...
Upcoming SlideShare
Loading in...5
×

100 bugs in Open Source C/C++ projects

1,021

Published on

This article demonstrates capabilities of the static code analysis methodology. The readers are offered to study the samples of one hundred errors found in open-source projects in C/C++.

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
1,021
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
11
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

100 bugs in Open Source C/C++ projects

  1. 1. 100 bugs in Open Source C/C++ projectsAuthors: Andrey Karpov, Evgeniy RyzhkovDate: 16.03.2012AbstractThis article demonstrates capabilities of the static code analysis methodology. The readers are offeredto study the samples of one hundred errors found in open-source projects in C/C++. All the errors havebeen found with the PVS-Studio static code analyzer.IntroductionWe wont tire you programmers by making you read texts and will pass to the error samples right away.Those who want to know what static code analysis is, please follow the link. Those who want to knowwhat PVS-Studio is and download the trial version, see this page: http://www.viva64.com/en/pvs-studio/.Yes, one more thing. Please see our post "FAQ for those who have read our articles".Samples of errors detected in various open-source projectsThe samples of detected errors will be divided into several groups. This division is rather relative. Oneand the same error can often be referred to misprints and incorrect array handling at a time.Of course, we have taken just a few errors from each of the projects. If we described all the founddefects, it would be a reference book. This is the list of analyzed projects: • Apache HTTP Server - http://httpd.apache.org/ • Audacity - http://audacity.sourceforge.net/ • Chromium - http://www.chromium.org/ • Clang - http://clang-analyzer.llvm.org/ • CMake - http://www.cmake.org/ • Crystal Space 3D SDK - http://www.crystalspace3d.org/main/Main_Page • Emule - http://www.emule.com/ • FAR Manager - http://www.farmanager.com/ • FCE Ultra - http://fceux.com/web/home.html
  2. 2. • Fennec Media Project - http://fennec.sourceforge.net/ • G3D Content Pak - http://sourceforge.net/projects/g3d-cpp/ • IPP Samples - http://www.viva64.com/go.php?url=449 • Lugaru - http://www.wolfire.com/lugaru • Miranda IM - http://www.miranda-im.org/ • MySQL - http://www.mysql.com/ • Newton Game Dynamics - http://newtondynamics.com/forum/newton.php • Notepad++ - http://notepad-plus-plus.org/ • Pixie - http://www.renderpixie.com/ • PNG library - http://libpng.org/pub/png/ • QT - http://qt.nokia.com/products/ • ReactOS - http://www.reactos.org/en/ • Shareaza - http://www.shareaza.com/ • SMTP Client with SSL/TLS - http://www.codeproject.com/KB/IP/smtp_ssl.aspx • StrongDC++ - http://strongdc.sourceforge.net/index.php?lang=eng • Swiss-Army Knife of Trace - http://www.codeproject.com/KB/trace/tracetool.aspx • TortoiseSVN - http://tortoisesvn.net/ • Ultimate TCP/IP - http://www.codeproject.com/KB/MFC/UltimateTCPIP.aspx • VirtualDub - http://www.virtualdub.org/ • WinDjView - http://windjview.sourceforge.net/ • WinMerge - http://winmerge.org/ • Wolfenstein 3D - http://en.wikipedia.org/wiki/Wolfenstein_3D • Crypto++ - http://www.cryptopp.com/ • Quake-III-Arena - https://github.com/id-Software/Quake-III-Arena • And some others.Errors of array and string handlingErrors of array and string handling are the largest class of defects in C/C++ programs. This is the price forthe capability of effective low-level memory handling available to programmers. In the article we willshow just a small part of these errors found by the PVS-Studio analyzer. But we think any C/C++programmer understands how numerous and insidious they are.Example 1. Wolfenstein 3D project. Only part of an object is cleared.void CG_RegisterItemVisuals( int itemNum ) { ... itemInfo_t *itemInfo; ... memset( itemInfo, 0, sizeof( &itemInfo ) ); ...}
  3. 3. The error was found through the V568 diagnostic: Its odd that the argument of sizeof() operator is the&itemInfo expression. cgame cg_weapons.c 1467.The sizeof() operator calculates the size of the pointer instead of the itemInfo_t structures size. It is"sizeof(*itemInfo)" that must be written.Example 2. Wolfenstein 3D project. Only part of a matrix is cleared.ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { memcpy( mat, src, sizeof( src ) );}The error was found through the V511: The sizeof() operator returns size of the pointer, and not of thearray, in sizeof(src) expression. Splines math_matrix.h 94Usually programmers expect sizeof(src) to return the size of an array equal to "3*3*sizeof(float)" bytes.But according to the language standard, src is just a pointer, not an array. Thus, the matrix will becopied only partly. The memcpy function will copy 4 or 8 bytes (the pointer size) depending on whetherthe code is 32-bit or 64-bit.If you want the whole matrix to be copied, you may pass a reference to the array into the function. Thisis the correct code:ID_INLINE mat3_t::mat3_t( float (&src)[3][3] ){ memcpy( mat, src, sizeof( src ) );}Example 3. FAR Manager project. Only part of an array is cleared.struct TreeItem{ int *Last; size_t LastCount; ... void Clear() { strName.Clear(); memset(Last, 0, sizeof(Last));
  4. 4. Depth=0; }};The error was found through the V579: diagnostic The memset function receives the pointer and its sizeas arguments. It is probably a mistake. Inspect the third argument. far treelist.hpp 66Most likely, there is a missing operation of multiplication by the number of items being cleared, and thecode must look as follows: "memset(Last, 0, LastCount * sizeof(Last));".Example 4. ReactOS project. Incorrect calculation of a string length.static const PCHAR Nv11Board = "NV11 (GeForce2) Board";static const PCHAR Nv11Chip = "Chip Rev B2";static const PCHAR Nv11Vendor = "NVidia Corporation";BOOLEANIsVesaBiosOk(...){ ... if (!(strncmp(Vendor, Nv11Vendor, sizeof(Nv11Vendor))) && !(strncmp(Product, Nv11Board, sizeof(Nv11Board))) && !(strncmp(Revision, Nv11Chip, sizeof(Nv11Chip))) && (OemRevision == 0x311)) ...}The error was found through the V579 diagnostic: The strncmp function receives the pointer and its sizeas arguments. It is probably a mistake. Inspect the third argument. vga vbe.c 57Calls of the strncmp function in this code compare only the first several characters, not whole strings.The error here is this: the sizeof() operator, absolutely inappropriate in this situation, is used to calculatestring lengths. The sizeof() operator actually calculates the pointer size instead of the number of bytes ina string.What is the most unpleasant and insidious about this error is that this code almost works as intended. In99% of cases, comparison of the first several characters is enough. But the remaining 1% can bring youmuch fun and long debugging.
  5. 5. Example 5. VirtualDub project. Array overrun (explicit index).struct ConvoluteFilterData { long m[9]; 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]; ...}The code was found through the V557 diagnostic: Array overrun is possible. The 9 index is pointingbeyond array bound. VirtualDub f_convolute.cpp 73It is not a real error, but good diagnostic. Explanation: http://www.viva64.com/go.php?url=756.Example 6. CPU Identifying Tool project. Array overrun (index in a macro).#define FINDBUFFLEN 64 // Max buffer find/replace size...int WINAPI Sticky (...){ ... static char findWhat[FINDBUFFLEN] = {0};
  6. 6. ... findWhat[FINDBUFFLEN] = 0; ...}The error was found through the V557 diagnostic: Array overrun is possible. The 64 index is pointingbeyond array bound. stickies stickies.cpp 7947This error is a kind of the previous one. The terminal null is written outside the array. The correct codeis: "findWhat[FINDBUFFLEN - 1] = 0;".Example 7. Wolfenstein 3D project. Array overrun (incorrect expression).typedef struct bot_state_s{ ... char teamleader[32]; //netname of the team leader ...} bot_state_t;void BotTeamAI( bot_state_t *bs ) { ... bs->teamleader[sizeof( bs->teamleader )] = 0; ...}The error was found through the V557 diagnostic: Array overrun is possible. The sizeof (bs->teamleader) index is pointing beyond array bound. game ai_team.c 548Here is one more example of an array overrun when using an explicitly declared index. These samplesshow that such simple at first sight errors are much more widely-spread than it may seem.The terminal null is written outside the teamleader array. This is the correct code:bs->teamleader[ sizeof(bs->teamleader) / sizeof(bs->teamleader[0]) - 1 ] = 0;
  7. 7. Example 8. Miranda IM project. Only part of a string is copied.typedef struct _textrangew{ CHARRANGE chrg; LPWSTR lpstrText;} TEXTRANGEW;const wchar_t* Utils::extractURLFromRichEdit(...){ ... ::CopyMemory(tr.lpstrText, L"mailto:", 7); ...}The error was found through the V512 diagnostic: A call of the memcpy function will lead to a bufferoverflow or underflow. tabsrmm utils.cpp 1080If Unicode-strings are used, one character occupies 2 or 4 bytes (depending on the data model beingused in compiler) instead of one byte. Unfortunately, programmers easily forget about it, and you canoften see defects like our example in programs.The CopyMemory function will copy only part of the L"mailto:" string since it handles bytes, notcharacters. You can fix the code by using a more appropriate function for string copying or, at least,multiplying number 7 by sizeof(wchar_t).Example 9. CMake project. Array overrun inside a loop.static const struct { DWORD winerr; int doserr;} doserrors[] ={ ...};
  8. 8. static voidla_dosmaperr(unsigned long e){ ... for (i = 0; i < sizeof(doserrors); i++) { if (doserrors[i].winerr == e) { errno = doserrors[i].doserr; return; } } ...}The error was found through the V557 diagnostic: Array overrun is possible. The value of i index couldreach 367. cmlibarchive archive_windows.c 1140, 1142The error handler itself contains an error. The sizeof() operator returns the array size in bytes and notthe number of items inside it. As a result, the program will try to search much more items than it shouldin the loop. This is the correct loop:for (i = 0; i < sizeof(doserrors) / sizeof(*doserrors); i++)Example 10. CPU Identifying Tool project. A string is printed into itself.char * OSDetection (){ ... sprintf(szOperatingSystem, "%sversion %d.%d %s (Build %d)", szOperatingSystem, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion,
  9. 9. osvi.dwBuildNumber & 0xFFFF); ... sprintf (szOperatingSystem, "%s%s(Build %d)", szOperatingSystem, osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF); ...}This error was found through the V541 diagnostic: It is dangerous to print the string szOperatingSysteminto itself. stickies camel.cpp 572, 603An attempt of formatted printing of a string into itself can lead to bad consequences. The result ofexecuting this code depends on the input data, and you cannot predict what will happen. Most likely,the result will be a meaningless string or an Access Violation will occur.This error can be referred to the category "code vulnerabilities". In some programs, by feeding specialdata to code, you can exploit such code fragments to cause a buffer overflow or other effects anintruder needs.Example 11. FCE Ultra project. A string gets less memory than needed.int FCEUI_SetCheat(...){ ... if((t=(char *)realloc(next->name,strlen(name+1)))) ...}The error was found through the V518 diagnostic: The realloc function allocates strange amount ofmemory calculated by strlen(expr). Perhaps the correct variant is strlen(expr) + 1. fceux cheat.cpp 609This error is caused by a misprint. It is the name pointer instead of the "name+1" expression that mustbe the argument of the strlen() function. As a result, the realloc function allocates 2 bytes less memorythan needed: one byte is lost because 1 is not added to the string length; another byte is lost becausethe strlen function calculates the string length skipping the first character.Example 12. Notepad++ project. Partial array clearing.#define CONT_MAP_MAX 50int _iContMap[CONT_MAP_MAX];
  10. 10. ...DockingManager::DockingManager(){ ... memset(_iContMap, -1, CONT_MAP_MAX); ...}The error was found through the V512 diagnostic: A call of the memset function will lead to a bufferoverflow or underflow. notepadPlus DockingManager.cpp 60Thats one more example of how the number of array items is mixed up with an array size. Amultiplication by sizeof(int) is missing.We can go on and on showing you errors of array handling we have found in various programs. But wehave to stop somewhere.Undefined behaviorA bit of theory at first.Undefined behavior is a property of certain programming languages (most prominent in C and C++) toproduce a result in certain situations that depends on compiler implementation or specifiedoptimization switches. In other words, the specification does not define the languages behavior in anypossible situations but says: "at A condition, the result of B operation is undefined". It is considered amistake to allow such a situation in your program even if it is executed well at some particular compiler.Such a program will not be crossplatform and may cause failures on a different computer, operatingsystem and even at different compilers settings.A sequence point in programming is any point in a program where it is guaranteed that the side effectsof all the previous calculations have already emerged while there are no side effects of the followingcalculations yet. To learn more about sequence points and cases of undefined behavior related tosequence points, see this post: http://www.viva64.com/en/t/0065/.Example 1. Chromium project. Incorrect use of smart pointer.void AccessibleContainsAccessible(...){ ... auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
  11. 11. ...}The error was found through the V554 diagnostic: Incorrect use of auto_ptr. The memory allocated withnew [] will be cleaned using delete. interactive_ui_tests accessibility_win_browsertest.cc 171This example demonstrates the case when using a smart pointer can cause undefined behavior. It maybe expressed through heap damage, program crash, incomplete object destruction or any other failure.The error is this: memory is allocated by the new [] operator and released by the delete operator in theauto_ptr class destructor:~auto_ptr() { delete _Myptr;}To fix these issues, you should use a more appropriate class, for instance, boost::scoped_array.Example 2. IPP Samples project. Classic Undefined behavior.template<typename T, Ipp32s size> 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++; ... } ...}The error was found through the V567 diagnostic: Undefined behavior. The pTemp variable is modifiedwhile being used twice between sequence points. me umc_me_cost_func.h 168This is a classic example of undefined program behavior. It is this construct which is used todemonstrate Undefined behavior in various articles. It is unknown whether pTemp will be incremented
  12. 12. by one or not. Two actions of changing pTemp variables value are located in one sequence point. Itmeans that the compiler may create the following code:pTemp = pTemp + 1;pTemp = pTemp;Or it may create another version of the code:TMP = pTemp;pTemp = pTemp + 1;pTemp = TMP;Which of the two code versions will be created depends on the compiler and optimization switches.Example 3. Fennec Media Project project. Complex expression.uint32 CUnBitArrayOld::DecodeValueRiceUnsigned(uint32 k){ ... while (!(m_pBitArray[m_nCurrentBitIndex >> 5] & Powers_of_Two_Reversed[m_nCurrentBitIndex++ & 31])) {} ...}The error was found through the V567 diagnostic: Undefined behavior. The m_nCurrentBitIndexvariable is modified while being used twice at single sequence point. MACLib unbitarrayold.cpp 78There are no sequence points between two instances of using the m_nCurrentBitIndex variable. Itmeans that the standard does not specify the moment when this variable is incremented.Correspondingly, this code may work differently depending on the compiler and optimization switches.Example 4. Miranda IM project. Complex expression.short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len){ ... while (*(n = ++s + strspn(s, EZXML_WS)) && *n != >) { ...
  13. 13. }The error was found through the V567 diagnostic: Undefined behavior. The s variable is modified whilebeing used twice between sequence points.msne zxml.c 371Prefix increment of the variable is used here. But it does not mean anything: it cannot be guaranteedthat the s variable will be incremented before calling the strspn() function.Errors relating to operation priorities.To make understanding of examples easier, lets recall the operation priorities table.Example 1. MySQL project. Priorities of ! and & operations.int ha_innobase::create(...){ ... if (srv_file_per_table && !mysqld_embedded && (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) { ...}The error was found through the V564 diagnostic: The & operator is applied to bool type value. Youveprobably forgotten to include parentheses or intended to use the && operator. innobase ha_innodb.cc6789The programmer wanted a part of the expression to check that a certain bit in the create_info->optionsvariable is equal to zero. But the priority of the ! operation is higher than that of the & operation,thats why the expression works by this algorithm:((!create_info->options) & HA_LEX_CREATE_TMP_TABLE)We should use additional parentheses if we want the code to work properly:(!(create_info->options & HA_LEX_CREATE_TMP_TABLE))Or, what we find nicer, write the code in the following way:((create_info->options & HA_LEX_CREATE_TMP_TABLE) == 0)Example 2. Emule project. Priorities of * and ++ operations.STDMETHODIMPCCustomAutoComplete::Next(..., ULONG *pceltFetched)
  14. 14. { ... if (pceltFetched != NULL) *pceltFetched++; ...}The error was found through the V532 diagnostic: Consider inspecting the statement of *pointer++pattern. Probably meant: (*pointer)++. emule customautocomplete.cpp 277If pceltFetched is not a null pointer, the function must increment the variable of the ULONG type thispointer refers to. The error is this: the priority of the ++ operation is higher than that of * operation(pointer dereferencing). The "*pceltFetched++;" line is identical to the following code:TMP = pceltFetched + 1;*pceltFetched;pceltFetched = TMP;Virtually it is just increment of the pointer. To make the code correct, we must add parentheses:"(*pceltFetched)++;".Example 3. Chromium project. Priorities of & and != operations.#define FILE_ATTRIBUTE_DIRECTORY 0x00000010bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { ... info->is_directory = file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0; ...}The error was found through the V564 diagnostic: The & operator is applied to bool type value. Youveprobably forgotten to include parentheses or intended to use the && operator. baseplatform_file_win.cc 216Programmers easily forget that the priority of the != operation is higher than that of &. This is whathappened in our case. As a result, we have the following expression:info->is_directory =
  15. 15. file_info.dwFileAttributes & (0x00000010 != 0);Lets simplify the expression:info->is_directory = file_info.dwFileAttributes & (true);Lets simplify it once again:info->is_directory = file_info.dwFileAttributes & 1;It turns out that we have tested the first bit instead of the fifth bit. To fix this, we need to addparentheses.Example 4. BCmenu project. IF and ELSE mixed up.void BCMenu::InsertSpaces(void){ if(IsLunaMenuStyle()) if(!xp_space_accelerators) return; else if(!original_space_accelerators) return; ...}The error was found through the V563 diagnostic: It is possible that this else branch must apply to theprevious if statement. fire bcmenu.cpp 1853This is not an error of operation priorities, but one relative to it. The programmer does not take intoaccount that the else branch refers to the nearest if operator. We can see that the code justificationas if it works by the following algorithm:if(IsLunaMenuStyle()) { if(!xp_space_accelerators) return;} else { if(!original_space_accelerators) return;}But actually it is equivalent to the following construct:if(IsLunaMenuStyle()){ if(!xp_space_accelerators) {
  16. 16. return; } else { if(!original_space_accelerators) return; }}Example 5. IPP Samples project. Priorities of ?: and | operations.vm_file* vm_file_fopen(...){ ... mds[3] = FILE_ATTRIBUTE_NORMAL | (islog == 0) ? 0 : FILE_FLAG_NO_BUFFERING; ...}The error was found through the V502 diagnostic: Perhaps the ?: operator works in a different waythan it was expected. The ?: operator has a lower priority than the | operator. vm vm_file_win.c 393Depending on the islog variables value, the expression must be either equal to"FILE_ATTRIBUTE_NORMAL" or "FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING". But it doesnot happen. Priority of the ?: operation is lower than that of |. As a result, the code acts as follows:mds[3] = (FILE_ATTRIBUTE_NORMAL | (islog == 0)) ? 0 : FILE_FLAG_NO_BUFFERING;Lets simplify the expression:mds[3] = (0x00000080 | ...) ? 0 : FILE_FLAG_NO_BUFFERING;Since FILE_ATTRIBUTE_NORMAL equals 0x00000080, the condition is always true. It means that 0 willalways be written into mds[3].Example 6. Newton Game Dynamics project. Priorities of ?: and * operations.dgInt32 CalculateConvexShapeIntersection (...){ ... den = dgFloat32 (1.0e-24f) *
  17. 17. (den > dgFloat32 (0.0f)) ? dgFloat32 (1.0f) : dgFloat32 (-1.0f); ...}The error was found through the V502 diagnostic: Perhaps the ?: operator works in a different waythan it was expected. The ?: operator has a lower priority than the * operator. physicsdgminkowskiconv.cpp 1061The error in this code again relates to the low priority of the ?: operation. The condition for the ?:operator is expressed by a meaningless subexpression "dgFloat32 (1.0e-24f) * (den > dgFloat32 (0.0f))".Adding parentheses will solve the issue.By the way, programmers often forget how cunning the ?: operator is. Here is a post on this topic:"How to make fewer errors at the stage of code writing. Part N2".Formatted output errorsExamples of these errors are boring and alike, so we will examine only a few samples. The point is thatfunctions with a variable number of arguments accept actual arguments incompatible with the formatstring. Any programmer who uses such functions as printf() is familiar with this type of errors.Example 1. ReactOS project. Incorrect printing of a WCHAR-character.static void REGPROC_unescape_string(WCHAR* str){ ... default: fprintf(stderr, "Warning! Unrecognized escape sequence: %cn", str[str_idx]); ...}The error was found through the V576 diagnostic: Incorrect format. Consider checking the third actualargument of the fprintf function. The char type argument is expected. regedit regproc.c 293
  18. 18. The fprinf() function must print a character of the char type. But the third argument is a character of theWCHAR type. The user will get an incorrectly generated message. To fix the code, we should replace %cwith %C in the format string.Example 2. Intel AMT SDK project. Character % missing.void addAttribute(...){ ... int index = _snprintf(temp, 1023, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" "%02x%02x:02x%02x:%02x%02x:%02x%02x", value[0],value[1],value[2],value[3],value[4], value[5],value[6],value[7],value[8], value[9],value[10],value[11],value[12], value[13],value[14],value[15]); ...}The error was found through the V576 diagnostic: Incorrect format. A different number of actualarguments is expected while calling _snprintf function. Expected: 18. Present: 19. mod_pvsmod_pvs.cpp 308It is not easy to find an error here at first sight. However, the PVS-Studio analyzer does not get tired andnotices that the function takes more actual arguments than specified in the format string. The reason isthat the % character is missing in one place. Lets single out this fragment:"%02x%02x:[HERE]02x%02x:%02x%02x:%02x%02x",Example 3. Intel AMT SDK project. Unused argument.bool GetUserValues(...){ ... printf("Error: illegal value. Aborting.n", tmp); return false;}
  19. 19. The error was found through the V576 diagnostic: Incorrect format. A different number of actualarguments is expected while calling printf function. Expected: 1. Present: 2. RemoteControlSampleremotecontrolsample.cpp 792The error is this: the tmp variable is not used in any way when printing the information message.Example 4. G3D Content Pak project. Printing of meaningless data.class Matrix3 { ... inline float* operator[] (int iRow) { ...};void AnyVal::serialize(G3D::TextOutput& t) const { ... const Matrix3& m = *(Matrix3*)m_value; ... t.printf("%10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f)", m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2]); ...}The error was found through the V520 diagnostic: The comma operator , in array index expression [0,0]. graphics3D anyval.cpp 275The program prints meaningless values instead of the matrix. You may write such a code when you workwith different programming languages and sometimes forget how to access an item in a two-dimensional array in the C language.Lets see how the m[0, 1] expression works. At first, expression"0, 1" is calculated. The result of thisexpression is 1. Then the operator[] function is called in the Matrix3 class. The function takes the actualargument 1 and returns the pointer to the first string in the matrix. It is the value of this pointer that willbe printed by the printf() function though it expects a value of the float-type.
  20. 20. This is the correct code:t.printf("%10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f)", m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2]);Examples of misprints found in codeA lot of programming errors are caused by misprints. Most of these errors are quickly detected at theearly stages of testing. But there are some defects of this kind that remain in code for a long timecausing troubles both to programmers and users.You can make these errors much fewer using the PVS-Studio analyzer. It will find them before testingstarts, which will significantly reduce the cost of defect detection and elimination.Example 1. Miranda IM project. Assignment inside IF.void CIcqProto::handleUserOffline(BYTE *buf, WORD wLen){ ... else if (wTLVType = 0x29 && wTLVLen == sizeof(DWORD)) ...}The error was found through the V560 diagnostic: A part of conditional expression is always true: 0x29.icqoscar8 fam_03buddy.cpp 632Because of a misprint, there is an assignment taking place inside the condition of the if operator. This isthe correct condition: "if (wTLVType == 0x29 && wTLVLen == sizeof(DWORD))".Example 2. ReactOS project. Assignment error.BOOL WINAPI GetMenuItemInfoA(...){ ... mii->cch = mii->cch;
  21. 21. ...}The error was found through the V570 diagnostic: The mii->cch variable is assigned to itself. user32menu.c 4347The value of the variable is assigned to itself. The programmer apparently intended to write it in thisway: "mii->cch = miiW->cch;".Example 3. Clang project. Object name misprinted.static Value *SimplifyICmpInst(...) { ... case Instruction::Shl: { bool NUW = LBO->hasNoUnsignedWrap() && LBO->hasNoUnsignedWrap(); bool NSW = LBO->hasNoSignedWrap() && RBO->hasNoSignedWrap(); ...}The error was found through the V501 diagnostic: There are identical sub-expressions LBO->hasNoUnsignedWrap () to the left and to the right of the && operator. LLVMAnalysisinstructionsimplify.cpp 1891There is a misprint when using variables with similar names. In the first line, both LBO and RBO variablesmust be used. This is the correct code:bool NUW = LBO->hasNoUnsignedWrap() && RBO->hasNoUnsignedWrap();Example 4. Notepad++ project. Incorrect state test.bool _isPointXValid;bool _isPointYValid;...bool isPointValid() { return _isPointXValid && _isPointXValid;};
  22. 22. The error was found through the V501 diagnostic: There are identical sub-expressions to the left and tothe right of the && operator. _isPointXValid && _isPointXValidThe name _isPointXValid is used twice. The function must actually return this code: "_isPointXValid &&_isPointYValid".Example 5. StrongDC++ project. Unsuccessful check of rn.static void getContentLengthAndHeaderLength(...){ ... while(line[linelen] != r && line[linelen] != r) ...}The error was found through the V501 diagnostic: There are identical sub-expressions line [linelen] !=r to the left and to the right of the && operator. miniupnpc miniupnpc.c 153Because of a misprint, presence of the r character is checked twice. Actually presence of the ncharacter must be checked too.Example 6. G3D Content Pak project. A closing parenthesis in a wrong place.bool Matrix4::operator==(const Matrix4& other) const { if (memcmp(this, &other, sizeof(Matrix4) == 0)) { return true; } ...}The error was found through the V575 diagnostic: The memcmp function processes 0 elements.Inspect the third argument. graphics3D matrix4.cpp 269One closing parenthesis is in a wrong place. It turns out that the size of the memory area beingcompared is calculated by the "sizeof(Matrix4) == 0" expression. This expression always has the falseresult. Then false turns into an integer value equal to 0. This is the correct code:if (memcmp(this, &other, sizeof(Matrix4)) == 0) {Example 7. QT project. Error of structure member copying.
  23. 23. PassRefPtr<Structure>Structure::getterSetterTransition(Structure* structure){ ... transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties; transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; ...}The error was found through the V570 diagnostic: The transition->m_hasGetterSetterPropertiesvariable is assigned to itself. QtScript structure.cpp 512It is not easy to find an error looking at this code. But it is there. The field m_hasGetterSetterPropertiesis copied into itself. This is the correct code:transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties;Example 8. Apache HTTP Server project. Extra sizeof operator.PSECURITY_ATTRIBUTES GetNullACL(void){ PSECURITY_ATTRIBUTES sa; sa = (PSECURITY_ATTRIBUTES) LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)); sa->nLength = sizeof(sizeof(SECURITY_ATTRIBUTES)); ...}
  24. 24. The error was found through the V568 diagnostic: Its odd that the argument of sizeof() operator is thesizeof (SECURITY_ATTRIBUTES) expression. libhttpd util_win32.c 115The field nLength must contain the size of the SECURITY_ATTRIBUTES structure. There is a misprint inthe code: the sizeof operator is used twice. As a result, the field nLength stores a size of the size_ttype. This is the correct code:sa->nLength = sizeof(SECURITY_ATTRIBUTES);Example 9. FCE Ultra project. Double variable declaration.int iNesSaveAs(char* name){ ... fp = fopen(name,"wb"); int x = 0; if (!fp) int x = 1; ...}The error was found through the V561 diagnostic: Its probably better to assign value to x variable thanto declare it anew. Previous daclaration: ines.cpp, line 960. fceuxines.cpp 962The x variable must store information whether or not a file was opened successfully. Because of amisprint, a new variable named x is created and initialized instead of assigning 1 to the existingvariable. This is how the correct code must look:if (!fp) x = 1;Example 10. Notepad++ project. Using && operator instead of &.TCHAR GetASCII(WPARAM wParam, LPARAM lParam){ ... result=ToAscii(wParam, (lParam >> 16) && 0xff, keys,&dwReturnedValue,0); ...
  25. 25. }The error was found through the V560 diagnostic: A part of conditional expression is always true: 0xff.notepadPlus babygrid.cpp 694The "(lParam >> 16) && 0xff" expression is meaningless and is always equal to 1 (true). A misprint hereis in using the && operator instead of &.Example 11. WinDjView project. Incomplete condition.inline bool IsValidChar(int c){ return c == 0x9 || 0xA || c == 0xD || c >= 0x20 && c <= 0xD7FF || c >= 0xE000 && c <= 0xFFFD || c >= 0x10000 && c <= 0x10FFFF;}The error was found through the V560 diagnostic: A part of conditional expression is always true: 0xA.WinDjView xmlparser.cpp 45 FalseThe IsValidChar function always returns true. Comparison is missing in one place because of a misprint:"... || 0xA || ...".Example 12. Fennec Media Project project. Extra semicolon.int settings_default(void){ ... for(i=0; i<16; i++); for(j=0; j<32; j++) { settings.conversion.equalizer_bands.boost[i][j] = 0.0; settings.conversion.equalizer_bands.preamp[i] = 0.0; }}The error was found through the V529 diagnostic: Odd semicolon ; after for operator. settings.c 483
  26. 26. All the C and C++ programmers know how dangerous an extra semicolon ; is. Unfortunately, thisknowledge does not prevent them from making such misprints. There is an extra semicolon after thefirst for operator, which makes this program fragment unable to execute.Example 13. QT project. Missing break operator.int QCleanlooksStyle::pixelMetric(...){ ... case PM_SpinBoxFrameWidth: ret = 3; break; case PM_MenuBarItemSpacing: ret = 6; case PM_MenuBarHMargin: ret = 0; break; ...}The error was found through the V519 diagnostic: The ret variable is assigned values twice successively.Perhaps this is a mistake. Check lines: 3765, 3767. QtGui qcleanlooksstyle.cpp 3767This is a classic error - break is missing inside the switch operator. I think you do not need any furthercomments here.Example 14. Miranda IM project. Assignment instead of comparison.int FindItem(...){ ... int ret; ret=FindItem(hwnd,dat,hItem, (struct ClcContact ** )&z, (struct ClcGroup ** )&isv,NULL);
  27. 27. if (ret=0) {return (0);} ...}The error was found through the V559 diagnostic: Suspicious assignment inside the condition expressionof if operator: ret = 0. clist_mw clcidents.c 179There is a misprint inside the condition of the if operator: = is written instead of ==. The function willhandle the situation incorrectly when a certain item is not found.Example 15. IPP Samples project. Incorrect index.struct AVS_MB_INFO{ ... Ipp8u refIdx[AVS_DIRECTIONS][4]; ...};void AVSCompressor::GetRefIndiciesBSlice(void){ ... if (m_pMbInfo->predType[0] & predType) { m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][0]; iRefNum += 1; } if (m_pMbInfo->predType[1] & predType) { m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][1]; iRefNum += 1; } if (m_pMbInfo->predType[2] & predType) {
  28. 28. m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][2]; iRefNum += 1; } if (m_pMbInfo->predType[3] & predType) { m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][30]; iRefNum += 1; } ...}The error was found through the V557 diagnostic: Array overrun is possible. The 30 index is pointingbeyond array bound. avs_enc umc_avs_enc_compressor_enc_b.cpp 495Consider this fragment: "m_pMbInfo->refIdx[dir][30]". Because of a misprint, number 30 is writteninstead of index 3. By the way, this sample shows well how relative our division of errors into categoriesis. This error might well be referred to the category "Errors of array and string handling". The division isrelative and is made to show diversity of errors the PVS-Studio analyzer can detect.Example 16. ReactOS project. Misprint in a macro.#define SWAP(a,b,c) c = a; a = b; a = cThe error was found through the V519 diagnostic: The v2 variable is assigned values twice successively.Perhaps this is a mistake. Check lines: 343, 343. win32k gradient.c 343It is a rather funny misprint in a macro intended to swap values in two variables. Look closely at the codeand you will see what I mean. This is the correct code:#define SWAP(a,b,c) c = a; a = b; b = cExample 17. Quake-III-Arena project. Misprint. Comma instead of multiplication operator.void Q1_AllocMaxBSP(void){
  29. 29. ... q1_allocatedbspmem += Q1_MAX_MAP_CLIPNODES * sizeof(q1_dclipnode_t); ... q1_allocatedbspmem += Q1_MAX_MAP_EDGES , sizeof(q1_dedge_t); ... q1_allocatedbspmem += Q1_MAX_MAP_MARKSURFACES * sizeof(unsigned short); ...}The error has been found with rule V521: Such expressions using the , operator are dangerous. Makesure the expression is correct. bspc l_bsp_q1.c 136Its a funny misprint. Look at the line in the middle of the code. , written instead of *. As a result, thesizeof(q1_dedge_t) value is always added to the q1_allocatedbspmem variable. I have no suggestionshow this misprint could have occurred.Example 18. LibXml project. Misprint =+.static intxmlXPathCompOpEvalFirst(...){ ... total += xmlXPathCompOpEvalFirst(...); ... total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first); ...}The error has been found with rule V588: The expression of the A =+ B kind is utilized. Considerreviewing it, as it is possible that A += B was meant. libxml xpath.c 12676In one place, "=+" is written instead of "+=" by mistake. They look similar but the result is quite different.Such errors are rather difficult to find just reviewing the code.
  30. 30. Many errors in software are caused by misprints. There are much more errors of this kind thanprogrammers think. We could go on and on in this section but we decide to stop at the 18-th example atlast.Incorrect use of base functions and classesExample 1. Fennec Media Project. Two terminal nulls absent.int JoiningProc(HWND hwnd,UINT uMsg, WPARAM wParam,LPARAM lParam){ ... OPENFILENAME lofn; memset(&lofn, 0, sizeof(lofn)); ... lofn.lpstrFilter = uni("All Files (*.*)0*.*"); ...}The error was found through the V540 diagnostic: Member lpstrFilter should point to string terminatedby two 0 characters. base windows.c 5309In Windows API there are structures in which pointers to strings must end with two null characters. It isthat very kind of string the lpstrFilter member in the OPENFILENAME structure points to.Description of lpstrFilter in MSDN:LPCTSTRA buffer containing pairs of null-terminated filter strings. The last string in the buffer must be terminatedby two NULL characters.If you forget to write an additional null at the end, the dialogue of file handling may contain garbage inthe filter fields. This is the correct code:lofn.lpstrFilter = uni("All Files (*.*)0*.*0");Example 2. TortoiseSVN project. Incorrect use of remove function.STDMETHODIMP CShellExt::Initialize(....)
  31. 31. { ... ignoredprops = UTF8ToWide(st.c_str()); // remove all escape chars () std::remove(ignoredprops.begin(), ignoredprops.end(), ); break; ...}The error was found through the V530 diagnostic: The return value of function remove is required tobe utilized. contextmenu.cpp 442The std::remove function does not remove items from the container. It only shifts the items and returnsthe iterator to the beginning of trash. Assume we have a vector<int> container that contains items1,2,3,1,2,3,1,2,3. If we execute the code "remove( v.begin(), v.end(), 2 )", the container will containitems 1,3,1,3,X,X,X, where X is some trash. The function will return the iterator to the first trash item, soif we want to remove these trash items, we need to write the code: "v.erase(remove(v.begin(), v.end(),2), v.end())".Example 3. TortoiseSVN project. Using empty function instead of clear.CMailMsg& CMailMsg::SetFrom(string sAddress, string sName){ if (initIfNeeded()) { // only one sender allowed if (m_from.size()) m_from.empty(); m_from.push_back(TStrStrPair(sAddress,sName)); } return *this;}The error was found through the V530 diagnostic: The return value of function empty is required to beutilized. mailmsg.cpp 40
  32. 32. The error here is this: the vector::empty() function is called by mistake instead of vector::clear(), and thearrays contents remain the same. It is a very frequent error because the words clear and empty arerather close in meaning, and you might easily mix them up.Example 4. WinMerge project. Using empty function instead of clear.void 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(); } else { ... }}The error was found through the V530 diagnostic: The return value of function empty is required to beutilized WinMerge DirActions.cpp 1307, 1308Again, the reason is in using the empty() function instead of clear(). We could cite examples of sucherrors from other projects as well: InstantVNC, IPP Samples, Chromium, Intel AMT SDK, etc.Unfortunately, all these samples are alike, and there is nothing interesting about examining them. Buttrust me, you can see these defects in serious projects developed by professional programmers.Example 5. Pixie project. Using alloca function inside loops.inline void triangulatePolygon(...) { ... for (i=1;i<nloops;i++) { ... do {
  33. 33. ... do { ... CTriVertex *snVertex = (CTriVertex *)alloca(2*sizeof(CTriVertex)); ... } while(dVertex != loops[0]); ... } while(sVertex != loops[i]); ... } ...}The error was found through the V505 diagnostic: The alloca function is used inside the loop. This canquickly overflow stack. ri polygons.cpp 1120The alloca function allocates memory inside the stack, so calling it many times inside the loop body maysuddenly cause a stack overflow. And we have several nested loops here. This code may exhaust stackmemory very quickly.Example 6. Miranda IM project. Arguments mixed up.static BOOL ImageArray_Alloc(LP_IMAGE_ARRAY_DATA iad, int size){ ... memset(&iad->nodes[iad->nodes_allocated_size], (size_grow - iad->nodes_allocated_size) * sizeof(IMAGE_ARRAY_DATA_NODE), 0); ...}The error was found through the V575 diagnostic: Function receives an odd argument. clist_modernmodern_image_array.cpp 59
  34. 34. The memset function handles 0 items, i.e. actually does nothing. The reason is in mixed up arguments.This is how the correct call of the memset function should be written:memset(&iad->nodes[iad->nodes_allocated_size], 0, (size_grow - iad->nodes_allocated_size) * sizeof(IMAGE_ARRAY_DATA_NODE));Examples of meaningless codeExample 1. IPP Samples project. Incomplete condition.void lNormalizeVector_32f_P3IM(Ipp32f *vec[3], Ipp32s* mask, Ipp32s len){ Ipp32s i; Ipp32f norm; for(i=0; i<len; i++) { if(mask<0) continue; norm = 1.0f/sqrt(vec[0][i]*vec[0][i]+ vec[1][i]*vec[1][i]+vec[2][i]*vec[2][i]); vec[0][i] *= norm; vec[1][i] *= norm; vec[2][i] *= norm; }}The error was found through the V503 diagnostic: This is a nonsensical comparison: pointer < 0.ipprsample ippr_sample.cpp 501I do not know how it happened, but there are 3 characters "[i]" missing in this code. As a result, the codeperforms a meaningless check that the pointer is below zero instead of checking the mask array.The correct check should be written in this way: if(mask[i] < 0).Example 2. Pc Ps2 Emulator project. Incorrect switch.LRESULT CALLBACK IOP_DISASM(...)
  35. 35. { ... switch(LOWORD(wParam)) { case (IDOK || IDCANCEL): EndDialog(hDlg,TRUE); return(TRUE); break; } ...}The error was found through the V560 diagnostic: A part of conditional expression is always true: 2.pcsx2 debugger.cpp 321This code does not have any meaning. The programmer must have intended to write it this way:switch(LOWORD(wParam)){ case IDOK: //no break case IDCANCEL: EndDialog(hDlg,TRUE); return(TRUE); break;}Example 3. CPU Identifying Tool project. A too strict condition.void projillum(short* wtab, int xdots, int ydots, double dec){ ... s = sin(-dtr(dec)); x = -s * sin(th); y = cos(th);
  36. 36. ... lon = (y == 0 && x == 0) ? 0.0 : rtd(atan2(y, x));}The error was found through the V550 diagnostic: An odd precise comparison: x == 0. Its probablybetter to use a comparison with defined precision: fabs(A - B) < Epsilon. clock_dll sunalgo.cpp 155It is strange to expect that the result will be strictly 0 after executing all these complex calculations usingsin and cos functions. Most likely, there must be comparison to be performed with certain accuracy.Example 4. Lugaru. Double assignment.int Game::DrawGLScene(void){ ... radius=fast_sqrt(maxdistance); radius=110; ...}The error was found through the V519 diagnostic: The radius object is assigned values twicesuccessively. Perhaps this is a mistake. Lugaru gamedraw.cpp 1505The programmer must have deliberately written value 110 into the radius variable for the sake ofexperiment and then forgot to remove this line. As a result, we have a meaningless and maybe eveninvalid code.Example 5. QT project. Duplicated check.Q3TextCustomItem* Q3TextDocument::parseTable(...){ ... while (end < length && !hasPrefix(doc, length, end, QLatin1String("</td")) && !hasPrefix(doc, length, end, QLatin1String("<td")) && !hasPrefix(doc, length, end, QLatin1String("</th")) && !hasPrefix(doc, length, end, QLatin1String("<th"))
  37. 37. && !hasPrefix(doc, length, end, QLatin1String("<td")) && !hasPrefix(doc, length, end, QLatin1String("</tr")) && !hasPrefix(doc, length, end, QLatin1String("<tr")) && !hasPrefix(doc, length, end, QLatin1String("</table"))) { ...}The error was found through the V501 diagnostic: There are identical sub-expressions to the left and tothe right of the && operator. Qt3Support q3richtext.cpp 6978Presence of the "<td" prefix is checked twice in the condition. It is meaningless. Maybe it is an extracheck or there should be some other prefix instead of the second "<td".Example 6. Audacity project. Strange check.int sf_error (SNDFILE *sndfile){ ... if (!sndfile) { if (sf_error != 0) return sf_errno; return 0; } ; ...}The error was found through the V516 diagnostic: Consider inspecting an odd expression. Non-nullfunction pointer is compared to null: sf_error != 0. libsndfile sndfile.c 491The "sf_error != 0" check always returns true, since sf_error is the name of the function in which thecode is executed.Example 7. IPP Samples project. Strange code inside a loop.static IppStatus mp2_HuffmanTableInitAlloc(Ipp32s *tbl, ...)
  38. 38. { ... for (i = 0; i < num_tbl; i++) { *tbl++; } ...}The error was found through the V532 diagnostic: Consider inspecting the statement of *pointer++pattern. Probably meant: (*pointer)++. mpeg2_dec umc_mpeg2_dec.cpp 59The loop body is probably incomplete because it is meaningless in the current form.Always true or always false conditionsIt is a very large and widely-spread type of errors. These errors also vary greatly depending on theimportance level. To non-dangerous errors we may refer incorrect conditions in ASSERT that actually donot check anything. To dangerous errors, incorrect checks of buffer size or index size are referred.Example 1. Shareaza project. Value range of char type.void CRemote::Output(LPCTSTR pszName){ ... CHAR* pBytes = new CHAR[ nBytes ]; hFile.Read( pBytes, nBytes ); ... if ( nBytes > 3 && pBytes[0] == 0xEF && pBytes[1] == 0xBB && pBytes[2] == 0xBF ) { pBytes += 3; nBytes -= 3; bBOM = true; }
  39. 39. ...}The error was found through the V547 diagnostic: Expression pBytes [ 0 ] == 0xEF is always false. Thevalue range of signed char type: [-128, 127]. Shareaza remote.cpp 350In this code, the TCHAR type is the char type. The value range of char is from -128 to 127 inclusive.Value 0xEF in the variable of the char type is nothing else than number -17. When comparing the charvariable with number 0xEF, its type is extended up to the int type. But the value still lies inside therange [-128..127]. The "pBytes[0] == 0xEF" ("-17 == 0xEF") condition is always false, and the programdoes not work as intended.This is the correct comparison:if ( nBytes > 3 && pBytes[0] == TCHAR(0xEF) && pBytes[1] == TCHAR(0xBB) && pBytes[2] == TCHAR(0xBF) )Example 2. TortoiseSVN project. Value range of char type.BOOL TortoiseBlame::OpenFile(const TCHAR *fileName){ ... // check each line for illegal utf8 sequences. // If one is found, we treat // the file as ASCII, otherwise we assume // an UTF8 file. char * utf8CheckBuf = lineptr; while ((bUTF8)&&(*utf8CheckBuf)) { if ((*utf8CheckBuf == 0xC0)|| (*utf8CheckBuf == 0xC1)|| (*utf8CheckBuf >= 0xF5)) { bUTF8 = false; break; }
  40. 40. ... } ...}The error was found through the V547 diagnostic: Expression * utf8CheckBuf == 0xC0 is always false.The value range of signed char type: [-128, 127]. tortoiseblame.cpp 310While the defect in the previous example seems to be caused through mere inattention, in this case it isnot so. Here is another identical example where a condition is always false. This is a very widely-spreadtype of errors in various projects.Example 3. VirtualDub project. Unsigned type is always >= 0.typedef unsigned short wint_t;...void lexungetc(wint_t c) { if (c < 0) return; g_backstack.push_back(c);}The error was found through the V547 diagnostic: Expression c < 0 is always false. Unsigned type valueis never < 0. Ami lexer.cpp 225The "c < 0" condition is always false because the variable of the unsigned type is always above or equalto 0.Example 4. Swiss-Army Knife of Trace project. Socket handling.static UINT_PTR m_socketHandle;void TTrace::LoopMessages(void){ ...
  41. 41. // Socket creation if ( (m_socketHandle = socket(AF_INET,SOCK_STREAM,0)) < 0) { continue; } ...}The error was found through the V547 diagnostic: Expression (m_socketHandle = socket (2, 1, 0)) < 0 isalways false. Unsigned type value is never < 0. Vs8_Win_Lib tracetool.cpp 871An attempt to check that a socket was created successfully is performed incorrectly. If a socket cannotbe created, this situation is not handled in any way. To make the check work correctly, we should usethe INVALID_SOCKET constant:m_socketHandle = socket(AF_INET,SOCK_STREAM,0);Example 5. Chromium project. Time handling.IdleState CalculateIdleState(...) { ... DWORD current_idle_time = 0; ... // Will go -ve if we have been idle for // a long time (2gb seconds). if (current_idle_time < 0) current_idle_time = INT_MAX; ...}The error was found through the V547 diagnostic: Expression current_idle_time < 0 is always false.Unsigned type value is never < 0. browser idle_win.cc 23To handle time, a variable of the unsigned type is used. As a result, check of too large values does notwork. This is the correct code:if (current_idle_time > INT_MAX) current_idle_time = INT_MAX;
  42. 42. Example 6. ICU project. Error in condition.U_CDECL_BEGIN static const char* U_CALLCONV_processVariableTop(...){ ... if(i == locElementCapacity && (*string != 0 || *string != _)) { *status = U_BUFFER_OVERFLOW_ERROR; } ...}The error was found through the V547 diagnostic: Expression *string != 0 || *string != _ is always true.Probably the && operator should be used here. icui18n ucol_sit.cpp 242The condition contains a logical error. The "(*string != 0 || *string != _)" subexpression is always true. Itis impossible that one and the same string character is not equal to 0 and _ at a time.Example 7. QT project. Dangerous loop.bool equals( class1* val1, class2* val2 ) const{{ ... size_t size = val1->size(); ... while ( --size >= 0 ){ if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++; } ...
  43. 43. }The error was found through the V547 diagnostic: Expression --size >= 0 is always true. Unsigned typevalue is always >= 0. QtCLucene arrays.h 154The (--size >= 0) condition is always true, since the size variable has the unsigned type. It means that iftwo sequences being compared are alike, we will get an overflow that will in its turn cause AccessViolation or other program failures.This is the correct code:for (size_t i = 0; i != size; i++){ if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++;}Example 8. MySQL project. Error in condition.enum enum_mysql_timestamp_typestr_to_datetime(...){ ... else if (str[0] != a || str[0] != A) continue; /* Not AM/PM */ ...}The error was found through the V547 diagnostic: Expression str [0] != a || str [0] != A is always true.Probably the && operator should be used here. clientlib my_time.c 340The condition is always true because the character is always either not equal to a or to A. This is thecorrect check:else if (str[0] != a && str[0] != A)Example 9. QT project. Incorrect count of references.STDMETHODIMP QEnumPins::QueryInterface(const IID &iid,void **out)
  44. 44. { ... if (S_OK) AddRef(); return hr;}The error was found through the V545 diagnostic: Such conditional expression of if operator isincorrect for the HRESULT type value (HRESULT) 0L. The SUCCEEDED or FAILED macro should be usedinstead. phonon_ds9 qbasefilter.cpp 60The check condition is represented by the S_OK constant. Since S_OK is 0, the AddRef() function willnever be called. This is how this check must look: if (hr == S_OK).Example 10. TickerTape project. Incorrect tornado.void GetWindAtSingleTornado(...){ ... if(radius < THRESH * 5) *yOut = THRESH * 10 / radius; else if (radius < THRESH * 5) *yOut = -3.0f / (THRESH * 5.0f) * (radius - THRESH * 5.0f) + 3.0f; else *yOut = 0.0f; ...}The error was found through the V517 diagnostic: The use of if (A) {...} else if (A) {...} pattern wasdetected. There is a probability of logical error presence. TickerTape wind.cpp 118The second condition is always false. The reason is that the first condition coincides with the second.There must be a misprint here.Example 11. Apache HTTP Server project. Error of socket handling in Windows.
  45. 45. typedef UINT_PTR SOCKET;static unsigned int __stdcall win9x_accept(void * dummy){ SOCKET csd; ... do { clen = sizeof(sa_client); csd = accept(nsd, (struct sockaddr *) &sa_client, &clen); } while (csd < 0 && APR_STATUS_IS_EINTR(apr_get_netos_error())); ...}The error was found through the V547 diagnostic: Expression csd < 0 is always false. Unsigned typevalue is never < 0. libhttpd child.c 404Socket handling errors very often emerge in crossplatform programs built under Windows. In Linux,socket descriptors are represented by the signed type, while in Windows it is the unsigned type.Programmers often forget about this and check the error status by comparing the value to 0. This isincorrect; you must use specialized constants.Example 12. QT project. Misprint in comparisons.QStringList ProFileEvaluator::Private::values(...){ ... else if (ver == QSysInfo::WV_NT) ret = QLatin1String("WinNT"); else if (ver == QSysInfo::WV_2000) ret = QLatin1String("Win2000"); else if (ver == QSysInfo::WV_2000) <<-- ret = QLatin1String("Win2003"); else if (ver == QSysInfo::WV_XP) ret = QLatin1String("WinXP");
  46. 46. ...}The error was found through the V517 diagnostic: The use of if (A) {...} else if (A) {...} pattern wasdetected. There is a probability of logical error presence. Check lines: 2303, 2305. lreleaseprofileevaluator.cpp 2303In the string we have marked, there must be the text "ver == QSysInfo::WV_2003". Because of this error,the "ret = QLatin1String("Win2003")" statement will never be executed.Code vulnerabilitiesOf course, errors leading to code vulnerabilities are actually misprints, incorrect conditions and incorrectarray handling. But we decided to single out certain errors into a separate group because they relate tothe notion of software vulnerabilities. An intruder, using such errors, can try to disturb programoperation, perform an attack to gain extended rights or carry out any other actions he/she needs.Example 1. Ultimate TCP/IP project. Incorrect check of an empty string.char *CUT_CramMd5::GetClientResponse(LPCSTR ServerChallenge){ ... if (m_szPassword != NULL) { ... if (m_szPassword != 0) { ...}The error was found through the V528 diagnostic: It is odd that pointer to char type is compared withthe 0 value. Probably meant: *m_szPassword != 0. UTMail ut_crammd5.cpp 333This code fragment must check that the pointer to the password is not equal to NULL and that the stringis not empty. But instead, the code checks twice that the pointer is not equal to NULL. The check of thestring does not work. The "if (m_szPassword != 0)" condition was intended to check that there is aterminal null in the very beginning of the string, which means that the string is empty. But a pointerdereferencing operation is missing here, and it is the pointer itself which is compared to zero. This is thecorrect code:if (m_szPassword != NULL)
  47. 47. { ... if (*m_szPassword != 0)Example 2. Chromium project. Null pointer handling.bool ChromeFrameNPAPI::Invoke(...){ ChromeFrameNPAPI* plugin_instance = ChromeFrameInstanceFromNPObject(header); if (!plugin_instance && (plugin_instance->automation_client_.get())) return false; ...}The error was found through the V522 diagnostic: Dereferencing of the null pointer plugin_instancemight take place. Check the logical condition. chrome_frame_npapi chrome_frame_npapi.cc 517The condition that checks the null pointer is written incorrectly. As a result, we have a segmentationerror. This is the correct code:if (plugin_instance && (plugin_instance->automation_client_.get())) return false;Example 3. SMTP Client with SSL/TLS project. Incomplete buffer clearing.void MD5::finalize () { ... uint1 buffer[64]; ... // Zeroize sensitive information memset (buffer, 0, sizeof(*buffer)); ...
  48. 48. }The error was found through the V512 diagnostic: A call of the memset function will lead to a bufferoverflow or underflow. CSmtp md5.cpp 212For security purposes, the function tries to clear the buffer containing sensitive information. But it fails.Only the first byte will be cleared in the buffer. The error is this: the sizeof operator calculates the sizeof the uint1 type instead of buffer. This is the correct code:memset (buffer, 0, sizeof(buffer));Generally, errors of incomplete memory clearing are rather frequent. Consider some other cases likethis.Example 4. Chromium. Incomplete buffer clearing.void Time::Explode(..., Exploded* exploded) const { ... ZeroMemory(exploded, sizeof(exploded)); ...}The error was found through the V512 diagnostic: A call of the memset function will lead to underflowof the buffer (exploded). base time_win.cc 227The ZeroMemory function clears only part of the Exploded structure. The reason is that the sizeofoperator returns the pointer size. To fix the error, we must dereference the pointer:ZeroMemory(exploded, sizeof(*exploded));Example 5. Apache HTTP Server project. Incomplete buffer clearing.#define MEMSET_BZERO(p,l) memset((p), 0, (l))void apr__SHA256_Final(..., SHA256_CTX* context) { ... MEMSET_BZERO(context, sizeof(context)); ...}The error was found through the V512 diagnostic: A call of the memset function will lead to underflowof the buffer (context). apr sha2.c 560
  49. 49. The error is completely identical to the previous one. The sizeof operator calculates the pointer size. Tofix it, we must write: "sizeof(*context)".Example 6. Miranda IM project. Incorrect string handling.static char *_skipblank(char * str){ char * endstr=str+strlen(str); while ((*str== || *str==t) && str!=0) str++; while ((*endstr== || *endstr==t) && endstr!=0 && endstr<str) endstr--; ...}The error was found through the diagnostics: V528 It is odd that pointer to char type is compared withthe 0 value. Probably meant: *str != 0. clist_modern modern_skinbutton.cpp 282V528 It is odd that pointer to char type is compared with the 0 value. Probably meant: *endstr !=0. clist_modern modern_skinbutton.cpp 283This code is rather dangerous because it incorrectly determines the string end. It may cause a stringoverflow and, as a consequence, an Access Violation exception. The error lies here: "str!=0" and here:"endstr!=0". A pointer dereferencing operation is missing. This is the correct code:while ((*str== || *str==t) && *str!=0) str++;while ((*endstr== || *endstr==t) && *endstr!=0 && endstr<str) endstr--;Example 7. PNG library project. Accidental pointer clearing.png_size_tpng_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key){ ...
  50. 50. if (key_len > 79) { png_warning(png_ptr, "keyword length must be 1 - 79 characters"); new_key[79] = 0; key_len = 79; } ...}The error was found through the V527 diagnostic: It is odd that the 0 value is assigned to char typepointer. Probably meant: *new_key [79] = 0. graphics3D pngwutil.c 1283This sample demonstrates a mistake when the programmer accidentally clears the pointer instead oftruncating the string length. The point is that new_key is a pointer to a string. And it means that weshould write our code as follows to truncate it to 79 characters:(*new_key)[79] = 0;Example 8. Intel AMT SDK project. Unverified user name.static voidwsman_set_subscribe_options(...){ ... if (options->delivery_certificatethumbprint || options->delivery_password || options->delivery_password) { ...}The error was found through the V501 diagnostic: There are identical sub-expressions options->delivery_password to the left and to the right of the || operator. OpenWsmanLib wsman-client.c 631Because of the developers inattention, presence of password is checked twice, while presence of username is not checked at all. This is the correct code:if (options->delivery_certificatethumbprint || options->delivery_username ||
  51. 51. options->delivery_password) {Example 9. Ultimate TCP/IP project. Incorrect handling of empty strings.void CUT_StrMethods::RemoveCRLF(LPSTR buf){ // v4.2 changed to size_t size_t len, indx = 1; if(buf != NULL){ len = strlen(buf); while((len - indx) >= 0 && indx <= 2) { if(buf[len - indx] == r || buf[len - indx] == n) buf[len - indx] = 0; ++indx; } }}The error was found through the V547 diagnostic: Expression (len - indx) >= 0 is always true. Unsignedtype value is always >= 0. UTDns utstrlst.cpp 58The "len - indx" expression has the unsigned type size_t and is always >= 0. Lets look what it will resultin, if we send an empty string to the input.If the string is empty, then: len = 0, indx = 1.The len - indx expression is equal to 0xFFFFFFFFu.Since 0xFFFFFFFFu > 0 and indx <= 2, an array access is performed"buf[len - indx]".The "buf[0xFFFFFFFFu]" operation will cause Access Violation.Example 10. Miranda IM project. Underflow protection does not work.void Append( PCXSTR pszSrc, int nLength ){
  52. 52. ... UINT nOldLength = GetLength(); if (nOldLength < 0) { // protects from underflow nOldLength = 0; } ...}The error was found through the V547 diagnostic: Expression nOldLength < 0 is always false. Unsignedtype value is never < 0. IRC mstring.h 229The check "if (nOldLength < 0)" does not work since the nOldLength variable has the unsigned type.Example 11. Apache HTTP Server project. Incorrect handling of negative values.typedef size_t apr_size_t;APU_DECLARE(apr_status_t) apr_memcache_getp(...){ ... apr_size_t len = 0; ... len = atoi(length); ... if (len < 0) { *new_length = 0; *baton = NULL; } else { ... }}
  53. 53. The error was found through the V547 diagnostic: Expression len < 0 is always false. Unsigned typevalue is never < 0. aprutil apr_memcache.c 814The check "if (len < 0)" does not work because the len variable has the unsigned type.Example 12. Ultimate TCP/IP project. Incorrect condition of loop termination.void CUT_StrMethods::RemoveSpaces(LPSTR szString) { ... size_t loop, len = strlen(szString); // Remove the trailing spaces for(loop = (len-1); loop >= 0; loop--) { if(szString[loop] != ) break; } ...}The error was found through the V547 diagnostic: Expression loop >= 0 is always true. Unsigned typevalue is always >= 0. UTDns utstrlst.cpp 430Suppose the whole string consists only of spaces. While searching the characters, the program will reachthe null item of the string, and the loop variable will equal to zero. Then it will be decremented onceagain. Since this variable is of unsigned type, its value will be 0xFFFFFFFFu or 0xFFFFFFFFFFFFFFFFu(depending on the architecture). This value is naturally >= 0, and a new loop iteration will start. Therewill be an attempt of memory access by szString[0xFFFFFFFFu] address - the consequences of this arefamiliar to every C/C++ programmer.Example 13. Crypto++ project. Private data clearing error.void CAST256::Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &){ AssertValidKeyLength(keylength); word32 kappa[8]; ... memset(kappa, 0, sizeof(kappa));
  54. 54. }The error has been found with rule V597: The compiler could delete the memset function call, which isused to flush kappa buffer. The RtlSecureZeroMemory() function should be used to erase the privatedata. cryptlib cast.cpp 293The problem is in the memset() function. The arguments passed into the function are correct. If aprogrammer looks how the Debug-version of this code works in the debugger, he/she wont notice thetrouble either. The error occurs in the Release version of the project. The data that should have beencleared will remain in memory. The reason is that the compiler has the right to delete the call of thememset() function during optimization, and this is what it does. If you want know why it happens, readthe article "Overwriting memory - why?".Copy-PasteDevelopers should not also underestimate Copy-Paste errors as well as common misprints. They arevery-very numerous. Programmers spend much time on debugging them.Of course, misprints and Copy-Paste errors are similar, but there is a difference between them thatcaused us to place them into different groups in this article. Misprints often result in using a wrongvariable instead of the needed one. And in the case of copy-paste, programmers simply forget to editcopied and pasted lines.Example 1. Fennec Media Project project. Mistake while handling array items.void* tag_write_setframe(char *tmem, const char *tid, const string dstr){ ... if(lset) { fhead[11] = 0; fhead[12] = 0; fhead[13] = 0; fhead[13] = 0; } ...}
  55. 55. The error was found through the V525 diagnostic: The code containing the collection of similar blocks.Check items 11, 12, 13, 13 in lines 716, 717, 718, 719. id3 editor.c 716The four similar lines must have appeared in the code through the copy-paste method. When theprogrammer started editing the indexes, he/she made a mistake that causes zero to be written intofhead[13] twice and not be written into fhead[14] .Example 2. MySQL project. Mistake while handling array items.static int rr_cmp(uchar *a,uchar *b){ if (a[0] != b[0]) return (int) a[0] - (int) b[0]; if (a[1] != b[1]) return (int) a[1] - (int) b[1]; if (a[2] != b[2]) return (int) a[2] - (int) b[2]; if (a[3] != b[3]) return (int) a[3] - (int) b[3]; if (a[4] != b[4]) return (int) a[4] - (int) b[4]; if (a[5] != b[5]) return (int) a[1] - (int) b[5]; if (a[6] != b[6]) return (int) a[6] - (int) b[6]; return (int) a[7] - (int) b[7];}The error was found through the V525 diagnostic: The code containing the collection of similar blocks.Check items 0, 1, 2, 3, 4, 1, 6 in lines 680, 682, 684, 689, 691, 693, 695. sql records.cc 680It is not apparent at first sight, so lets single it out:return (int) a[1] - (int) b[5];Actually there must be the following code:return (int) a[5] - (int) b[5];
  56. 56. Example 3. TortoiseSVN project. File name not corrected.BOOL GetImageHlpVersion(DWORD &dwMS, DWORD &dwLS){ return(GetInMemoryFileVersion(("DBGHELP.DLL"), dwMS, dwLS)) ;}BOOL GetDbgHelpVersion(DWORD &dwMS, DWORD &dwLS){ return(GetInMemoryFileVersion(("DBGHELP.DLL"), dwMS, dwLS)) ;}The error was found through the V524 diagnostic: It is odd that the GetDbgHelpVersion function is fullyequivalent to the GetImageHlpVersion function (SymbolEngine.h, line 98). symbolengine.h 105The GetImageHlpVersion function must have appeared through copying and pasting theGetInMemoryFileVersion function. The error is this: the programmer forgot to fix the file name in thecopied and pasted function. This is the correct code:BOOL GetImageHlpVersion(DWORD &dwMS, DWORD &dwLS){ return(GetInMemoryFileVersion(("IMAGEHLP.DLL"), dwMS, dwLS)) ;}Example 4. Clang project. Identical function bodies.MapTy PerPtrTopDown;MapTy PerPtrBottomUp;
  57. 57. void clearBottomUpPointers() { PerPtrTopDown.clear();}void clearTopDownPointers() { PerPtrTopDown.clear();}The error was found through the V524 diagnostic: It is odd that the body of clearTopDownPointersfunction is fully equivalent to the body of clearBottomUpPointers function (ObjCARC.cpp, line 1318).LLVMScalarOpts objcarc.cpp 1322The body of the clearBottomUpPointers function seems to be incorrect; this function should be writtenas follows:void clearBottomUpPointers() { PerPtrBottomUp.clear();}Example 5. QT. Unsuccessful swap.bool qt_testCollision(...){ ... t=x1; x1=x2; x2=t; t=y1; x1=y2; y2=t; ...}The error was found through the V519 diagnostic: The x1 variable is assigned values twice successively.Perhaps this is a mistake. Check lines: 2218, 2219. Qt3Support q3canvas.cpp 2219The first line is absolutely correct and swaps values in the x1 and x2 variables. In the second line,variables y1 and y2 must be swapped. This line is probably a copy of the previous one. All the x lettersmust be replaced with letters y. Unfortunately, the programmer forgot to do that in one place: "...x1=y2; ...".Correct code:t=x1; x1=x2; x2=t;
  58. 58. t=y1; y1=y2; y2=t;Example 6. Crystal Space 3D SDK project. Identical subexpressions.inline_ bool Contains(const LSS& lss){ return Contains(Sphere(lss.mP0, lss.mRadius)) && Contains(Sphere(lss.mP0, lss.mRadius));}The error was found through the V501 diagnostic: There are identical sub-expressions to the left and tothe right of the && operator. plgcsopcode icelss.h 69The error is this: the lss.mP0. variable is used twice here. There must be lss.mP1 in the first part of theexpression.Example 7. Notepad++ project. Setting an incorrect style.void KeyWordsStyleDialog::updateDlg(){ ... 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);
  59. 59. 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); ...}The error was found through the V525 diagnostic: The code containing the collection of similar blocks.Check items 7, 7, 6, 7 in lines 576, 580, 584, 588It is almost unreal to find this error by sight, so lets abridge the text to single out the most interestingfragments:styleUpdate(... IDC_KEYWORD1_BOLD_CHECK, IDC_KEYWORD1_ITALIC_CHECK, ...);styleUpdate(... IDC_KEYWORD2_BOLD_CHECK, IDC_KEYWORD2_ITALIC_CHECK, ...);styleUpdate(... IDC_KEYWORD3_BOLD_CHECK, IDC_KEYWORD3_BOLD_CHECK, <<-- ...);styleUpdate(... IDC_KEYWORD4_BOLD_CHECK, IDC_KEYWORD4_ITALIC_CHECK,
  60. 60. ...);By mistake, IDC_KEYWORD3_BOLD_CHECK is used instead of IDC_KEYWORD3_ITALIC_CHECK.Example 8. ReactOS object. Choosing a wrong object.void CardButton::DrawRect(HDC hdc, RECT *rect, bool fNormal){ ... HPEN hhi = CreatePen(0, 0, MAKE_PALETTERGB(crHighlight)); HPEN hsh = CreatePen(0, 0, MAKE_PALETTERGB(crShadow)); ... if(fNormal) hOld = SelectObject(hdc, hhi); else hOld = SelectObject(hdc, hhi); ...}The error was found through the V523 diagnostic: The then statement is equivalent to the elsestatement. cardlib cardbutton.cpp 83The hsh object is not used, while hhi is used twice. This is the correct code:if(fNormal) hOld = SelectObject(hdc, hhi);else hOld = SelectObject(hdc, hsh);Example 9. IPP Samples project. Incorrect check.Status VC1VideoDecoder::ResizeBuffer(){ ... if(m_pContext && m_pContext->m_seqLayerHeader && m_pContext->m_seqLayerHeader->heightMB &&
  61. 61. m_pContext->m_seqLayerHeader->heightMB) ...}The error was found through the V501 diagnostic: There are identical sub-expressions m_pContext->m_seqLayerHeader->heightMB to the left and to the right of the && operator. vc1_decumc_vc1_video_decoder.cpp 1347Correct code:if(m_pContext && m_pContext->m_seqLayerHeader && m_pContext->m_seqLayerHeader->heightMB && m_pContext->m_seqLayerHeader->widthMB)Example 10. ReactOS project. Mistake in a variable name.BOOL APIENTRYGreStretchBltMask(...){ ... MaskPoint.x += DCMask->ptlDCOrig.x; MaskPoint.y += DCMask->ptlDCOrig.x; ...}The error was found through the V537 diagnostic: Consider reviewing the correctness of x items usage.win32k bitblt.c 670This is a very good example where you can see that a line was copied and pasted. After that, theprogrammer fixed the first name x but forgot to fix the second. This is the correct code:MaskPoint.x += DCMask->ptlDCOrig.x;MaskPoint.y += DCMask->ptlDCOrig.y;Late check of null pointersC/C++ programmers have to check numerous pointers all the time to make sure that they are not equalto zero. Since these checks are numerous, the chance to make a mistake is also big. It often happensthat a pointer is used first and only then is compared to NULL. Errors of this type reveal themselves veryrarely. Usually the program works correctly in the standard mode and fails only in case of a non-
  62. 62. standard situation. Instead of correctly processing a null pointer in normal mode, an Access Violationwill occur and an exception will be thrown.Example 1. Quake-III-Arena project. Late check.void Item_Paint(itemDef_t *item) { vec4_t red; menuDef_t *parent = (menuDef_t*)item->parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if (item == NULL) { return; } ...}The error has been found with rule V595: The item pointer was utilized before it was verified againstnullptr. Check lines: 3865, 3869. cgame ui_shared.c 3865The item pointer is used first and only then is compared to NULL.Example 2. LAME Aint an MP3 Encoder project. Late check.static intcheck_vbr_header(PMPSTR mp, int bytes){ ... buf = buf->next; pos = buf->pos; if(!buf) return -1; /* fatal error */ ...}The error has been found with rule V595: The buf pointer was utilized before it was verified againstnullptr. Check lines: 226, 227. mpglib interface.c 226
  63. 63. If buf equals NULL, an exception will be thrown instead of returning the error code. And if exceptionsare not used, the program will crash.Example 3. daoParanoia library project. Late check.static long i_stage2_each(root_block *root, v_fragment *v, void(*callback)(long,int)){ cdrom_paranoia *p=v->p; long dynoverlap=p->dynoverlap/2*2; if (!v || !v->one) return(0); ...}The error has been found with rule V595: The v pointer was utilized before it was verified againstnullptr. Check lines: 532, 535. daoParanoia paranoia.c 532The situation here is identical to the previous ones.Example 4. TrinityCore project. Late check.bool OnCheck(Player* player, Unit* /*target*/){ bool checkArea = player->GetAreaId() == AREA_ARGENT_TOURNAMENT_FIELDS || player->GetAreaId() == AREA_RING_OF_ASPIRANTS || player->GetAreaId() == AREA_RING_OF_ARGENT_VALIANTS || player->GetAreaId() == AREA_RING_OF_ALLIANCE_VALIANTS || player->GetAreaId() == AREA_RING_OF_HORDE_VALIANTS || player->GetAreaId() == AREA_RING_OF_CHAMPIONS; return player && checkArea && player->duel && player->duel->isMounted;}
  64. 64. The error has been found with rule V595: The player pointer was utilized before it was verified againstnullptr. Check lines: 310, 312. scripts achievement_scripts.cpp 310As you can see from the "player && ..." condition, the player pointer can be equal to zero. However,this check, like in all the previous examples, is too late.We could cite many examples of such errors, but they are all alike. If you have seen a couple of sucherrors, be sure youve seen them all.MiscellaneousExample 1. Image Processing SDK project. Octal number.inlinevoid elxLuminocity(const PixelRGBus& iPixel, LuminanceCell< PixelRGBus >& oCell){ oCell._luminance = uint16(0.2220f*iPixel._red + 0.7067f*iPixel._blue + 0.0713f*iPixel._green); oCell._pixel = iPixel;}inlinevoid elxLuminocity(const PixelRGBi& iPixel, LuminanceCell< PixelRGBi >& oCell){ oCell._luminance = 2220*iPixel._red + 7067*iPixel._blue + 0713*iPixel._green; oCell._pixel = iPixel;}The error was found through the V536 diagnostic: Be advised that the utilized constant value isrepresented by an octal form. Oct: 0713, Dec: 459. IFF plugins pixelservices.inl 146If you examine the second function, you will see that the programmer intended to use number 713, not0713. Number 0713 is declared in the octal numeral system. You can easily forget about it if you seldomuse octal constants.
  65. 65. Example 2. IPP Samples project. One variable for two loops.JERRCODE CJPEGDecoder::DecodeScanBaselineNI(void){ ... for(c = 0; c < m_scan_ncomps; c++) { block = m_block_buffer + (DCTSIZE2*m_nblock*(j+(i*m_numxMCU))); // skip any relevant components for(c = 0; c < m_ccomp[m_curr_comp_no].m_comp_no; c++) { block += (DCTSIZE2*m_ccomp[c].m_nblocks); } ...}The error was found through the V535 diagnostic: The variable c is being used for this loop and for theouter loop. jpegcodec jpegdec.cpp 4652One and the same variable is used for the outer loop and the inner loop. As a result, this code willhandle only part of the data or cause an eternal loop.Example 3. Quake-III-Arena project. Missing return.static ID_INLINE int BigLong(int l){ LongSwap(l); }The error has been found with rule V591: Non-void function should return a value. botlib q_shared.h155This code is written in C. It means that the compiler doesnt require that return should be necessarilypresent. But it is really necessary here. However, the code can work well due to sheer luck. Everythingdepends on what the EAX register contains. But its just luck and nothing more. The function bodyshould have been written this way: { return LongSwap(l); }.Example 4. Notepad++ project. Odd condition.
  66. 66. int Notepad_plus::getHtmlXmlEncoding(....) const{ ... if (langT != L_XML && langT != L_HTML && langT == L_PHP) return -1; ...}The error has been found with rule V590: Consider inspecting this expression. The expression isexcessive or contains a misprint. Notepad++ notepad_plus.cpp 853Perhaps this error is just a misprint, but it also could have appeared during factoring. However, it isobvious. The condition can be simplified: if (langT == L_PHP). It means that the code must have lookedthis way:if (langT != L_XML && langT != L_HTML && langT != L_PHP)References 1. PVS-Studio Main Product Page. http://www.viva64.com/en/pvs-studio/ 2. Download the fully functional trial. http://www.viva64.com/en/pvs-studio-download/ 3. Buy PVS-Studio. http://www.viva64.com/en/order/ 4. PVS-Studio Documentation. http://www.viva64.com/en/d/ 5. Feedback. http://www.viva64.com/en/about-feedback/ 6. Twitter. http://twitter.com/Code_Analysis

×