[cfe-dev] clang static analyzer fails to find bug it found previously

Dennis Cote DennisC at harding.ca
Wed Apr 3 11:25:08 PDT 2013


Hi,

 

This is my first post to this list. I hope someone here can help.

 

I have built LLVM and Clang from source (SVN trunk head today) using
Mingw/MSYS and CMake in order to use the static analyzer to check some C
code. 

 

To test my builds I have been using the source files for AStyle as a
test case. I added a unpaired malloc call to astyle_main.cpp to ensure a
bug would be found. The static analyzer is functioning and detects that
bug (as well as a couple of other "values stored is not read" errors).

 

In earlier test runs a few days ago the static analyzer found what I
believe is a real bug in the AStyle source and gave me a nice memory is
never released report with HTML etc which I printed. Since then I have
rebuilt LLVM and Clang several times (while changing build tools etc.).
Now I no longer get the same bug report for that section of code.

 

The code is question is fairly short so I have copied it below. It does
two allocations, but doesn't free the first allocation if the second
fails. I believe the delete [] outBuf that I have commented out below is
required for correct operation without a memory leak.

 

string ASConsole::getNumberFormat(int num, size_t lcid) const

{

                // Compilers that don't support C++ locales should still
support this assert.

                // The C locale should be set but not the C++.

                // This function is not necessary if the C++ locale is
set.

                assert(locale().name() == "C");

                // convert num to a string

                stringstream alphaNum;

                alphaNum << num;

                string number = alphaNum.str();

                if (useAscii)

                                return number;

 

                // format the number using the Windows API

                if (lcid == 0)

                                lcid = LOCALE_USER_DEFAULT;

                int outSize = ::GetNumberFormat(lcid, 0, number.c_str(),
NULL, NULL, 0);

                char* outBuf = new(nothrow) char[outSize];

                if (outBuf == NULL)

                                return number;

                ::GetNumberFormat(lcid, 0, number.c_str(), NULL, outBuf,
outSize);

 

                // remove the decimal

                string formattedNum(outBuf);

                int decSize = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL,
NULL, 0);

                char* decBuf = new(nothrow) char[decSize];

                if (decBuf == NULL) {

                                // delete [] outBuf;

                                return number;

                }

                ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, decBuf, decSize);

                size_t i = formattedNum.rfind(decBuf);

                if (i != string::npos)

                                formattedNum.erase(i);

                if (!formattedNum.length())

                                formattedNum = "0";

 

                delete [] outBuf;

                delete [] decBuf;

                return formattedNum;

}

 

One possibility is that the code is not compiled at all during the
static analyzer build. This function inside a #ifdef _WIN32/#endif pair.
I don't know why the definition would have changed, but I suspect it
has. 

 

To check I preprocessed  the file and I can see that _WIN32 is defined,
at least by g++.

 

$ g++ -E -dM ../../src/astyle_main.cpp | grep -i "_win32"

#define VER_PLATFORM_WIN32_NT 2

#define FACILITY_WIN32 7

#define _WIN32_WINNT WINVER

#define LHashValOfName(l,n) LHashValOfNameSys(SYS_WIN32,l,n)

#define __GTHREAD_HIDE_WIN32API 1

#define SERVICE_WIN32_OWN_PROCESS 16

#define WIN32 1

#define _WIN32 1

#define SERVICE_WIN32_SHARE_PROCESS 32

#define __WIN32__ 1

#define SERVICE_WIN32
(SERVICE_WIN32_OWN_PROCESS|SERVICE_WIN32_SHARE_PROCESS)

#define __WIN32 1

#define __RPC_WIN32__

#define VER_PLATFORM_WIN32_WINDOWS 1

#define SERVICE_TYPE_ALL
(SERVICE_WIN32|SERVICE_ADAPTER|SERVICE_DRIVER|SERVICE_INTERACTIVE_PROCES
S)

#define HRESULT_FROM_WIN32(x)
(x?((HRESULT)(((x)&0x0000FFFF)|(FACILITY_WIN32<<16)|0x80000000)):0)

#define GCC_GTHR_WIN32_H

#define VER_PLATFORM_WIN32s 0

 

So I repeated with clang++ in case the wrong compiler is being used for
the build, but it defines _WIN32 as well

 

$ clang++ -E -dM ../../src/astyle_main.cpp | grep -i "win32"

#define FACILITY_WIN32 7

#define GCC_GTHR_WIN32_H

#define HRESULT_FROM_WIN32(x)
(x?((HRESULT)(((x)&0x0000FFFF)|(FACILITY_WIN32<<16)|0x80000000)):0)

#define LHashValOfName(l,n) LHashValOfNameSys(SYS_WIN32,l,n)

#define SERVICE_TYPE_ALL
(SERVICE_WIN32|SERVICE_ADAPTER|SERVICE_DRIVER|SERVICE_INTERACTIVE_PROCES
S)

#define SERVICE_WIN32
(SERVICE_WIN32_OWN_PROCESS|SERVICE_WIN32_SHARE_PROCESS)

#define SERVICE_WIN32_OWN_PROCESS 16

#define SERVICE_WIN32_SHARE_PROCESS 32

#define VER_PLATFORM_WIN32_NT 2

#define VER_PLATFORM_WIN32_WINDOWS 1

#define VER_PLATFORM_WIN32s 0

#define WIN32 1

#define _WIN32 1

#define _WIN32_WINNT WINVER

#define __GTHREAD_HIDE_WIN32API 1

#define __RPC_WIN32__

#define __WIN32 1

#define __WIN32__ 1 

 

So my question is why has the static analyzer stopped detecting the
memory leak bug it found previously? Does anyone have any ideas or
suggestions?

 

Thanks.

 

Dennis Cote

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130403/65e48285/attachment.html>


More information about the cfe-dev mailing list