Can visual c++ 2013 do what Purify and Quntify do?

1.6k views Asked by At

We develop a console application using VC 6.0, Purify, PC-Lint, and Quantify on Windows XP. VC6 will not work on Windows 7 and 8. I have looked at our options for development environments if we were to upgrade to Windows 8. Our application is standard C++ console application. Virtually all of our users are on Linux. Does anyone have experience with VC++ Pro 2013 or 2012 for cross platform c++ development? Specifically, can it do memory bounds checking, memory leak checking, and code performance analysis (how much time each function takes)?

1

There are 1 answers

1
jww On

Can visual c++ 2013 do what Purify and Quantify do?

Well, its not so much "can one do everything the other does". Its more like an intersection, and use them all to get the most coverage.

Purify is a runtime checker, so it will usually outperform Visual Studio's built-in memory checking facilities. But Purify does not do static analysis, so you will need to use Visual Studio. Its one big partnership.


I have looked at our options for development environments ... Our application is [cross-platform] standard C++ console application.

The Bike Shedding begins... This is a great opportunity since you are writing portable code. So many folks write code that runs on one platform, they loose the diagnostics from other tools on other platforms.

Everything below is free (except Enterprise Code Analysis under Visual Studio Enterprise), and if you can get through the process cleanly then you'll have fairly solid code.

Windows

Use Visual Studio (any edition) and turn up warnings. They include /WAll and /W4. If you have Visual Studio Enterprise, be sure to add Enterprise Code Analysis or add the /analyze switch.

You get basic memory checking in Visual Studio. I'm not sure how the latest Purity works with it. (I don't use it because I write cross-platform code and use Linux for the heavy duty memory checking).

There's other things you should be doing for a Windows platform. You can find a discussion of development toolchains at OWASP's C-Based Toolchain Hardening.

Linux

Be sure to support GCC, Clang, and ICC. When using them be sure to crank up warnings, including -Wall, -Wextra, and -Wconversion. GCC is the mainstay, and your code probably works well on it. ICC is Intel's compiler, and its ruthless about removing undefined behavior. If your code breaks under ICC, its probably because the compiler/optimizer removed some undefined behavior (see Clang's undefined sanitizer below on how to locate the offending code).

Clang 3.3 really shines with its sanitizers (Clang 3.2 and below don't have them). Be sure to run with -fsanitize=address and -fsanitize=undefined. The sanitizers add runtime checkers and looks for violations during execution. The more self tests you have, the better. A complete list of sanitizers is available a Clang's Controlling Code Generation.

The Clang 3.3 recipes are below. They include how to fetch Clang, hot to build Clang, and how to execute your tests using the santizers.

After you get through compilation with GCC, Clang, and ICC, run the program under Valgrind. Valgrind is another dynamic memory checker.

There's other things you should be doing for a Linux platform. You can find a discussion of development toolchains at OWASP's C-Based Toolchain Hardening.


To download and build Clang 3.3 with the latest:

wget http://llvm.org/releases/3.3/llvm-3.3.src.tar.gz
wget http://llvm.org/releases/3.3/cfe-3.3.src.tar.gz
wget http://llvm.org/releases/3.3/compiler-rt-3.3.src.tar.gz
# wget http://llvm.org/releases/3.3/lldb-3.3.src.tar.gz
tar xvf llvm-3.3.src.tar.gz
cd llvm-3.3.src/tools
tar xvf ../../cfe-3.3.src.tar.gz
mv cfe-3.3.src clang
# tar xvf ../../lldb-3.3.src.tar.gz
# mv lldb-3.3.src/ lldb
cd ..
cd projects
tar xvf ../../compiler-rt-3.3.src.tar.gz
mv compiler-rt-3.3.src/ compiler-rt
cd ..
./configure --enable-optimized --prefix=/usr/local
make -j4

# Pause to wait for the password prompt
read -p "Press [Enter] key to install..."

# Begin install
sudo make install

# Install does not copy asan_symbolize.py
sudo cp projects/compiler-rt/lib/asan/scripts/asan_symbolize.py /usr/local/bin

# Install does not install scan-build and scan-view
# Perform the copy, and/or put them on-path
sudo mkdir /usr/local/bin/scan-build
sudo cp -r tools/clang/tools/scan-build /usr/local/bin
sudo mkdir /usr/local/bin/scan-view
sudo cp -r tools/clang/tools/scan-view /usr/local/bin

To use Clang:

export CC=/usr/local/bin/clang
export CXX=/usr/local/bin/clang++
export CFLAGS="-g3 -fsanitize=undefined"
export CXXFLAGS="-g3 -fsanitize=undefined -fno-sanitize=vptr"

./configure

make

make check | /usr/local/bin/asan_symbolize.py

If you get any memory issue it will look similar to the following (taken from Squid 3.3.9 Self Test Failures on Mac OS X 10.8):

==76794==ERROR: AddressSanitizer: global-buffer-overflow on address
0x000105ad50d2 at pc 0x105a364ab bp 0x7fff5a23f720 sp 0x7fff5a23f718
READ of size 19 at 0x000105ad50d2 thread T0
    #0 0x105a364aa in MemBuf::append MemBuf.cc:248
    #1 0x105a4ef57 in testHttpReply::testSanityCheckFirstLine
testHttpReply.cc:197
    #2 0x1068d71d1 in CppUnit::TestCaseMethodFunctor::operator()() const (in
libcppunit-1.12.1.dylib) + 33
    #3 0x1068cd9a3 in CppUnit::DefaultProtector::protect(CppUnit::Functor
const&, CppUnit::ProtectorContext const&) (in libcppunit-1.12.1.dylib) + 35
    #4 0x1068d4d88 in CppUnit::ProtectorChain::ProtectFunctor::operator()()
const (in libcppunit-1.12.1.dylib) + 24
    #5 0x1068d45e8 in CppUnit::ProtectorChain::protect(CppUnit::Functor const&,
CppUnit::ProtectorContext const&) (in libcppunit-1.12.1.dylib) + 456
    #6 0x1068dcf78 in CppUnit::TestResult::protect(CppUnit::Functor const&,
CppUnit::Test*, std::string const&) (in libcppunit-1.12.1.dylib) + 56
    #7 0x1068d6d1d in CppUnit::TestCase::run(CppUnit::TestResult*) (in
libcppunit-1.12.1.dylib) + 285
    #8 0x1068d77b6 in
CppUnit::TestComposite::doRunChildTests(CppUnit::TestResult*) (in
libcppunit-1.12.1.dylib) + 54
    #9 0x1068d76be in CppUnit::TestComposite::run(CppUnit::TestResult*) (in
libcppunit-1.12.1.dylib) + 30
    #10 0x1068d77b6 in
CppUnit::TestComposite::doRunChildTests(CppUnit::TestResult*) (in
libcppunit-1.12.1.dylib) + 54
    #11 0x1068d76be in CppUnit::TestComposite::run(CppUnit::TestResult*) (in
libcppunit-1.12.1.dylib) + 30
    #12 0x1068dcde1 in CppUnit::TestResult::runTest(CppUnit::Test*) (in
libcppunit-1.12.1.dylib) + 33
    #13 0x1068de9a5 in CppUnit::TestRunner::run(CppUnit::TestResult&,
std::string const&) (in libcppunit-1.12.1.dylib) + 53
    #14 0x105a55a97 in main testMain.cc:31
    #15 0x7fff90af07e0 in start (in libdyld.dylib) + 0
    #16 0x0
0x000105ad50d2 is located 46 bytes to the left of global variable '.str28' from
'tests/testHttpReply.cc' (0x105ad5100) of size 16
  '.str28' is ascii string 'HTTP/1.1 -000

0x000105ad50d2 is located 0 bytes to the right of global variable '.str27' from
'tests/testHttpReply.cc' (0x105ad50c0) of size 18
  '.str27' is ascii string 'HTTP/1.10 Okay

And here's what undefined behavior and an illegal shift looks like (taken from Postgres's Clang 3.3 findings and Illegal Shifts):

make check
...

vacuuming database template1 ... localtime.c:127:20: runtime error:
left shift of negative value -1
pg_lzcompress.c:601:5: runtime error: left shift of negative value -68
pg_lzcompress.c:601:5: runtime error: left shift of negative value -68
pg_lzcompress.c:385:16: runtime error: left shift of negative value -68
pg_lzcompress.c:615:4: runtime error: left shift of negative value -68

If you are failing under Intel's ICC, then be sure to run it under Clang with -fsanitize=undefined because ICC will silently remove any offending code. Its the easiest way I've found to find the offending code.