Coverity Scan
The Crypto++ library performs regular scans of the library using Coverity Scan service with its test program cryptest.exe
. The project's page for the scan service can be found at Coverity | Cryptopp (there were character set restrictions).
Coverity kindly donates the scan service for FOSS projects. Its an awesome service and we are grateful to Coverity for providing it. The service has uncovered at least three bugs we knew existed but were not able to track down with reviews and audits (in addition to other tools missing them).
Coverity Scan is one of six analysis tools we use to help keep the library fit. You can read about the use of static and dynamic analysis at Release Process | Analysis Tools. The results of the Coverity Scan service are world readable since we believe in complete transparency. Coverity requires you have an account to view the defect reports.
The page below offers the processes and files we use to navigate the scan build process. It also offers hints for things we have discovered since the documentation is kind of scant.
As of May 2018 we have been locked out of the cryptopp account. We have not been able to run a scan since April 2018. Synopsis Tech Support was not able to help us.
Preparation
You must prepare before starting the scan build process. You will need supporting tools and files. The Crypto++ project supplies the supporting files. Coverity and your platform supplies the supporting tools.
Source Files
Obviously, you will need the Crypto++ source files. You can get the latest source files with the following. Its sometimes useful to use a new directory since it can take some time to clear a Coverity finding (especially if we exhaust our weekly limit during experimentation).
git clone https://github.com/weidai11/cryptopp.git cryptopp-coverity cd cryptopp-coverity
The remainder of the document presumes you are working from the root Crypto++ directory.
Supporting Files
The Crypto++ project uses a handful of files to support the scan build process. The files are located in the TestScript
directory even though they are not scripts per se. The files are listed below.
cryptest-coverity.cpp
- the Coverity modeling file. As it is updated, the file is re-uploaded to the Scan Service. We are still learning how to use it.
coverity-linux.txt
- the scan build procedure used on Unix, Linux and OS X. Painting with a broad brush, they are commands issued in a terminal when performing the steps in the process.
coverity-windows.txt
- the scan build procedure used on Windows. Painting with a broad brush, they are commands issued in a terminal when performing the steps in the process.
cryptest.nmake
- a Nmake based file used for building Crypto++ from the command line. The file is multipurpose even though the library supplies Visual Studio solution and project files.
Supporting Tools
You will need the following supporting tools, depending on your platform. The tools are a compiler, a linker and archiver and a non-anemic Make like GNU Make on Unix or Nmake on Windows. Windows users don't need Visual Studio. Instead, they can use the free Visual C++ Build Tools.
Be sure your tools are on-path. You should open a Developer Command Prompt for Visual Studio to ensure the Visual C++ Build Tools are on path on Windows.
Unix, Linux, OS X
- Build Essentials (gmake, gcc, ld, ar, etc)
- tar
- curl
Windows
- Visual C++ Build Tools (cl.exe, link.exe, nmake.exe)
- 7zip
- curl
Self-Build Installation
The Self-Build Installation instructions that follow are for Unix, Linux, OS X and Windows. The installation of the Coverity client component is simple once you find it on Coverity's website. The client component is called self-build. To navigate to it, Click Submit Build on the right side of the page. Then click the big red button labeled Download Coverity Scan Self-Build. You must be logged into the service to download the self-build client.
The cov-analysis-*
files are large. For example, Linux's package is cov-analysis-linux-8.5.0.3
, and its 480 MB compressed. Within cov-analysis-*
is cov-build
. You only need the bin/
on path to ensure cov-build
is accessible. The instructions below provides recipes for Unix, Linux and OS X.
Unix, Linux, OS X
First unpack the tarball and move it into /usr/local/bin
. Be sure to use the correct tarball name.
$ tar xzf cov-analysis-linux-8.5.0.3.tar.gz $ sudo mv cov-analysis-linux-8.5.0.3 /usr/local/bin/
For OS X only remove the quarantine bits:
$ sudo xattr -r -d com.apple.quarantine /usr/local/bin/cov-analysis-macosx-8.5.0.3/bin/
Second, create a script in /usr/local/bin/
called cov-build
which sets the path and calls the real cov-build
:
$ cat /usr/local/bin/cov-build #!/usr/bin/env bash PATH=/usr/local/bin/cov-analysis-linux-8.5.0.3/bin:$PATH; /usr/local/bin/cov-analysis-linux-8.5.0.3/bin/cov-build "$@"
Third, make the script executable:
$ sudo chmod a+x /usr/local/bin/cov-build
Finally, test it:
$ command -v cov-build /usr/local/bin/cov-build $ cov-build --help Coverity Build Capture (32-bit) version 8.5.0.3 on Linux 3.13.0-96-generic i686 Internal version numbers: db70178643 p-kent-push-26368.949 ...
Windows
Download and install cov-build
(from cov-analysis-windows.zip), 7zip and cURL. If you don't have Visual Studio, then you can use Visual C++ Build Tools. Visual C++ Build Tools provides everything you need for a scan build submission. Install then in Program Files or the Windows System directory.
Generally speaking, a path without spaces causes the least trouble, so C:\Windows
is often a good choice. Just move the tools' topmost directory into C:\Windows
, and then ensure the binary is on path (see two paragraphs down).
Be sure 7z.exe
and curl.exe
are on path, and cacerts.pem
is available to cURL. See Configuring System and User Environment Variables from MSDN for instructions on modifying your path. The additional paths should include similar to the following:
- C:\Windows\cov-analysis-win64-8.5.0.3\bin
- C:\Windows\curl_7_50_3
- C:\Windows\7-Zip
You can verify the programs on path by checking their version from the command line:
C:\Users\cryptopp>curl.exe --version curl 7.50.3 (x86_64-pc-win32) libcurl/7.50.3 OpenSSL/1.0.2j nghttp2/1.15.0 Protocols: dict file ftp ftps gopher http https imap imaps ldap pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IPv6 Largefile NTLM SSL HTTP2
Scan Building
The Scan Building instructions that follow are for Unix, Linux, OS X and Windows. The process creates a binary with additional Coverity instrumentation that can be analyzed by the Scan Service.
Unix, Linux, and Windows work as expected. OS X is having trouble. We have not been able to get the scan service client to build the library on OS X 10.8 or 10.9.
Unix and Linux
The project uses the GNUmakefile
and cov-build
for Unix and Linux. The script should be run from the root of the Crypto++ directory. Its really just a text file, and we copy/paste it into a terminal. The script is shown below, and it relies on two variables.
COVERITY_SCAN_NAME
is the friendly name displayed on the Crypto++ project Coverity scan page. CRYPTOPP_COVERITY_TOKEN
is the token Coverity provides to access the service.
In the script below, the order of arguments when building the cov-build
is significant. CXXFLAGS
must proceed the command. A temporary directly like --dir cov-int
must be supplied as an argument. Finally we tell the command to invoke our makefile with make -j 2
.
$ cat coverity-linux.txt reset make distclean &>/dev/null # Usually we test with these flags # CXXFLAGS="-DNDEBUG -g3 -O2" # Testing for Issue 302 (http://github.com/weidai11/cryptopp/issues/302) CXXFLAGS="-DNDEBUG -g2 -O3 -march=i686 -msse -msse2 -msse3 -mssse3 -mno-aes" cov-build --dir cov-int make -j 2 tar czvf cryptopp.tgz cov-int CRYPTOPP_COVERITY_TOKEN=XXXXXXXXXXXXXXXX COVERITY_SCAN_NAME="Rijndael-AliasedTable-SSE2-Linux-i686" curl \ --form token="$CRYPTOPP_COVERITY_TOKEN" \ --form [email protected] \ --form [email protected] \ --form version="$COVERITY_SCAN_NAME" \ --form description="$COVERITY_SCAN_NAME" \ https://scan.coverity.com/builds?project=Cryptopp
OS X
The project uses the GNUmakefile
and cov-build
for OS X. The procedure is the same as Unix and Linux. If all goes well on OS X, then the following will work as expected. If things don't go well, then there are two work-arounds, and one of them should work.
reset make distclean &>/dev/null CXXFLAGS="-DNDEBUG -g2 -O3" cov-build --dir cov-int make -j 2 tar czvf cryptopp.tgz cov-int CRYPTOPP_COVERITY_TOKEN=XXXXXXXXXXXXXXXX COVERITY_SCAN_NAME="Cryptopp-OSX-x86_64" curl \ --form token="$CRYPTOPP_COVERITY_TOKEN" \ --form [email protected] \ --form [email protected] \ --form version="$COVERITY_SCAN_NAME" \ --form description="$COVERITY_SCAN_NAME" \ https://scan.coverity.com/builds?project=Cryptopp
First Work-around
If the process fails with the following error:
Coverity Build Capture (64-bit) version 8.5.0.3 on Darwin 12.6.0 x86_64 Internal version numbers: db70178643 p-kent-push-26368.949 Platform info: Sysname = Darwin Release = 12.6.0 Machine = x86_64 [ERROR] This platform is not supported by Coverity. [ERROR] See documentation for the list of supported platforms.
Then Flash Sheridan and Caleb from Stack Overflow suggests using COVERITY_UNSUPPORTED=1
.
$ COVERITY_UNSUPPORTED=1 CXXFLAGS="-DNDEBUG -g3 -O2" cov-build --dir cov-int make -j 8
Unfortunately, the workaround failed on OS X 10.8.5:
[WARNING] Emitted 1 C/C++ compilation units (0%) successfully 1 C/C++ compilation units (0%) are ready for analysis For more details, please look at: /Users/cryptopp/cov-int/build-log.txt
Second Work-around
Check you build log and see if it fingers Xcode 5.x, and produces multiple errors like the following.
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/ clang/5.0/include/stddef.h", line 29: error #109: expression preceding parentheses of apparent call must have (pointer-to-) function type #if !defined(_PTRDIFF_T) || __has_feature(modules) "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/ clang/5.0/include/stddef.h", line 31: error #59: function call is not allowed in a constant expression #if !__has_feature(modules)
The second work-around is to use a different compiler with the first work-around. Below, we use MacPorts Clang 3.7 to perform a scan build. You may need to use -std=c++11
to avoid C++03 findings based on C++11 code.
$ CXX=/opt/local/bin/clang++-mp-3.7 COVERITY_UNSUPPORTED=1 CXXFLAGS="-DNDEBUG -g3 -O2 -std=c++11" cov-build --dir cov-int make -j 8 Coverity Build Capture (64-bit) version 8.5.0.3 on Darwin 12.6.0 x86_64 Internal version numbers: db70178643 p-kent-push-26368.949 /opt/local/bin/clang++-mp-3.7 -DNDEBUG -g3 -O2 -std=c++11 -fPIC -march=native -pipe -c cryptlib.cpp /opt/local/bin/clang++-mp-3.7 -DNDEBUG -g3 -O2 -std=c++11 -fPIC -march=native -pipe -c cpu.cpp ... Emitted 134 C/C++ compilation units (100%) successfully 134 C/C++ compilation units (100%) are ready for analysis The cov-build utility completed successfully.
Windows
The project uses the cryptest.nmake
and cov-build
for Windows. cryptest.nmake
is the equivalent of the Unix and Linux makefile. The scan build is performed from a Developer Tools command line prompt similar to Unix and Linux. You may be able to perform a scan build with msbuild
or Visual Studio, but we have not attempted it.
cryptest.nmake
has a selection of CXXFLAGS
for testing under X86, X64 ad ARM. You should open cryptest.nmake
and uncomment the one that matches your Developer Tools command line prompt. Below is the block for X86, and you would use it if you opened an X86 Developer Tools command line prompt.
!IF "$(PLATFORM)" == "x86" || "$(PLATFORM)" == "X86" # CXXFLAGS = $(CXXFLAGS) /arch:SSE2 # CXXFLAGS = $(CXXFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP # CXXFLAGS = $(CXXFLAGS) /DWINAPI_FAMILY=WINAPI_FAMILY_APP AS = ml.exe ASFLAGS = /nologo /D_M_X86 /W3 /Cx /Zi /safeseh LIB_SRCS = $(LIB_SRCS) rdrand.cpp rdrand.asm LIB_OBJS = $(LIB_OBJS) rdrand.obj rdrand-x86.obj LDLIBS = $(LDLIBS) ws2_32.lib kernel32.lib !ENDIF
After you uncomment the CXXFLAGS
of interest, perform the following from the command line prompt. COVERITY_SCAN_NAME
is the friendly name displayed on the Crypto++ Coverity scan page. CRYPTOPP_COVERITY_TOKEN
is the token which Coverity provides to access the service.
C:\cryptopp> type coverity-windows.txt cls del /f cryptopp.zip rmdir /q /s cov-int nmake /f cryptest.nmake clean cov-build.exe --dir cov-int nmake /f cryptest.nmake 7z.exe a -r -tzip cryptopp.zip cov-int set CRYPTOPP_COVERITY_TOKEN=XXXXXXXXXXXXXXXX set COVERITY_SCAN_NAME=Rijndael-AliasedTable-SSE2-Windows-X64 curl.exe ^ --form token="%CRYPTOPP_COVERITY_TOKEN%" ^ --form [email protected] ^ --form [email protected] ^ --form version="%COVERITY_SCAN_NAME%" ^ --form description="%COVERITY_SCAN_NAME%" ^ https://scan.coverity.com/builds?project=Cryptopp
Errata and Fodder
The following is a collection of errata items.
Self-signed Certificate
If you receive an error similar to:
$ curl \ --form token="$CRYPTOPP_COVERITY_TOKEN" \ --form [email protected] \ --form [email protected] \ --form version="$COVERITY_SCAN_NAME" \ --form description="$COVERITY_SCAN_NAME" \ https://scan.coverity.com/builds?project=Cryptopp curl: (60) SSL certificate problem: self signed certificate in certificate chain More details here: https://curl.haxx.se/docs/sslcerts.html ...
Then you should update the certificate bundle used by cURL. To update the certificate bundle run build-cacert.sh
from Noloader's GitHub. After updating the bundle re-reun the command with CURL_CA_BUNDLE
set to the bundle:
$ CURL_CA_BUNDLE="$HOME/.cacert/cacert.pem" curl \ --form token="$CRYPTOPP_COVERITY_TOKEN" \ --form [email protected] \ --form [email protected] \ --form version="$COVERITY_SCAN_NAME" \ --form description="$COVERITY_SCAN_NAME" \ https://scan.coverity.com/builds?project=Cryptopp
OS X and UNCAUGHT_EXCEPT
When scan building on OS X 10.8.5 with both work-arounds in place, we found Coverity flagged a C++03 issue under a C++11 compiler. Its due to out use of CRYPTOPP_THROW
macro for C++11 and throwing destructors. You can safely ignore it:
CID 171374 (1 of 1): Uncaught exception (UNCAUGHT_EXCEPT) exn_spec_violation: An exception of type CryptoPP::InvalidArgument is thrown but the throw list throw() doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate(). fun_call_w_exception: Called function throws an exception of type CryptoPP::InvalidArgument. 17 class GFP2Element { ... };