Gagging, checked Visual C ++ 2013 libraries (update 3)

    PVS-Studio and Visual Studio 2013I was asked to check the libraries included in Visual Studio 2013. I did not find anything particularly remarkable. Only a few minor mistakes and shortcomings. You can’t make an intriguing article out of it, but I’ll still describe the shortcomings I noticed. I hope this makes the libraries a little better, and encourages authors to conduct a more thorough check. I do not have project files for building libraries. So I checked the files somehow, and a lot could be skipped.

    This is the second article about checking libraries included in Visual C ++. The results of the previous check can be found in the article: Errors were detected in Visual C ++ 2012 libraries .

    I can’t check the full library. I did very clumsy. Included in the new project all the files contained in the folders "crt \ src" and "atlmfc \ src". Plus, I made a new test.cpp file, where I included all the header files related to the standard library (vector, map, set, and so on).

    After that, having conjured a little with the project settings, I got that about 80% of the files are compiled. I think that’s enough. Even if the file does not compile, it will most likely be checked by PVS-Studio, even if not completely.

    I think if this article is of interest to library developers, they will be able to conduct a more thorough analysis. Even if the assembly is carried out in an exotic way, now it will not be a problem. You can use the compiler startup tracking mechanism .

    For verification, I used PVS-Studio version 5.19. We checked the source codes of C / C ++ libraries included in Visual Studio 2013 (update 3).

    Result of checking


    There were some shortcomings that we found in the previous version of Visual Studio 2012. For example, the proj () function still looks strange, the ~ single_link_registry () destructor is dangerous. But repeating is not interesting. Let's try to find something new.

    Incorrect index check


    void _Initialize_order_node(...., size_t _Index, ....)
    {
      if (_Index < 0)
      {
        throw std::invalid_argument("_Index");
      }
      ....
    }

    PVS-Studio warning : V547 Expression '_Index <0' is always false. Unsigned type value is never <0. agents.h 8442 The

    argument is _Index and has an unsigned type. Therefore, verification does not make sense. An exception will never be thrown. I think this is not a mistake, but just an extra code.

    Format error


    int _tfpecode; /* float point exception code */
    void __cdecl _print_tiddata1 (
      _ptiddata ptd
    )
    {
      ....
      printf("\t_gmtimebuf      = %p\n",   ptd->_gmtimebuf);
      printf("\t_initaddr       = %p\n",   ptd->_initaddr);
      printf("\t_initarg        = %p\n",   ptd->_initarg);
      printf("\t_pxcptacttab    = %p\n",   ptd->_pxcptacttab);
      printf("\t_tpxcptinfoptrs = %p\n",   ptd->_tpxcptinfoptrs);
      printf("\t_tfpecode       = %p\n\n", ptd->_tfpecode);
      ....
    }

    Warning PVS-Studio: V576 Incorrect format. Consider checking the second actual argument of the 'printf' function. The pointer is expected as an argument. tidprint.c 133

    Here we are dealing with the effect of the last line . An error was made at the end of the block of the same type of lines. Everywhere you should print the value of the pointer. But at the very end, the variable '_tfpecode' is not a pointer, but simply an integer value. It should be written:
    printf("\t_tfpecode       = %i\n\n", ptd->_tfpecode);

    Strange repeating calculations


    unsigned int SchedulerProxy::AdjustAllocationIncrease(....) const
    {
      ....
      unsigned int remainingConcurrency = 
                             m_maxConcurrency - m_currentConcurrency;
      remainingConcurrency = m_maxConcurrency - m_currentConcurrency;
      ....
    }

    PVS-Studio Warning: V519 The 'remainingConcurrency' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 1136, 1137. schedulerproxy.cpp 1137

    Two times the result of the same expression is assigned to the variable. This code is redundant and most likely resulted from unsuccessful refactoring.

    Typo suspicion


    double HillClimbing::CalculateThroughputSlope(....)
    {
      ....
      MeasuredHistory * lastHistory = GetHistory(fromSetting);
      MeasuredHistory * currentHistory = GetHistory(toSetting);
      ....
      double varianceOfcurrentHistory = currentHistory->VarianceMean();
      double varianceOflastHistory = currentHistory->VarianceMean();
      ....
    }

    PVS-Studio Warning: V656 Variables 'varianceOfcurrentHistory', 'varianceOflastHistory' are initialized through the call to the same function. It's probably an error or un-optimized code. Consider inspecting the 'currentHistory-> VarianceMean ()' expression. Check lines: 412, 413. hillclimbing.cpp 413 It is

    suspicious that the variable varianceOfcurrentHistory and varianceOflastHistory are assigned the same value. It would be logical to initialize varianceOflastHistory like this:
    double varianceOflastHistory = varianceOfcurrentHistory;

    Moreover, there is still a pointer to 'lastHistory'. Let me suggest that the code contains a typo. Perhaps the code should be like this:
    double varianceOfcurrentHistory = currentHistory->VarianceMean();
    double varianceOflastHistory = lastHistory->VarianceMean();

    And here is exactly a typo


    BOOL CPropertySheet::SetActivePage(CPropertyPage* pPage)
    {
      ASSERT_VALID(this);
      ENSURE_VALID(pPage);
      ASSERT_KINDOF(CPropertyPage, pPage);
      int nPage = GetPageIndex(pPage);
      ASSERT(pPage >= 0);
      return SetActivePage(nPage);
    }

    PVS-Studio warning : V503 This is a nonsensical comparison: pointer> = 0. dlgprop.cpp 1206

    It is strange to check that the value of a pointer is greater than or equal to zero. This is a typo and, in fact, we wanted to check the variable 'nPage':
    int nPage = GetPageIndex(pPage);
    ASSERT(nPage >= 0);

    Of course, this is just ASSERT, and the error will not lead to any negative consequences. But still, this is a mistake.

    The same actions, regardless of the condition


    void CMFCVisualManager::OnDrawTasksGroupCaption(....)
    {
      ....
      if (pGroup->m_bIsSpecial)
      {
        if (!pGroup->m_bIsCollapsed)
        {
          CMenuImages::Draw(pDC, CMenuImages::IdArrowUp,
                            rectButton.TopLeft());
        }
        else
        {
          CMenuImages::Draw(pDC, CMenuImages::IdArrowDown,
                            rectButton.TopLeft());
        }
      }
      else
      {
        if (!pGroup->m_bIsCollapsed)
        {
          CMenuImages::Draw(pDC, CMenuImages::IdArrowUp,
                            rectButton.TopLeft());
        }
        else
        {
          CMenuImages::Draw(pDC, CMenuImages::IdArrowDown,
                            rectButton.TopLeft());
        }
      }
      ....
    }

    PVS-Studio Warning: V523 The 'then' statement is equivalent to the 'else' statement. afxvisualmanager.cpp 2118

    Regardless of the condition (pGroup-> m_bIsSpecial), the same actions are performed. This is strange.

    Incorrect port number verification


    typedef WORD ATL_URL_PORT;
    ATL_URL_PORT m_nPortNumber;
    inline BOOL Parse(_In_z_ LPCTSTR lpszUrl)
    {
      ....
      m_nPortNumber = (ATL_URL_PORT) _ttoi(tmpBuf);
      if (m_nPortNumber < 0)
        goto error;
      ....
    }

    PVS-Studio warning : V547 Expression 'm_nPortNumber <0' is always false. Unsigned type value is never <0. atlutil.h 2773 The

    variable 'm_nPortNumber' has an unsigned WORD type.

    No virtual destructor


    class CDataSourceControl
    {
      ....
      ~CDataSourceControl();
      ....
      virtual IUnknown* GetCursor();
      virtual void BindProp(....);
      virtual void BindProp(....);
      ....
    }
    CDataSourceControl* m_pDataSourceControl;
    COleControlSite::~COleControlSite()
    {
      ....
      delete m_pDataSourceControl;
      ....
    }

    Warning PVS_Studio: V599 The destructor was not declared as a virtual one, although the 'CDataSourceControl' class contains virtual functions. occsite.cpp 77

    The CDataSourceControl class contains virtual methods, but the destructor is not virtual. This is dangerous. If the class X is inherited from the CDataSourceControl class, then objects of type X cannot be destroyed using a pointer to the base class.

    Incomplete code


    BOOL CMFCWindowsManagerDialog::OnHelpInfo(HELPINFO* pHelpInfo)
    {
      pHelpInfo->iCtrlId;
      CWnd* pParentFrame = AfxGetMainWnd();
      pParentFrame->SendMessage(AFX_WM_WINDOW_HELP, 0,
                                (LPARAM) this);
      return FALSE;
    }

    Warning PVS_Studio: V607 Ownerless expression 'pHelpInfo-> iCtrlId'. afxwindowsmanagerdialog.cpp 472

    What is "pHelpInfo-> iCtrlId;"? What would that mean?

    Suspicious Double Initialization


    CMFCStatusBar::CMFCStatusBar()
    {
      m_hFont = NULL;
      // setup correct margins
      m_cxRightBorder = m_cxDefaultGap;  //<<--
      m_cxSizeBox = 0;
      m_cxLeftBorder = 4;
      m_cyTopBorder = 2;
      m_cyBottomBorder = 0;
      m_cxRightBorder = 0;               //<<--
      ....
    }

    PVS-Studio Warning: V519 The 'm_cxRightBorder' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 74, 80. afxstatusbar.cpp 80

    At the beginning, the value of another variable is written to the variable 'm_cxRightBorder'. And then, that value is suddenly overwritten by zero.

    Suspicious Status Check


    #define S_OK  ((HRESULT)0L)
    #define E_NOINTERFACE  _HRESULT_TYPEDEF_(0x80004002L)
    HRESULT GetDocument(IHTMLDocument2** ppDoc) const
    {  
      const T* pT = static_cast(this);
      return pT->GetDHtmlDocument(ppDoc) ? S_OK : E_NOINTERFACE;
    }
    HRESULT GetEvent(IHTMLEventObj **ppEventObj) const
    {
      ....
      if (GetDocument(&sphtmlDoc))
      ....
    }

    PVS-Studio Warning: V545 Such conditional expression of 'if' operator is incorrect for the HRESULT type value 'GetDocument (& sphtmlDoc)'. The SUCCEEDED or FAILED macro should be used instead. afxhtml.h 593

    The design of the code may not correspond to its logic of work. It seems that if the condition 'GetDocument (...)' is true, then we were able to “get” the document. But, in fact, this is not so. The GetDocument () function returns a value of type HRESULT. With this type, the opposite is true. For example, the status S_OK is encoded as 0, and the status E_NOINTERFACE as 0x80004002L. To check values ​​of type HRESULT, special macros should be used: SUCCEEDED, FAILED.

    I don’t know if there is an error here or not, but this code is confusing and should be checked.

    Invalid argument for macro MAKE_HRESULT


    #define MAKE_HRESULT(sev,fac,code) \
      ((HRESULT) \
       (((unsigned long)(sev)<<31) | \
        ((unsigned long)(fac)<<16) | \
        ((unsigned long)(code))) )
    ATLINLINE ATLAPI AtlSetErrorInfo(....)
    {
      ....
      hRes = MAKE_HRESULT(3, FACILITY_ITF, nID);
      ....
    }

    PVS-Studio warning : V673 The '(unsigned long) (3) << 31' expression evaluates to 6442450944. 33 bits are required to store the value, but the expression evaluates to the 'unsigned' type which can only hold '32' bits. atlcom.h 6650

    Everything will work correctly, but there is an error. I will explain.

    The function should generate error information in a variable of type HRESULT. To do this, use the macro MAKE_HRESULT. But it is used incorrectly. The programmer considered that the first parameter 'severity' can lie in the aisles from 0 to 3. Apparently, he confused this with the method of generating error codes used when working with the GetLastError () / SetLastError () functions.

    The MAKE_HRESULT macro can only accept 0 (success) or 1 (failure) as the first argument. This issue was discussed in more detail on the CodeGuru website forum: Warning! MAKE_HRESULT macro doesn't work.

    Since the number 3 is used as the first actual argument, an overflow occurs. The number 3 will turn into 1. Due to this randomness, the error will not affect the program.

    ASSERTs whose conditions are always true


    There are quite a few situations where the condition for ASSERT looks like this: (X> = 0). In this case, the variable X is declared as an unsigned integer type. It turns out that the condition is always true.

    In some cases, the presence of such ASSERT is reasonable. Suddenly, in the process of refactoring, the variable will become significant, and the algorithm is not ready to work with negative numbers. However, the existence of some of them is most likely meaningless. They need to be removed from the code or replaced with another useful check. Therefore, I decided to mention them in the article.

    Consider an example:
    DWORD m_oversubscribeCount; 
    void ExternalContextBase::Oversubscribe(....)
    {
      if (beginOversubscription)
      {
        ASSERT(m_oversubscribeCount >= 0);
        ++m_oversubscribeCount;
      }
      ....
    }

    PVS-Studio warning : V547 Expression 'm_oversubscribeCount> = 0' is always true. Unsigned type value is always> = 0. externalcontextbase.cpp 204

    The rest of the warnings are listed simply:
    • V547 Expression 'm_oversubscribeCount> = 0' is always true. Unsigned type value is always> = 0. internalcontextbase.cpp 506
    • V547 Expression 'pGlobalNode-> m_idleCores> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 3764
    • V547 Expression 'pGlobalNode-> m_availableCores> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 3769
    • V547 Expression 'pReceivingProxyData-> m_allocation> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4100
    • V547 Expression 'pReceivingProxyData-> m_allocation> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4360
    • V547 Expression 'exclusiveCoresAvailable> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4657
    • V547 Expression 'coresNeeded> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4657
    • V547 Expression 'previousGlobal> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4781
    • V547 Expression 'currentGlobal> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4782
    • V547 Expression 'm_minConcurrency> = 0' is always true. Unsigned type value is always> = 0. schedulerproxy.cpp 63
    • V547 Expression 'm_minimumHardwareThreads> = 0' is always true. Unsigned type value is always> = 0. schedulerproxy.cpp 125
    • V547 Expression 'm_oversubscribeCount> = 0' is always true. Unsigned type value is always> = 0. umsthreadinternalcontext.cpp 308
    • V547 Expression 'j> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 1922
    • V547 Expression 'pMaxNode-> m_availableCores> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 2542
    • V547 Expression 'previousLocal> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4793
    • V547 Expression 'currentLocal> = 0' is always true. Unsigned type value is always> = 0. resourcemanager.cpp 4794
    • V547 Expression is always true. Unsigned type value is always> = 0. schedulerpolicybase.cpp 285
    • V547 Expression 'value> = 0' is always true. Unsigned type value is always> = 0. schedulerpolicybase.cpp 345

    Extra casts


    There were several explicit type conversions that are not only superfluous, but also can ruin the values.

    Consider the first example:
    size_t __cdecl strnlen(const char *str, size_t maxsize);
    size_t __cdecl _mbstrnlen_l(const char *s,
                                size_t sizeInBytes,
                                _locale_t plocinfo)
    {
      ....
      if ( _loc_update.GetLocaleT()->locinfo->mb_cur_max == 1 )
          /* handle single byte character sets */
          return (int)strnlen(s, sizeInBytes);
      ....
    }

    PVS-Studio warning : V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: 'strnlen (s, sizeInBytes)'. _mbslen_s.c 67

    The strnlen () function returns a value of type 'size_t'. Then it suddenly becomes explicitly of type 'int'. After that, the value will be implicitly again expanded to type size_t.

    This code contains a potential 64-bit error. If suddenly someone wants to count the number of characters in a very long line using the _mbstrnlen_l () function in a 64-bit program, then he will get the wrong result.

    It seems to me that this explicit cast remained in the code by accident and should simply be deleted.

    Consider the second example:
    WINBASEAPI SIZE_T WINAPI GlobalSize (_In_ HGLOBAL hMem);
    inline void __cdecl memcpy_s(
      _Out_writes_bytes_to_(_S1max,_N)  void *_S1,
      _In_ size_t _S1max,
      _In_reads_bytes_(_N) const void *_S2,
      _In_ size_t _N);
    AFX_STATIC HGLOBAL AFXAPI _AfxCopyGlobalMemory(....)
    {
      ULONG_PTR nSize = ::GlobalSize(hSource);
      ....
      Checked::memcpy_s(lpDest, (ULONG)::GlobalSize(hDest),
                        lpSource, (ULONG)nSize);
      ....
    }

    PVS-Studio warning: V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: 'nSize'. olemisc.cpp 684.

    The GlobalSize () function returns the type SIZE_T. The arguments to memcpy_s () are also of type size_t.

    So why then did an explicit cast like "(ULONG) :: GlobalSize (hDest)" be done?

    If we work with a buffer larger than 4Gb, then the memcpy_s () function will copy only part of the array.

    There are some more suspicious type conversions:
    • V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: 'wcslen (* vp ++)'. cenvarg.c 236
    • V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: ':: GlobalSize (m_hGlobalMemory)'. fileshrd.cpp 48
    • V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: 'wcslen (lpsz)'. dumpcont.cpp 31
    • V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: 'wcslen (lpsz)'. dumpcont.cpp 82
    • V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: '(cElems * sizeof (CLSID))'. ctlcore.cpp 1975
    • V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: 'wParam'. afxtoolbarslistcheckbox.cpp 94
    • V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being casted: 'nChars * sizeof (TCHAR)'. statreg.h 270

    Use before verification


    CMFCPopupMenu* CMFCCustomizeButton::CreatePopupMenu()
    {
      ....
      if (m_pWndParentToolbar->IsLocked())
      {
        pMenu->GetMenuBar()->m_pRelatedToolbar = m_pWndParentToolbar;
      }
      pMenu->m_bRightAlign = m_bMenuRightAlign &&
        (m_pWndParentToolbar->GetExStyle() & WS_EX_LAYOUTRTL) == 0;
      BOOL bIsLocked = (m_pWndParentToolbar == NULL ||
                        m_pWndParentToolbar->IsLocked());
      ....
    }

    PVS-Studio warning : V595 The 'm_pWndParentToolbar' pointer was utilized before it was verified against nullptr. Check lines: 192, 199. afxcustomizebutton.cpp 192

    At the beginning, the pointer 'm_pWndParentToolbar' is dereferenced in the expression 'm_pWndParentToolbar-> IsLocked ()'. And then it is checked for equality to zero: 'm_pWndParentToolbar == NULL'.

    Such a code is dangerous, and I think it’s not worth explaining why.

    Another such case:
    void COleControlSite::BindDefaultProperty(....)
    {
      ....
      if (pDSCWnd != NULL)
      {
        ....
        m_pDSCSite = pDSCWnd->m_pCtrlSite;
        ....
        m_pDSCSite->m_pDataSourceControl->BindProp(this, TRUE);
        if (m_pDSCSite != NULL)
          m_pDSCSite->m_pDataSourceControl->BindColumns();
      }
      ....
    }

    PVS-Studio Warning: V595 The 'm_pDSCSite' pointer was utilized before it was verified against nullptr. Check lines: 1528, 1529. occsite.cpp 1528

    Extra variables


    Extra variables are not a mistake. But superfluous, they are superfluous, and it is worth getting rid of them. Example:
    int GetImageCount() const
    {
      CRect rectImage(m_Params.m_rectImage);
      if (m_Bitmap.GetCount() == 1)
      {
        HBITMAP hBmp = m_Bitmap.GetImageWell();
        BITMAP bmp;
        if (::GetObject(hBmp, sizeof(BITMAP), &bmp) ==
            sizeof(BITMAP))
        {
          return bmp.bmHeight / m_Params.m_rectImage.Height();
        }
        return 0;
      }
      return m_Bitmap.GetCount();
    }

    PVS-Studio Warning: V808 'rectImage' object of 'CRect' type was created but was not utilized. afxcontrolrenderer.h 89 The

    rectangle 'rectImage' is created, but not used later. Extra line in the program and a few extra cycles when working Debug version.

    I give a list of found unnecessary variables: vs2003_V808.txt

    Little things


    Quite a lot of warnings can be attributed not to errors, but rather to an unsuccessful style of programming. It seems to me that the source code of Visual C ++ libraries should serve other programmers as a role model. Therefore, do not teach them bad things.

    I will list some fragments that can be improved.

    Dangerous comparisons with TRUE


    _PHNDLR __cdecl signal(int signum, _PHNDLR sigact)
    {
      ....
      if ( SetConsoleCtrlHandler(ctrlevent_capture, TRUE)
           == TRUE )
      ....
    }

    PVS-Studio Warning: V676 It is incorrect to compare the variable of BOOL type with TRUE. winsig.c 255

    Everywhere, including the MSDN, it says that it is not good to compare something with TRUE. The function can return any value other than 0, and this will be considered true. TRUE, this is 1. It is always correct to compare: Foo ()! = FALSE.

    Similar checks can be found here:
    • V676 It is incorrect to compare the variable of BOOL type with TRUE. event.cpp 448
    • V676 It is incorrect to compare the variable of BOOL type with TRUE. Correct expression is: 'retVal! = FALSE'. resourcemanager.cpp 1437
    • V676 It is incorrect to compare the variable of BOOL type with TRUE. Correct expression is: 'retVal! = FALSE'. resourcemanager.cpp 5027

    Increment


    void _To_array(
      ::Concurrency::details::_Dynamic_array<_EType>& _Array)
    {
      _LockHolder _Lock(_M_lock);
      _M_iteratorCount++;
      for(_LinkRegistry::iterator _Link = _M_links.begin();
          *_Link != NULL; _Link++)
      {
        _Array._Push_back(*_Link);
      }
    }

    Warning PVS-Studio: V803 Decreased performance. In case '_Link' is iterator it's more effective to use prefix form of increment. Replace iterator ++ with ++ iterator. agents.h 1713

    A trifle, of course, but everywhere recommend using ++ iterator. If possible, it is best to use a prefix operator to demonstrate a good style for teaching others.

    Note. Notes on this topic:If the authors of the libraries consider that it is worth exercising with the increment, then here is the list of places for this: vs2003_V803.txt .

    Incorrect warning level recovery


    #pragma warning (disable : 4311)
    SetClassLongPtr(m_hWnd,
      GCLP_HBRBACKGROUND,
      PtrToLong(reinterpret_cast(
        ::GetSysColorBrush(COLOR_BTNFACE))));
    #pragma warning (default : 4311)

    Warning V665 Possibly, the usage of '#pragma warning (default: X)' is incorrect in this context. The '#pragma warning (push / pop)' should be used instead. Check lines: 165, 167. afxbasepane.cpp 167 The

    correct way to return the previous warning state is to use "#pragma warning (push [, n])" and "#pragma warning (pop)".

    Other places: vs2003_V665.txt .

    Validation (this == NULL)


    Classics of the genre:
    _AFXWIN_INLINE CWnd::operator HWND() const
      { return this == NULL ? NULL : m_hWnd; }

    PVS-Studio warning : V704 'this == 0' expression should be avoided - this expression is always false on newer compilers, because 'this' pointer can never be NULL. afxwin2.inl 19

    Unfortunately, this is a very frequent pattern. Especially in MFC. But it’s worth it to slowly wean people from using such designs and set a good example.

    For those readers who do not yet know why this is bad, I propose to get acquainted with the documentation for the V704 diagnostics . Everything is described in sufficient detail there.

    I understand that there is no way to fix operator HWND (). Backward compatibility is important. But suddenly somewhere it can be done painlessly. The list of such checks: vs2003_V704.txt

    Conclusion


    As you can see, this is a fairly large article. But, in fact, nothing significant has been found. Visual C ++ library code is uniquely quality and debugged.

    I would be glad if this article helps to make Visual C ++ libraries a little better in the future. I note once again that the check was performed inadequately. Visual C ++ library developers will be able to do this more efficiently, as they have scripts / projects for building libraries. If there are any difficulties, I am ready to help - write to us in support.

    PS For those who missed the “ Let's play the game ” post, I suggest checking your attentiveness and passing the proposed test. At the same time I want to answer the question why the test is on time. This is the trolling of those people who claim that the errors that PVS-Studio detects are found by the eyes in 15 seconds.

    This article is in English.


    If you want to share this article with an English-speaking audience, then please use the link to the translation: Andrey Karpov. A Slipshod Check of the Visual C ++ 2013 Library (update 3) .

    Have you read the article and have a question?
    Often our articles are asked the same questions. We collected answers to them here: Answers to questions from readers of articles about PVS-Studio and CppCat, version 2014 . Please see the list.

    Also popular now: