2008-12-18 22:28:57 +01:00
/*
2009-01-21 21:04:20 +01:00
* Cppcheck - A tool for static C / C + + code analysis
2019-02-09 07:24:06 +01:00
* Copyright ( C ) 2007 - 2019 Cppcheck team .
2008-12-18 22:28:57 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2008-12-18 22:28:57 +01:00
*/
# include "cppcheckexecutor.h"
2017-05-27 04:33:47 +02:00
2016-12-08 22:46:44 +01:00
# include "analyzerinfo.h"
2013-09-04 06:18:22 +02:00
# include "cmdlineparser.h"
2017-05-27 04:33:47 +02:00
# include "config.h"
2008-12-18 22:28:57 +01:00
# include "cppcheck.h"
2013-09-04 06:18:22 +02:00
# include "filelister.h"
2017-05-27 04:33:47 +02:00
# include "importproject.h"
# include "library.h"
2013-09-04 06:18:22 +02:00
# include "path.h"
# include "pathmatch.h"
# include "preprocessor.h"
2017-05-27 04:33:47 +02:00
# include "settings.h"
# include "standards.h"
# include "suppressions.h"
2013-09-04 06:18:22 +02:00
# include "threadexecutor.h"
2015-11-14 19:59:22 +01:00
# include "utils.h"
2018-02-10 15:34:49 +01:00
# include "checkunusedfunctions.h"
2014-06-28 14:05:18 +02:00
2017-09-07 13:02:44 +02:00
# include <csignal>
# include <cstdio>
2009-03-06 01:03:31 +01:00
# include <cstdlib> // EXIT_SUCCESS and EXIT_FAILURE
2011-08-11 16:34:59 +02:00
# include <cstring>
2014-06-28 14:05:18 +02:00
# include <iostream>
2017-05-27 04:33:47 +02:00
# include <list>
# include <utility>
# include <vector>
2011-10-09 20:14:44 +02:00
2018-04-03 00:41:13 +02:00
# if !defined(NO_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && !defined(__MINGW32__) && !defined(__OS2__)
2014-03-16 12:04:13 +01:00
# define USE_UNIX_SIGNAL_HANDLING
2014-11-14 23:40:53 +01:00
# include <unistd.h>
2014-11-15 20:10:34 +01:00
# if defined(__APPLE__)
# define _XOPEN_SOURCE // ucontext.h APIs can only be used on Mac OSX >= 10.7 if _XOPEN_SOURCE is defined
# include <ucontext.h>
2017-05-27 04:33:47 +02:00
2014-11-15 20:10:34 +01:00
# undef _XOPEN_SOURCE
2016-05-09 00:48:20 +02:00
# elif !defined(__OpenBSD__)
2014-11-15 20:10:34 +01:00
# include <ucontext.h>
# endif
2014-11-14 23:40:53 +01:00
# ifdef __linux__
# include <sys/syscall.h>
# include <sys/types.h>
# endif
2014-03-16 12:04:13 +01:00
# endif
2016-11-29 09:44:50 +01:00
# if !defined(NO_UNIX_BACKTRACE_SUPPORT) && defined(USE_UNIX_SIGNAL_HANDLING) && defined(__GNUC__) && defined(__GLIBC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__SVR4) && !defined(__QNX__)
2014-06-28 14:05:18 +02:00
# define USE_UNIX_BACKTRACE_SUPPORT
# include <cxxabi.h>
# include <execinfo.h>
# endif
2014-03-22 09:57:43 +01:00
# if defined(_MSC_VER)
2014-03-17 19:11:00 +01:00
# define USE_WINDOWS_SEH
2014-06-29 18:57:48 +02:00
# include <DbgHelp.h>
# include <TCHAR.H>
2017-05-27 04:33:47 +02:00
# include <Windows.h>
# include <excpt.h>
2014-03-16 12:04:13 +01:00
# endif
2015-11-21 16:50:57 +01:00
2019-07-15 18:11:11 +02:00
/*static*/ FILE * CppCheckExecutor : : mExceptionOutput = stdout ;
2015-11-21 16:50:57 +01:00
2008-12-18 22:28:57 +01:00
CppCheckExecutor : : CppCheckExecutor ( )
2019-07-15 20:58:07 +02:00
: mSettings ( nullptr ) , mLatestProgressOutputTime ( 0 ) , mErrorOutput ( nullptr ) , mShowAllErrors ( false )
2008-12-18 22:28:57 +01:00
{
}
CppCheckExecutor : : ~ CppCheckExecutor ( )
{
2019-07-15 18:16:07 +02:00
delete mErrorOutput ;
2008-12-18 22:28:57 +01:00
}
2010-08-31 20:32:26 +02:00
bool CppCheckExecutor : : parseFromArgs ( CppCheck * cppcheck , int argc , const char * const argv [ ] )
{
2012-04-06 14:19:26 +02:00
Settings & settings = cppcheck - > settings ( ) ;
CmdLineParser parser ( & settings ) ;
2018-04-23 12:39:47 +02:00
const bool success = parser . parseFromArgs ( argc , argv ) ;
2010-08-31 20:32:26 +02:00
2011-10-13 20:53:06 +02:00
if ( success ) {
2018-04-23 12:39:47 +02:00
if ( parser . getShowVersion ( ) & & ! parser . getShowErrorMessages ( ) ) {
2015-11-25 22:37:38 +01:00
const char * const extraVersion = cppcheck - > extraVersion ( ) ;
2012-02-29 20:57:48 +01:00
if ( * extraVersion ! = 0 )
2011-08-11 16:34:59 +02:00
std : : cout < < " Cppcheck " < < cppcheck - > version ( ) < < " ( "
2012-02-18 11:55:05 +01:00
< < extraVersion < < ' ) ' < < std : : endl ;
2011-08-11 16:34:59 +02:00
else
std : : cout < < " Cppcheck " < < cppcheck - > version ( ) < < std : : endl ;
2010-08-31 20:32:26 +02:00
}
2018-04-23 12:39:47 +02:00
if ( parser . getShowErrorMessages ( ) ) {
2019-07-15 18:31:12 +02:00
mShowAllErrors = true ;
2017-07-29 18:56:22 +02:00
std : : cout < < ErrorLogger : : ErrorMessage : : getXMLHeader ( ) ;
2010-08-31 20:32:26 +02:00
cppcheck - > getErrorMessages ( ) ;
2017-07-29 18:56:22 +02:00
std : : cout < < ErrorLogger : : ErrorMessage : : getXMLFooter ( ) < < std : : endl ;
2010-08-31 20:32:26 +02:00
}
2011-01-27 09:30:53 +01:00
2018-04-23 12:39:47 +02:00
if ( parser . exitAfterPrinting ( ) ) {
2014-06-05 09:28:04 +02:00
settings . terminate ( ) ;
return true ;
}
2011-11-05 18:15:03 +01:00
} else {
2014-06-05 09:28:04 +02:00
return false ;
2010-08-31 20:32:26 +02:00
}
2011-01-09 09:29:38 +01:00
// Check that all include paths exist
{
2018-04-04 21:11:23 +02:00
for ( std : : list < std : : string > : : iterator iter = settings . includePaths . begin ( ) ;
2016-01-03 16:18:17 +01:00
iter ! = settings . includePaths . end ( ) ;
2011-10-13 20:53:06 +02:00
) {
2011-01-11 20:03:18 +01:00
const std : : string path ( Path : : toNativeSeparators ( * iter ) ) ;
2011-04-16 11:19:56 +02:00
if ( FileLister : : isDirectory ( path ) )
+ + iter ;
2011-10-13 20:53:06 +02:00
else {
2015-07-25 17:39:44 +02:00
// If the include path is not found, warn user and remove the non-existing path from the list.
2017-04-11 11:49:09 +02:00
if ( settings . isEnabled ( Settings : : INFORMATION ) )
2016-05-20 21:32:59 +02:00
std : : cout < < " (information) Couldn't find path given by -I ' " < < path < < ' \' ' < < std : : endl ;
2016-01-03 16:18:17 +01:00
iter = settings . includePaths . erase ( iter ) ;
2011-01-09 09:29:38 +01:00
}
}
}
2015-07-23 14:01:33 +02:00
// Output a warning for the user if he tries to exclude headers
bool warn = false ;
2018-04-23 12:39:47 +02:00
const std : : vector < std : : string > & ignored = parser . getIgnoredPaths ( ) ;
for ( const std : : string & i : ignored ) {
if ( Path : : isHeader ( i ) ) {
2015-07-23 14:01:33 +02:00
warn = true ;
break ;
}
}
if ( warn ) {
std : : cout < < " cppcheck: filename exclusion does not apply to header (.h and .hpp) files. " < < std : : endl ;
std : : cout < < " cppcheck: Please use --suppress for ignoring results from the header files. " < < std : : endl ;
2010-08-31 20:32:26 +02:00
}
2018-04-23 12:39:47 +02:00
const std : : vector < std : : string > & pathnames = parser . getPathNames ( ) ;
2011-08-06 11:29:51 +02:00
2011-10-02 11:02:07 +02:00
# if defined(_WIN32)
2015-07-23 14:01:33 +02:00
// For Windows we want case-insensitive path matching
const bool caseSensitive = false ;
2011-10-02 11:02:07 +02:00
# else
2015-07-23 14:01:33 +02:00
const bool caseSensitive = true ;
2011-10-02 11:02:07 +02:00
# endif
2015-07-23 14:01:33 +02:00
if ( ! pathnames . empty ( ) ) {
// Execute recursiveAddFiles() to each given file parameter
2018-04-04 21:02:13 +02:00
const PathMatch matcher ( ignored , caseSensitive ) ;
2019-04-07 12:07:47 +02:00
for ( const std : : string & pathname : pathnames )
2019-07-15 18:24:27 +02:00
FileLister : : recursiveAddFiles ( mFiles , Path : : toNativeSeparators ( pathname ) , mSettings - > library . markupExtensions ( ) , matcher ) ;
2010-10-22 17:09:50 +02:00
}
2011-01-31 14:25:51 +01:00
2019-07-15 18:21:52 +02:00
if ( mFiles . empty ( ) & & settings . project . fileSettings . empty ( ) ) {
2015-07-23 14:01:33 +02:00
std : : cout < < " cppcheck: error: could not find or open any of the paths given. " < < std : : endl ;
if ( ! ignored . empty ( ) )
std : : cout < < " cppcheck: Maybe all paths were ignored? " < < std : : endl ;
2011-01-31 14:25:51 +01:00
return false ;
}
2014-09-02 16:10:51 +02:00
return true ;
2010-08-31 20:32:26 +02:00
}
2009-03-06 01:03:31 +01:00
int CppCheckExecutor : : check ( int argc , const char * const argv [ ] )
2008-12-18 22:28:57 +01:00
{
2011-05-02 14:58:16 +02:00
Preprocessor : : missingIncludeFlag = false ;
2014-05-03 19:31:15 +02:00
Preprocessor : : missingSystemIncludeFlag = false ;
2011-05-02 14:58:16 +02:00
2018-02-10 15:34:49 +01:00
CheckUnusedFunctions : : clear ( ) ;
2011-02-16 02:12:15 +01:00
CppCheck cppCheck ( * this , true ) ;
2009-02-19 23:21:18 +01:00
2015-11-14 19:59:22 +01:00
const Settings & settings = cppCheck . settings ( ) ;
2019-07-15 18:24:27 +02:00
mSettings = & settings ;
2012-04-06 14:19:26 +02:00
2012-04-08 10:05:44 +02:00
if ( ! parseFromArgs ( & cppCheck , argc , argv ) ) {
return EXIT_FAILURE ;
}
2014-06-05 09:28:04 +02:00
if ( settings . terminated ( ) ) {
return EXIT_SUCCESS ;
}
2014-03-16 12:04:13 +01:00
if ( cppCheck . settings ( ) . exceptionHandling ) {
return check_wrapper ( cppCheck , argc , argv ) ;
}
2018-04-04 21:11:23 +02:00
return check_internal ( cppCheck , argc , argv ) ;
2014-03-16 12:04:13 +01:00
}
2017-08-21 12:52:15 +02:00
void CppCheckExecutor : : setSettings ( const Settings & settings )
{
2019-07-15 18:24:27 +02:00
mSettings = & settings ;
2017-08-21 12:52:15 +02:00
}
2014-06-29 18:57:48 +02:00
/**
* Simple helper function :
* \ return size of array
* */
template < typename T , int size >
2015-11-15 10:45:01 +01:00
std : : size_t GetArrayLength ( const T ( & ) [ size ] )
2014-06-29 18:57:48 +02:00
{
return size ;
}
2014-03-16 12:04:13 +01:00
# if defined(USE_UNIX_SIGNAL_HANDLING)
2016-05-20 21:32:59 +02:00
/*
* Try to print the callstack .
2017-06-06 20:56:59 +02:00
* That is very sensitive to the operating system , hardware , compiler and runtime .
* The code is not meant for production environment !
* One reason is named first : it ' s using functions not whitelisted for usage in a signal handler function .
2016-05-20 21:32:59 +02:00
*/
static void print_stacktrace ( FILE * output , bool demangling , int maxdepth , bool lowMem )
{
2014-06-28 14:05:18 +02:00
# if defined(USE_UNIX_BACKTRACE_SUPPORT)
2015-03-08 14:24:54 +01:00
// 32 vs. 64bit
# define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
2016-05-20 21:32:59 +02:00
const int fd = fileno ( output ) ;
2019-06-30 21:39:22 +02:00
void * callstackArray [ 32 ] = { nullptr } ; // the less resources the better...
2017-06-06 20:56:59 +02:00
const int currentdepth = backtrace ( callstackArray , ( int ) GetArrayLength ( callstackArray ) ) ;
2016-05-20 21:32:59 +02:00
const int offset = 2 ; // some entries on top are within our own exception handling code or libc
if ( maxdepth < 0 )
maxdepth = currentdepth - offset ;
else
maxdepth = std : : min ( maxdepth , currentdepth ) ;
if ( lowMem ) {
fputs ( " Callstack (symbols only): \n " , output ) ;
2017-06-06 20:56:59 +02:00
backtrace_symbols_fd ( callstackArray + offset , maxdepth , fd ) ;
2016-05-20 21:32:59 +02:00
} else {
2017-06-06 20:56:59 +02:00
char * * symbolStringList = backtrace_symbols ( callstackArray , currentdepth ) ;
if ( symbolStringList ) {
2016-05-20 21:32:59 +02:00
fputs ( " Callstack: \n " , output ) ;
for ( int i = offset ; i < maxdepth ; + + i ) {
2017-06-06 20:56:59 +02:00
const char * const symbolString = symbolStringList [ i ] ;
char * realnameString = nullptr ;
const char * const firstBracketName = strchr ( symbolString , ' ( ' ) ;
const char * const firstBracketAddress = strchr ( symbolString , ' [ ' ) ;
2016-05-20 21:32:59 +02:00
const char * const secondBracketAddress = strchr ( firstBracketAddress , ' ] ' ) ;
const char * const beginAddress = firstBracketAddress + 3 ;
const int addressLen = int ( secondBracketAddress - beginAddress ) ;
const int padLen = int ( ADDRESSDISPLAYLENGTH - addressLen ) ;
if ( demangling & & firstBracketName ) {
const char * const plus = strchr ( firstBracketName , ' + ' ) ;
if ( plus & & ( plus > ( firstBracketName + 1 ) ) ) {
2017-06-06 20:56:59 +02:00
char input_buffer [ 1024 ] = { 0 } ;
2016-05-20 21:32:59 +02:00
strncpy ( input_buffer , firstBracketName + 1 , plus - firstBracketName - 1 ) ;
2017-06-06 20:56:59 +02:00
char output_buffer [ 2048 ] = { 0 } ;
2016-05-20 21:32:59 +02:00
size_t length = GetArrayLength ( output_buffer ) ;
int status = 0 ;
2017-06-06 20:56:59 +02:00
// We're violating the specification - passing stack address instead of malloc'ed heap.
// Benefit is that no further heap is required, while there is sufficient stack...
realnameString = abi : : __cxa_demangle ( input_buffer , output_buffer , & length , & status ) ; // non-NULL on success
2015-11-14 19:59:22 +01:00
}
}
2016-05-20 21:32:59 +02:00
const int ordinal = i - offset ;
fprintf ( output , " #%-2d 0x " ,
ordinal ) ;
if ( padLen > 0 )
fprintf ( output , " %0*d " ,
padLen , 0 ) ;
2017-06-06 20:56:59 +02:00
if ( realnameString ) {
2016-05-20 21:32:59 +02:00
fprintf ( output , " %.*s in %s \n " ,
( int ) ( secondBracketAddress - firstBracketAddress - 3 ) , firstBracketAddress + 3 ,
2017-06-06 20:56:59 +02:00
realnameString ) ;
2016-05-20 21:32:59 +02:00
} else {
fprintf ( output , " %.*s in %.*s \n " ,
( int ) ( secondBracketAddress - firstBracketAddress - 3 ) , firstBracketAddress + 3 ,
2017-06-06 20:56:59 +02:00
( int ) ( firstBracketAddress - symbolString ) , symbolString ) ;
2016-05-20 21:32:59 +02:00
}
2014-03-16 18:37:28 +01:00
}
2017-06-06 20:56:59 +02:00
free ( symbolStringList ) ;
2016-05-20 21:32:59 +02:00
} else {
fputs ( " Callstack could not be obtained \n " , output ) ;
2014-03-16 18:37:28 +01:00
}
2016-05-20 21:32:59 +02:00
}
2015-03-08 14:24:54 +01:00
# undef ADDRESSDISPLAYLENGTH
2017-05-25 00:19:27 +02:00
# else
UNUSED ( output ) ;
UNUSED ( demangling ) ;
UNUSED ( maxdepth ) ;
UNUSED ( lowMem ) ;
2014-03-16 12:04:13 +01:00
# endif
2016-05-20 21:32:59 +02:00
}
2014-03-16 12:04:13 +01:00
2016-05-20 21:32:59 +02:00
static const size_t MYSTACKSIZE = 16 * 1024 + SIGSTKSZ ; // wild guess about a reasonable buffer
static char mytstack [ MYSTACKSIZE ] = { 0 } ; // alternative stack for signal handler
static bool bStackBelowHeap = false ; // lame attempt to locate heap vs. stack address space. See CppCheckExecutor::check_wrapper()
2015-03-07 20:47:27 +01:00
2018-12-21 21:23:03 +01:00
/**
2016-05-20 21:32:59 +02:00
* \ param [ in ] ptr address to be examined .
* \ return true if address is supposed to be on stack ( contrary to heap ) . If ptr is 0 false will be returned .
* If unknown better return false .
*/
static bool IsAddressOnStack ( const void * ptr )
{
if ( nullptr = = ptr )
return false ;
char a ;
if ( bStackBelowHeap )
return ptr < & a ;
else
return ptr > & a ;
}
2015-03-07 18:15:25 +01:00
2016-05-20 21:32:59 +02:00
/* (declare this list here, so it may be used in signal handlers in addition to main())
* A list of signals available in ISO C
* Check out http : //pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
* For now we only want to detect abnormal behaviour for a few selected signals :
*/
2015-11-14 19:59:22 +01:00
2018-04-08 22:54:10 +02:00
# define DECLARE_SIGNAL(x) std::make_pair(x, #x)
2016-05-20 21:32:59 +02:00
typedef std : : map < int , std : : string > Signalmap_t ;
2018-04-08 22:54:10 +02:00
static const Signalmap_t listofsignals = {
DECLARE_SIGNAL ( SIGABRT ) ,
DECLARE_SIGNAL ( SIGBUS ) ,
DECLARE_SIGNAL ( SIGFPE ) ,
DECLARE_SIGNAL ( SIGILL ) ,
DECLARE_SIGNAL ( SIGINT ) ,
DECLARE_SIGNAL ( SIGQUIT ) ,
DECLARE_SIGNAL ( SIGSEGV ) ,
DECLARE_SIGNAL ( SIGSYS ) ,
// don't care: SIGTERM
DECLARE_SIGNAL ( SIGUSR1 ) ,
//DECLARE_SIGNAL(SIGUSR2) no usage currently
} ;
2015-11-25 22:37:38 +01:00
# undef DECLARE_SIGNAL
2016-05-20 21:32:59 +02:00
/*
* Entry pointer for signal handlers
* It uses functions which are not safe to be called from a signal handler ,
* ( http : //pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04 has a whitelist)
* but when ending up here something went terribly wrong anyway .
* And all which is left is just printing some information and terminate .
*/
static void CppcheckSignalHandler ( int signo , siginfo_t * info , void * context )
{
int type = - 1 ;
2018-03-20 14:24:45 +01:00
pid_t killid ;
2014-12-31 01:44:50 +01:00
# if defined(__linux__) && defined(REG_ERR)
2016-05-20 21:32:59 +02:00
const ucontext_t * const uc = reinterpret_cast < const ucontext_t * > ( context ) ;
killid = ( pid_t ) syscall ( SYS_gettid ) ;
if ( uc ) {
type = ( int ) uc - > uc_mcontext . gregs [ REG_ERR ] & 2 ;
}
2017-05-25 00:19:27 +02:00
# else
UNUSED ( context ) ;
2018-03-20 14:24:45 +01:00
killid = getpid ( ) ;
2014-11-14 23:40:53 +01:00
# endif
2017-05-25 00:19:27 +02:00
2016-05-20 21:32:59 +02:00
const Signalmap_t : : const_iterator it = listofsignals . find ( signo ) ;
const char * const signame = ( it = = listofsignals . end ( ) ) ? " unknown " : it - > second . c_str ( ) ;
2017-06-06 20:56:59 +02:00
bool printCallstack = true ; // try to print a callstack?
2018-03-20 14:24:45 +01:00
bool lowMem = false ; // was low-memory condition detected? Be careful then! Avoid allocating much more memory then.
bool unexpectedSignal = true ; // unexpected indicates program failure
2017-06-06 20:56:59 +02:00
bool terminate = true ; // exit process/thread
const bool isAddressOnStack = IsAddressOnStack ( info - > si_addr ) ;
2016-05-20 21:32:59 +02:00
FILE * output = CppCheckExecutor : : getExceptionOutput ( ) ;
switch ( signo ) {
case SIGABRT :
fputs ( " Internal error: cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
2018-03-20 14:24:45 +01:00
fputs (
# ifdef NDEBUG
2018-03-22 07:14:01 +01:00
" - out of memory? \n " ,
2018-03-20 14:24:45 +01:00
# else
2018-03-22 07:14:01 +01:00
" - out of memory or assertion? \n " ,
2018-03-20 14:24:45 +01:00
# endif
2018-03-22 07:14:01 +01:00
output ) ;
2016-05-20 21:32:59 +02:00
lowMem = true ; // educated guess
break ;
case SIGBUS :
fputs ( " Internal error: cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
switch ( info - > si_code ) {
case BUS_ADRALN : // invalid address alignment
fputs ( " - BUS_ADRALN " , output ) ;
break ;
case BUS_ADRERR : // nonexistent physical address
fputs ( " - BUS_ADRERR " , output ) ;
break ;
case BUS_OBJERR : // object-specific hardware error
fputs ( " - BUS_OBJERR " , output ) ;
2015-11-21 16:50:57 +01:00
break ;
2014-05-25 15:53:26 +02:00
# ifdef BUS_MCEERR_AR
2016-05-20 21:32:59 +02:00
case BUS_MCEERR_AR : // Hardware memory error consumed on a machine check;
fputs ( " - BUS_MCEERR_AR " , output ) ;
break ;
2014-05-25 15:53:26 +02:00
# endif
# ifdef BUS_MCEERR_AO
2016-05-20 21:32:59 +02:00
case BUS_MCEERR_AO : // Hardware memory error detected in process but not consumed
fputs ( " - BUS_MCEERR_AO " , output ) ;
break ;
2014-05-25 15:53:26 +02:00
# endif
2016-05-20 21:32:59 +02:00
default :
2014-05-25 15:53:26 +02:00
break ;
2016-05-20 21:32:59 +02:00
}
fprintf ( output , " (at 0x%lx). \n " ,
( unsigned long ) info - > si_addr ) ;
break ;
case SIGFPE :
fputs ( " Internal error: cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
switch ( info - > si_code ) {
case FPE_INTDIV : // integer divide by zero
fputs ( " - FPE_INTDIV " , output ) ;
2014-05-25 15:53:26 +02:00
break ;
2016-05-20 21:32:59 +02:00
case FPE_INTOVF : // integer overflow
fputs ( " - FPE_INTOVF " , output ) ;
2014-05-25 15:53:26 +02:00
break ;
2016-05-20 21:32:59 +02:00
case FPE_FLTDIV : // floating-point divide by zero
fputs ( " - FPE_FLTDIV " , output ) ;
2014-05-25 15:53:26 +02:00
break ;
2016-05-20 21:32:59 +02:00
case FPE_FLTOVF : // floating-point overflow
fputs ( " - FPE_FLTOVF " , output ) ;
2014-05-25 15:53:26 +02:00
break ;
2016-05-20 21:32:59 +02:00
case FPE_FLTUND : // floating-point underflow
fputs ( " - FPE_FLTUND " , output ) ;
break ;
case FPE_FLTRES : // floating-point inexact result
fputs ( " - FPE_FLTRES " , output ) ;
break ;
case FPE_FLTINV : // floating-point invalid operation
fputs ( " - FPE_FLTINV " , output ) ;
break ;
case FPE_FLTSUB : // subscript out of range
fputs ( " - FPE_FLTSUB " , output ) ;
2014-05-25 15:53:26 +02:00
break ;
default :
break ;
}
2016-05-20 21:32:59 +02:00
fprintf ( output , " (at 0x%lx). \n " ,
( unsigned long ) info - > si_addr ) ;
break ;
case SIGILL :
fputs ( " Internal error: cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
switch ( info - > si_code ) {
case ILL_ILLOPC : // illegal opcode
fputs ( " - ILL_ILLOPC " , output ) ;
break ;
case ILL_ILLOPN : // illegal operand
fputs ( " - ILL_ILLOPN " , output ) ;
break ;
case ILL_ILLADR : // illegal addressing mode
fputs ( " - ILL_ILLADR " , output ) ;
break ;
case ILL_ILLTRP : // illegal trap
fputs ( " - ILL_ILLTRP " , output ) ;
break ;
case ILL_PRVOPC : // privileged opcode
fputs ( " - ILL_PRVOPC " , output ) ;
break ;
case ILL_PRVREG : // privileged register
fputs ( " - ILL_PRVREG " , output ) ;
break ;
case ILL_COPROC : // coprocessor error
fputs ( " - ILL_COPROC " , output ) ;
break ;
case ILL_BADSTK : // internal stack error
fputs ( " - ILL_BADSTK " , output ) ;
break ;
default :
break ;
2014-05-25 15:53:26 +02:00
}
2016-05-20 21:32:59 +02:00
fprintf ( output , " (at 0x%lx).%s \n " ,
( unsigned long ) info - > si_addr ,
2017-06-06 20:56:59 +02:00
( isAddressOnStack ) ? " Stackoverflow? " : " " ) ;
2016-05-20 21:32:59 +02:00
break ;
case SIGINT :
unexpectedSignal = false ; // legal usage: interrupt application via CTRL-C
fputs ( " cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
printCallstack = true ;
fputs ( " . \n " , output ) ;
break ;
case SIGSEGV :
fputs ( " Internal error: cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
switch ( info - > si_code ) {
case SEGV_MAPERR : // address not mapped to object
fputs ( " - SEGV_MAPERR " , output ) ;
break ;
case SEGV_ACCERR : // invalid permissions for mapped object
fputs ( " - SEGV_ACCERR " , output ) ;
break ;
default :
break ;
2014-05-25 15:53:26 +02:00
}
2016-05-20 21:32:59 +02:00
fprintf ( output , " (%sat 0x%lx).%s \n " ,
2019-01-13 13:18:35 +01:00
// cppcheck-suppress knownConditionTrueFalse ; FP
2016-05-20 21:32:59 +02:00
( type = = - 1 ) ? " " :
( type = = 0 ) ? " reading " : " writing " ,
( unsigned long ) info - > si_addr ,
2017-06-06 20:56:59 +02:00
( isAddressOnStack ) ? " Stackoverflow? " : " "
2016-05-20 21:32:59 +02:00
) ;
break ;
case SIGUSR1 :
fputs ( " cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
fputs ( " . \n " , output ) ;
2017-06-06 20:56:59 +02:00
terminate = false ;
2016-05-20 21:32:59 +02:00
break ;
default :
fputs ( " Internal error: cppcheck received signal " , output ) ;
fputs ( signame , output ) ;
fputs ( " . \n " , output ) ;
break ;
2015-11-14 19:59:22 +01:00
}
2016-05-20 21:32:59 +02:00
if ( printCallstack ) {
print_stacktrace ( output , true , - 1 , lowMem ) ;
}
if ( unexpectedSignal ) {
fputs ( " \n Please report this to the cppcheck developers! \n " , output ) ;
}
fflush ( output ) ;
2017-06-06 20:56:59 +02:00
if ( terminate ) {
// now let things proceed, shutdown and hopefully dump core for post-mortem analysis
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
act . sa_handler = SIG_DFL ;
sigaction ( signo , & act , nullptr ) ;
kill ( killid , signo ) ;
}
2014-03-16 12:04:13 +01:00
}
# endif
2014-03-17 19:11:00 +01:00
# ifdef USE_WINDOWS_SEH
2015-11-14 19:59:22 +01:00
namespace {
const ULONG maxnamelength = 512 ;
struct IMAGEHLP_SYMBOL64_EXT : public IMAGEHLP_SYMBOL64 {
TCHAR NameExt [ maxnamelength ] ; // actually no need to worry about character encoding here
} ;
typedef BOOL ( WINAPI * fpStackWalk64 ) ( DWORD , HANDLE , HANDLE , LPSTACKFRAME64 , PVOID , PREAD_PROCESS_MEMORY_ROUTINE64 , PFUNCTION_TABLE_ACCESS_ROUTINE64 , PGET_MODULE_BASE_ROUTINE64 , PTRANSLATE_ADDRESS_ROUTINE64 ) ;
fpStackWalk64 pStackWalk64 ;
typedef DWORD64 ( WINAPI * fpSymGetModuleBase64 ) ( HANDLE , DWORD64 ) ;
fpSymGetModuleBase64 pSymGetModuleBase64 ;
typedef BOOL ( WINAPI * fpSymGetSymFromAddr64 ) ( HANDLE , DWORD64 , PDWORD64 , PIMAGEHLP_SYMBOL64 ) ;
fpSymGetSymFromAddr64 pSymGetSymFromAddr64 ;
typedef BOOL ( WINAPI * fpSymGetLineFromAddr64 ) ( HANDLE , DWORD64 , PDWORD , PIMAGEHLP_LINE64 ) ;
fpSymGetLineFromAddr64 pSymGetLineFromAddr64 ;
typedef DWORD ( WINAPI * fpUnDecorateSymbolName ) ( const TCHAR * , PTSTR , DWORD , DWORD ) ;
fpUnDecorateSymbolName pUnDecorateSymbolName ;
typedef PVOID ( WINAPI * fpSymFunctionTableAccess64 ) ( HANDLE , DWORD64 ) ;
fpSymFunctionTableAccess64 pSymFunctionTableAccess64 ;
typedef BOOL ( WINAPI * fpSymInitialize ) ( HANDLE , PCSTR , BOOL ) ;
fpSymInitialize pSymInitialize ;
HMODULE hLibDbgHelp ;
2014-06-29 18:57:48 +02:00
// avoid explicit dependency on Dbghelp.dll
2015-11-14 19:59:22 +01:00
bool loadDbgHelp ( )
{
hLibDbgHelp = : : LoadLibraryW ( L " Dbghelp.dll " ) ;
if ( ! hLibDbgHelp )
return false ;
pStackWalk64 = ( fpStackWalk64 ) : : GetProcAddress ( hLibDbgHelp , " StackWalk64 " ) ;
pSymGetModuleBase64 = ( fpSymGetModuleBase64 ) : : GetProcAddress ( hLibDbgHelp , " SymGetModuleBase64 " ) ;
pSymGetSymFromAddr64 = ( fpSymGetSymFromAddr64 ) : : GetProcAddress ( hLibDbgHelp , " SymGetSymFromAddr64 " ) ;
pSymGetLineFromAddr64 = ( fpSymGetLineFromAddr64 ) : : GetProcAddress ( hLibDbgHelp , " SymGetLineFromAddr64 " ) ;
pSymFunctionTableAccess64 = ( fpSymFunctionTableAccess64 ) : : GetProcAddress ( hLibDbgHelp , " SymFunctionTableAccess64 " ) ;
pSymInitialize = ( fpSymInitialize ) : : GetProcAddress ( hLibDbgHelp , " SymInitialize " ) ;
pUnDecorateSymbolName = ( fpUnDecorateSymbolName ) : : GetProcAddress ( hLibDbgHelp , " UnDecorateSymbolName " ) ;
return true ;
}
2014-06-29 18:57:48 +02:00
2015-11-28 10:49:08 +01:00
void PrintCallstack ( FILE * outputFile , PEXCEPTION_POINTERS ex )
2015-11-14 19:59:22 +01:00
{
if ( ! loadDbgHelp ( ) )
return ;
const HANDLE hProcess = GetCurrentProcess ( ) ;
const HANDLE hThread = GetCurrentThread ( ) ;
2019-01-13 13:06:44 +01:00
pSymInitialize (
hProcess ,
nullptr ,
TRUE
) ;
2015-11-14 19:59:22 +01:00
CONTEXT context = * ( ex - > ContextRecord ) ;
STACKFRAME64 stack = { 0 } ;
2014-06-29 18:57:48 +02:00
# ifdef _M_IX86
2015-11-14 19:59:22 +01:00
stack . AddrPC . Offset = context . Eip ;
stack . AddrPC . Mode = AddrModeFlat ;
stack . AddrStack . Offset = context . Esp ;
stack . AddrStack . Mode = AddrModeFlat ;
stack . AddrFrame . Offset = context . Ebp ;
stack . AddrFrame . Mode = AddrModeFlat ;
2014-06-29 18:57:48 +02:00
# else
2015-11-14 19:59:22 +01:00
stack . AddrPC . Offset = context . Rip ;
stack . AddrPC . Mode = AddrModeFlat ;
stack . AddrStack . Offset = context . Rsp ;
stack . AddrStack . Mode = AddrModeFlat ;
stack . AddrFrame . Offset = context . Rsp ;
stack . AddrFrame . Mode = AddrModeFlat ;
2014-06-29 18:57:48 +02:00
# endif
2015-11-14 19:59:22 +01:00
IMAGEHLP_SYMBOL64_EXT symbol ;
symbol . SizeOfStruct = sizeof ( IMAGEHLP_SYMBOL64 ) ;
symbol . MaxNameLength = maxnamelength ;
DWORD64 displacement = 0 ;
int beyond_main = - 1 ; // emergency exit, see below
for ( ULONG frame = 0 ; ; frame + + ) {
2019-01-13 13:06:44 +01:00
BOOL result = pStackWalk64
(
2014-06-29 18:57:48 +02:00
# ifdef _M_IX86
2019-01-13 13:06:44 +01:00
IMAGE_FILE_MACHINE_I386 ,
2014-06-29 18:57:48 +02:00
# else
2019-01-13 13:06:44 +01:00
IMAGE_FILE_MACHINE_AMD64 ,
2014-06-29 18:57:48 +02:00
# endif
2019-01-13 13:06:44 +01:00
hProcess ,
hThread ,
& stack ,
& context ,
nullptr ,
pSymFunctionTableAccess64 ,
pSymGetModuleBase64 ,
nullptr
) ;
2015-11-14 19:59:22 +01:00
if ( ! result ) // official end...
break ;
pSymGetSymFromAddr64 ( hProcess , ( ULONG64 ) stack . AddrPC . Offset , & displacement , & symbol ) ;
TCHAR undname [ maxnamelength ] = { 0 } ;
pUnDecorateSymbolName ( ( const TCHAR * ) symbol . Name , ( PTSTR ) undname , ( DWORD ) GetArrayLength ( undname ) , UNDNAME_COMPLETE ) ;
if ( beyond_main > = 0 )
+ + beyond_main ;
if ( _tcscmp ( undname , _T ( " main " ) ) = = 0 )
beyond_main = 0 ;
2015-11-28 10:49:08 +01:00
fprintf ( outputFile ,
2015-11-14 19:59:22 +01:00
" %lu. 0x%08I64X in " ,
frame , ( ULONG64 ) stack . AddrPC . Offset ) ;
2015-11-28 10:49:08 +01:00
fputs ( ( const char * ) undname , outputFile ) ;
fputc ( ' \n ' , outputFile ) ;
2015-11-14 19:59:22 +01:00
if ( 0 = = stack . AddrReturn . Offset | | beyond_main > 2 ) // StackWalk64() sometimes doesn't reach any end...
break ;
}
2014-07-07 21:25:30 +02:00
2015-11-14 19:59:22 +01:00
FreeLibrary ( hLibDbgHelp ) ;
2018-04-05 08:12:15 +02:00
hLibDbgHelp = nullptr ;
2015-11-14 19:59:22 +01:00
}
2014-06-29 18:57:48 +02:00
2015-11-28 10:49:08 +01:00
void writeMemoryErrorDetails ( FILE * outputFile , PEXCEPTION_POINTERS ex , const char * description )
2015-11-14 19:59:22 +01:00
{
2015-11-28 10:49:08 +01:00
fputs ( description , outputFile ) ;
fprintf ( outputFile , " (instruction: 0x%p) " , ex - > ExceptionRecord - > ExceptionAddress ) ;
2015-11-14 19:59:22 +01:00
// Using %p for ULONG_PTR later on, so it must have size identical to size of pointer
// This is not the universally portable solution but good enough for Win32/64
C_ASSERT ( sizeof ( void * ) = = sizeof ( ex - > ExceptionRecord - > ExceptionInformation [ 1 ] ) ) ;
switch ( ex - > ExceptionRecord - > ExceptionInformation [ 0 ] ) {
case 0 :
2015-11-28 10:49:08 +01:00
fprintf ( outputFile , " reading from 0x%p " ,
2015-11-14 19:59:22 +01:00
reinterpret_cast < void * > ( ex - > ExceptionRecord - > ExceptionInformation [ 1 ] ) ) ;
break ;
case 1 :
2015-11-28 10:49:08 +01:00
fprintf ( outputFile , " writing to 0x%p " ,
2015-11-14 19:59:22 +01:00
reinterpret_cast < void * > ( ex - > ExceptionRecord - > ExceptionInformation [ 1 ] ) ) ;
break ;
case 8 :
2015-11-28 10:49:08 +01:00
fprintf ( outputFile , " data execution prevention at 0x%p " ,
2015-11-14 19:59:22 +01:00
reinterpret_cast < void * > ( ex - > ExceptionRecord - > ExceptionInformation [ 1 ] ) ) ;
break ;
default :
break ;
}
2015-02-20 08:26:02 +01:00
}
2015-11-14 19:59:22 +01:00
/*
* Any evaluation of the exception needs to be done here !
*/
int filterException ( int code , PEXCEPTION_POINTERS ex )
{
2015-11-28 10:49:08 +01:00
FILE * outputFile = stdout ;
fputs ( " Internal error: " , outputFile ) ;
2015-11-14 19:59:22 +01:00
switch ( ex - > ExceptionRecord - > ExceptionCode ) {
case EXCEPTION_ACCESS_VIOLATION :
2015-11-28 10:49:08 +01:00
writeMemoryErrorDetails ( outputFile , ex , " Access violation " ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
2015-11-28 10:49:08 +01:00
fputs ( " Out of array bounds " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_BREAKPOINT :
2015-11-28 10:49:08 +01:00
fputs ( " Breakpoint " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_DATATYPE_MISALIGNMENT :
2015-11-28 10:49:08 +01:00
fputs ( " Misaligned data " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_FLT_DENORMAL_OPERAND :
2015-11-28 10:49:08 +01:00
fputs ( " Denormalized floating-point value " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_FLT_DIVIDE_BY_ZERO :
2015-11-28 10:49:08 +01:00
fputs ( " Floating-point divide-by-zero " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_FLT_INEXACT_RESULT :
2015-11-28 10:49:08 +01:00
fputs ( " Inexact floating-point value " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_FLT_INVALID_OPERATION :
2015-11-28 10:49:08 +01:00
fputs ( " Invalid floating-point operation " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_FLT_OVERFLOW :
2015-11-28 10:49:08 +01:00
fputs ( " Floating-point overflow " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_FLT_STACK_CHECK :
2015-11-28 10:49:08 +01:00
fputs ( " Floating-point stack overflow " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_FLT_UNDERFLOW :
2015-11-28 10:49:08 +01:00
fputs ( " Floating-point underflow " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_GUARD_PAGE :
2015-11-28 10:49:08 +01:00
fputs ( " Page-guard access " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_ILLEGAL_INSTRUCTION :
2015-11-28 10:49:08 +01:00
fputs ( " Illegal instruction " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_IN_PAGE_ERROR :
2015-11-28 10:49:08 +01:00
writeMemoryErrorDetails ( outputFile , ex , " Invalid page access " ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_INT_DIVIDE_BY_ZERO :
2015-11-28 10:49:08 +01:00
fputs ( " Integer divide-by-zero " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_INT_OVERFLOW :
2015-11-28 10:49:08 +01:00
fputs ( " Integer overflow " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_INVALID_DISPOSITION :
2015-11-28 10:49:08 +01:00
fputs ( " Invalid exception dispatcher " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_INVALID_HANDLE :
2015-11-28 10:49:08 +01:00
fputs ( " Invalid handle " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_NONCONTINUABLE_EXCEPTION :
2015-11-28 10:49:08 +01:00
fputs ( " Non-continuable exception " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_PRIV_INSTRUCTION :
2015-11-28 10:49:08 +01:00
fputs ( " Invalid instruction " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_SINGLE_STEP :
2015-11-28 10:49:08 +01:00
fputs ( " Single instruction step " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
case EXCEPTION_STACK_OVERFLOW :
2015-11-28 10:49:08 +01:00
fputs ( " Stack overflow " , outputFile ) ;
2015-11-14 19:59:22 +01:00
break ;
default :
2015-11-28 10:49:08 +01:00
fprintf ( outputFile , " Unknown exception (%d) \n " ,
2015-11-14 19:59:22 +01:00
code ) ;
break ;
}
2015-11-28 10:49:08 +01:00
fputc ( ' \n ' , outputFile ) ;
PrintCallstack ( outputFile , ex ) ;
fflush ( outputFile ) ;
2015-11-14 19:59:22 +01:00
return EXCEPTION_EXECUTE_HANDLER ;
2014-03-17 19:11:00 +01:00
}
2014-03-16 18:37:28 +01:00
}
# endif
/**
* Signal / SEH handling
2014-03-18 21:14:09 +01:00
* Has to be clean for using with SEH on windows , i . e . no construction of C + + object instances is allowed !
2014-03-16 18:37:28 +01:00
* TODO Check for multi - threading issues !
*
*/
2014-04-07 20:39:19 +02:00
int CppCheckExecutor : : check_wrapper ( CppCheck & cppcheck , int argc , const char * const argv [ ] )
2014-03-16 12:04:13 +01:00
{
2014-03-17 19:11:00 +01:00
# ifdef USE_WINDOWS_SEH
2015-11-28 10:49:08 +01:00
FILE * outputFile = stdout ;
2014-03-17 19:11:00 +01:00
__try {
2014-04-07 20:39:19 +02:00
return check_internal ( cppcheck , argc , argv ) ;
2014-03-17 19:11:00 +01:00
} __except ( filterException ( GetExceptionCode ( ) , GetExceptionInformation ( ) ) ) {
2015-03-08 14:24:54 +01:00
// reporting to stdout may not be helpful within a GUI application...
2015-11-28 10:49:08 +01:00
fputs ( " Please report this to the cppcheck developers! \n " , outputFile ) ;
2014-03-16 18:37:28 +01:00
return - 1 ;
}
2014-06-28 14:05:18 +02:00
# elif defined(USE_UNIX_SIGNAL_HANDLING)
2015-03-07 20:47:27 +01:00
// determine stack vs. heap
char stackVariable ;
char * heapVariable = ( char * ) malloc ( 1 ) ;
bStackBelowHeap = & stackVariable < heapVariable ;
free ( heapVariable ) ;
// set up alternative stack for signal handler
2015-03-07 18:15:25 +01:00
stack_t segv_stack ;
segv_stack . ss_sp = mytstack ;
segv_stack . ss_flags = 0 ;
segv_stack . ss_size = MYSTACKSIZE ;
2015-11-30 22:13:49 +01:00
sigaltstack ( & segv_stack , nullptr ) ;
2015-03-07 18:15:25 +01:00
2015-03-07 20:47:27 +01:00
// install signal handler
2014-03-16 18:37:28 +01:00
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
2015-03-07 18:15:25 +01:00
act . sa_flags = SA_SIGINFO | SA_ONSTACK ;
2014-03-16 18:37:28 +01:00
act . sa_sigaction = CppcheckSignalHandler ;
2015-11-14 19:59:22 +01:00
for ( std : : map < int , std : : string > : : const_iterator sig = listofsignals . begin ( ) ; sig ! = listofsignals . end ( ) ; + + sig ) {
2015-11-30 22:13:49 +01:00
sigaction ( sig - > first , & act , nullptr ) ;
2014-03-16 12:04:13 +01:00
}
2014-04-07 20:39:19 +02:00
return check_internal ( cppcheck , argc , argv ) ;
2014-03-16 12:04:13 +01:00
# else
2014-04-07 20:39:19 +02:00
return check_internal ( cppcheck , argc , argv ) ;
2014-03-16 12:04:13 +01:00
# endif
}
2014-03-18 21:14:09 +01:00
/*
* That is a method which gets called from check_wrapper
* */
2014-04-07 20:39:19 +02:00
int CppCheckExecutor : : check_internal ( CppCheck & cppcheck , int /*argc*/ , const char * const argv [ ] )
2014-03-16 12:04:13 +01:00
{
2014-04-07 20:39:19 +02:00
Settings & settings = cppcheck . settings ( ) ;
2019-07-15 18:24:27 +02:00
mSettings = & settings ;
2018-02-18 14:28:48 +01:00
const bool std = tryLoadLibrary ( settings . library , argv [ 0 ] , " std.cfg " ) ;
2019-03-15 06:59:37 +01:00
for ( const std : : string & lib : settings . libraries ) {
if ( ! tryLoadLibrary ( settings . library , argv [ 0 ] , lib . c_str ( ) ) ) {
const std : : string msg ( " Failed to load the library " + lib ) ;
const std : : list < ErrorLogger : : ErrorMessage : : FileLocation > callstack ;
ErrorLogger : : ErrorMessage errmsg ( callstack , emptyString , Severity : : information , msg , " failedToLoadCfg " , false ) ;
reportErr ( errmsg ) ;
return EXIT_FAILURE ;
}
}
2013-12-26 11:15:28 +01:00
bool posix = true ;
2019-04-12 06:47:28 +02:00
if ( settings . posix ( ) )
2015-01-10 22:18:57 +01:00
posix = tryLoadLibrary ( settings . library , argv [ 0 ] , " posix.cfg " ) ;
2014-10-19 07:34:40 +02:00
bool windows = true ;
if ( settings . isWindowsPlatform ( ) )
2015-01-10 22:18:57 +01:00
windows = tryLoadLibrary ( settings . library , argv [ 0 ] , " windows.cfg " ) ;
2013-12-26 11:15:28 +01:00
2014-10-19 07:34:40 +02:00
if ( ! std | | ! posix | | ! windows ) {
2013-12-26 11:15:28 +01:00
const std : : list < ErrorLogger : : ErrorMessage : : FileLocation > callstack ;
2014-10-19 07:34:40 +02:00
const std : : string msg ( " Failed to load " + std : : string ( ! std ? " std.cfg " : ! posix ? " posix.cfg " : " windows.cfg " ) + " . Your Cppcheck installation is broken, please re-install. " ) ;
2014-01-03 21:59:50 +01:00
# ifdef CFGDIR
const std : : string details ( " The Cppcheck binary was compiled with CFGDIR set to \" " +
std : : string ( CFGDIR ) + " \" and will therefore search for "
" std.cfg in that path. " ) ;
# else
const std : : string cfgfolder ( Path : : fromNativeSeparators ( Path : : getPathFromFilename ( argv [ 0 ] ) ) + " cfg " ) ;
const std : : string details ( " The Cppcheck binary was compiled without CFGDIR set. Either the "
" std.cfg should be available in " + cfgfolder + " or the CFGDIR "
" should be configured. " ) ;
# endif
2016-07-26 16:27:55 +02:00
ErrorLogger : : ErrorMessage errmsg ( callstack , emptyString , Severity : : information , msg + " " + details , " failedToLoadCfg " , false ) ;
2013-12-26 11:15:28 +01:00
reportErr ( errmsg ) ;
return EXIT_FAILURE ;
}
2013-12-23 10:06:45 +01:00
2012-04-06 14:19:26 +02:00
if ( settings . reportProgress )
2019-07-15 20:58:07 +02:00
mLatestProgressOutputTime = std : : time ( nullptr ) ;
2010-08-12 21:03:33 +02:00
2017-05-30 15:04:28 +02:00
if ( ! settings . outputFile . empty ( ) ) {
2019-07-15 18:16:07 +02:00
mErrorOutput = new std : : ofstream ( settings . outputFile ) ;
2017-05-30 15:04:28 +02:00
}
2016-01-03 16:18:17 +01:00
if ( settings . xml ) {
2017-07-29 18:56:22 +02:00
reportErr ( ErrorLogger : : ErrorMessage : : getXMLHeader ( ) ) ;
2009-10-17 08:19:37 +02:00
}
2009-02-09 21:51:04 +01:00
2016-11-14 20:50:08 +01:00
if ( ! settings . buildDir . empty ( ) ) {
2016-12-08 22:46:44 +01:00
std : : list < std : : string > fileNames ;
2019-07-15 18:21:52 +02:00
for ( std : : map < std : : string , std : : size_t > : : const_iterator i = mFiles . begin ( ) ; i ! = mFiles . end ( ) ; + + i )
2016-12-08 22:46:44 +01:00
fileNames . push_back ( i - > first ) ;
AnalyzerInformation : : writeFilesTxt ( settings . buildDir , fileNames , settings . project . fileSettings ) ;
2016-11-14 20:50:08 +01:00
}
2009-10-17 08:19:37 +02:00
unsigned int returnValue = 0 ;
2016-01-03 16:18:17 +01:00
if ( settings . jobs = = 1 ) {
2009-10-17 08:19:37 +02:00
// Single process
2015-01-07 19:26:16 +01:00
settings . jointSuppressionReport = true ;
2011-04-19 13:52:32 +02:00
2012-07-08 23:39:46 +02:00
std : : size_t totalfilesize = 0 ;
2019-07-15 18:21:52 +02:00
for ( std : : map < std : : string , std : : size_t > : : const_iterator i = mFiles . begin ( ) ; i ! = mFiles . end ( ) ; + + i ) {
2011-04-19 13:52:32 +02:00
totalfilesize + = i - > second ;
}
2012-07-08 23:39:46 +02:00
std : : size_t processedsize = 0 ;
2012-02-19 17:22:59 +01:00
unsigned int c = 0 ;
2019-04-13 20:01:40 +02:00
if ( settings . project . fileSettings . empty ( ) ) {
2019-07-15 18:21:52 +02:00
for ( std : : map < std : : string , std : : size_t > : : const_iterator i = mFiles . begin ( ) ; i ! = mFiles . end ( ) ; + + i ) {
2019-07-15 18:24:27 +02:00
if ( ! mSettings - > library . markupFile ( i - > first )
| | ! mSettings - > library . processMarkupAfterCode ( i - > first ) ) {
2019-04-13 20:01:40 +02:00
returnValue + = cppcheck . check ( i - > first ) ;
processedsize + = i - > second ;
if ( ! settings . quiet )
2019-07-15 18:21:52 +02:00
reportStatus ( c + 1 , mFiles . size ( ) , processedsize , totalfilesize ) ;
2019-04-13 20:01:40 +02:00
c + + ;
}
2013-10-20 14:09:10 +02:00
}
2019-04-13 20:01:40 +02:00
} else {
2013-10-20 14:09:10 +02:00
2019-04-13 20:01:40 +02:00
// filesettings
c = 0 ;
for ( const ImportProject : : FileSettings & fs : settings . project . fileSettings ) {
returnValue + = cppcheck . check ( fs ) ;
+ + c ;
if ( ! settings . quiet )
reportStatus ( c , settings . project . fileSettings . size ( ) , c , settings . project . fileSettings . size ( ) ) ;
}
2016-08-13 10:50:03 +02:00
}
2013-10-31 19:09:01 +01:00
// second loop to parse all markup files which may not work until all
2013-10-20 14:09:10 +02:00
// c/cpp files have been parsed and checked
2019-07-15 18:21:52 +02:00
for ( std : : map < std : : string , std : : size_t > : : const_iterator i = mFiles . begin ( ) ; i ! = mFiles . end ( ) ; + + i ) {
2019-07-15 18:24:27 +02:00
if ( mSettings - > library . markupFile ( i - > first ) & & mSettings - > library . processMarkupAfterCode ( i - > first ) ) {
2014-04-07 20:39:19 +02:00
returnValue + = cppcheck . check ( i - > first ) ;
2013-10-20 14:09:10 +02:00
processedsize + = i - > second ;
2015-07-25 17:39:44 +02:00
if ( ! settings . quiet )
2019-07-15 18:21:52 +02:00
reportStatus ( c + 1 , mFiles . size ( ) , processedsize , totalfilesize ) ;
2013-10-20 14:09:10 +02:00
c + + ;
}
2011-04-23 14:20:55 +02:00
}
2018-01-12 08:24:01 +01:00
if ( cppcheck . analyseWholeProgram ( ) )
returnValue + + ;
2011-10-13 20:53:06 +02:00
} else if ( ! ThreadExecutor : : isEnabled ( ) ) {
2009-10-17 08:19:37 +02:00
std : : cout < < " No thread support yet implemented for this platform. " < < std : : endl ;
2011-10-13 20:53:06 +02:00
} else {
2009-10-17 08:19:37 +02:00
// Multiple processes
2019-07-15 18:21:52 +02:00
ThreadExecutor executor ( mFiles , settings , * this ) ;
2009-10-17 08:19:37 +02:00
returnValue = executor . check ( ) ;
2009-01-08 22:30:25 +01:00
}
2009-10-17 08:19:37 +02:00
2019-07-15 18:24:27 +02:00
cppcheck . analyseWholeProgram ( mSettings - > buildDir , mFiles ) ;
2016-11-05 21:26:56 +01:00
2017-04-11 11:49:09 +02:00
if ( settings . isEnabled ( Settings : : INFORMATION ) | | settings . checkConfiguration ) {
2016-10-28 12:10:19 +02:00
const bool enableUnusedFunctionCheck = cppcheck . isUnusedFunctionCheckEnabled ( ) ;
2015-01-07 19:26:16 +01:00
2019-01-22 19:40:39 +01:00
if ( settings . jointSuppressionReport ) {
2019-07-15 18:21:52 +02:00
for ( std : : map < std : : string , std : : size_t > : : const_iterator i = mFiles . begin ( ) ; i ! = mFiles . end ( ) ; + + i ) {
2019-01-21 20:33:22 +01:00
const bool err = reportUnmatchedSuppressions ( settings . nomsg . getUnmatchedLocalSuppressions ( i - > first , enableUnusedFunctionCheck ) ) ;
if ( err & & returnValue = = 0 )
2019-01-19 21:42:01 +01:00
returnValue = settings . exitCode ;
2015-01-07 19:26:16 +01:00
}
}
2019-01-21 20:33:22 +01:00
const bool err = reportUnmatchedSuppressions ( settings . nomsg . getUnmatchedGlobalSuppressions ( enableUnusedFunctionCheck ) ) ;
if ( err & & returnValue = = 0 )
returnValue = settings . exitCode ;
2015-01-07 19:26:16 +01:00
}
2011-05-02 14:58:16 +02:00
2013-05-31 15:20:58 +02:00
if ( ! settings . checkConfiguration ) {
2014-04-07 20:39:19 +02:00
cppcheck . tooManyConfigsError ( " " , 0U ) ;
2012-12-26 18:35:49 +01:00
2017-04-11 11:49:09 +02:00
if ( settings . isEnabled ( Settings : : MISSING_INCLUDE ) & & ( Preprocessor : : missingIncludeFlag | | Preprocessor : : missingSystemIncludeFlag ) ) {
2011-05-02 14:58:16 +02:00
const std : : list < ErrorLogger : : ErrorMessage : : FileLocation > callStack ;
ErrorLogger : : ErrorMessage msg ( callStack ,
2016-07-26 16:27:55 +02:00
emptyString ,
2011-05-02 14:58:16 +02:00
Severity : : information ,
2011-05-04 18:52:03 +02:00
" Cppcheck cannot find all the include files (use --check-config for details) \n "
2011-11-05 17:56:40 +01:00
" Cppcheck cannot find all the include files. Cppcheck can check the code without the "
2011-05-02 14:58:16 +02:00
" include files found. But the results will probably be more accurate if all the include "
" files are found. Please check your project's include directories and add all of them "
" as include directories for Cppcheck. To see what files Cppcheck cannot find use "
2011-05-04 18:52:03 +02:00
" --check-config. " ,
2014-05-03 19:31:15 +02:00
Preprocessor : : missingIncludeFlag ? " missingInclude " : " missingIncludeSystem " ,
2011-05-02 14:58:16 +02:00
false ) ;
2012-06-18 23:15:48 +02:00
reportInfo ( msg ) ;
2011-05-02 14:58:16 +02:00
}
}
2011-02-16 02:12:15 +01:00
2016-01-03 16:18:17 +01:00
if ( settings . xml ) {
2017-07-29 18:56:22 +02:00
reportErr ( ErrorLogger : : ErrorMessage : : getXMLFooter ( ) ) ;
2009-10-17 08:19:37 +02:00
}
2019-07-15 18:24:27 +02:00
mSettings = nullptr ;
2010-04-02 07:30:58 +02:00
if ( returnValue )
2016-01-03 16:18:17 +01:00
return settings . exitCode ;
2018-04-04 21:11:23 +02:00
return 0 ;
2008-12-18 22:28:57 +01:00
}
2017-08-21 12:52:15 +02:00
# ifdef _WIN32
// fix trac ticket #439 'Cppcheck reports wrong filename for filenames containing 8-bit ASCII'
2017-10-03 18:24:18 +02:00
static inline std : : string ansiToOEM ( const std : : string & msg , bool doConvert )
2017-08-21 12:52:15 +02:00
{
if ( doConvert ) {
2017-08-22 13:15:11 +02:00
const unsigned msglength = msg . length ( ) ;
2017-08-21 12:52:15 +02:00
// convert ANSI strings to OEM strings in two steps
2017-08-22 13:15:11 +02:00
std : : vector < WCHAR > wcContainer ( msglength ) ;
std : : string result ( msglength , ' \0 ' ) ;
2017-08-21 12:52:15 +02:00
// ansi code page characters to wide characters
2017-08-22 13:15:11 +02:00
MultiByteToWideChar ( CP_ACP , 0 , msg . data ( ) , msglength , wcContainer . data ( ) , msglength ) ;
2017-08-21 12:52:15 +02:00
// wide characters to oem codepage characters
2018-04-05 08:12:15 +02:00
WideCharToMultiByte ( CP_OEMCP , 0 , wcContainer . data ( ) , msglength , const_cast < char * > ( result . data ( ) ) , msglength , nullptr , nullptr ) ;
2017-08-21 12:52:15 +02:00
2017-08-22 13:15:11 +02:00
return result ; // hope for return value optimization
2017-08-21 12:52:15 +02:00
}
return msg ;
}
# else
// no performance regression on non-windows systems
2017-08-29 20:23:45 +02:00
# define ansiToOEM(msg, doConvert) (msg)
2017-08-21 12:52:15 +02:00
# endif
2009-01-05 16:49:57 +01:00
void CppCheckExecutor : : reportErr ( const std : : string & errmsg )
2008-12-18 22:28:57 +01:00
{
2011-10-09 20:03:38 +02:00
// Alert only about unique errors
2019-07-15 18:29:09 +02:00
if ( mShownErrors . find ( errmsg ) ! = mShownErrors . end ( ) )
2011-10-09 20:03:38 +02:00
return ;
2019-07-15 18:29:09 +02:00
mShownErrors . insert ( errmsg ) ;
2019-07-15 18:16:07 +02:00
if ( mErrorOutput )
* mErrorOutput < < errmsg < < std : : endl ;
2017-08-30 17:42:04 +02:00
else {
2019-07-15 18:24:27 +02:00
std : : cerr < < ansiToOEM ( errmsg , ( mSettings = = nullptr ) ? true : ! mSettings - > xml ) < < std : : endl ;
2017-08-29 16:51:56 +02:00
}
2008-12-18 22:28:57 +01:00
}
2009-01-05 16:49:57 +01:00
void CppCheckExecutor : : reportOut ( const std : : string & outmsg )
2008-12-18 22:28:57 +01:00
{
2017-08-21 12:52:15 +02:00
std : : cout < < ansiToOEM ( outmsg , true ) < < std : : endl ;
2008-12-18 22:28:57 +01:00
}
2009-02-01 19:00:47 +01:00
2012-07-08 23:39:46 +02:00
void CppCheckExecutor : : reportProgress ( const std : : string & filename , const char stage [ ] , const std : : size_t value )
2010-08-08 08:45:37 +02:00
{
( void ) filename ;
2019-07-15 20:58:07 +02:00
if ( ! mLatestProgressOutputTime )
2010-08-12 21:03:33 +02:00
return ;
2010-08-08 08:45:37 +02:00
// Report progress messages every 10 seconds
2017-10-14 22:05:58 +02:00
const std : : time_t currentTime = std : : time ( nullptr ) ;
2019-07-15 20:58:07 +02:00
if ( currentTime > = ( mLatestProgressOutputTime + 10 ) ) {
mLatestProgressOutputTime = currentTime ;
2010-08-08 08:45:37 +02:00
// format a progress message
std : : ostringstream ostr ;
ostr < < " progress: "
< < stage
2012-07-06 13:17:08 +02:00
< < ' ' < < value < < ' % ' ;
2010-08-08 08:45:37 +02:00
// Report progress message
reportOut ( ostr . str ( ) ) ;
}
}
2012-06-18 23:15:48 +02:00
void CppCheckExecutor : : reportInfo ( const ErrorLogger : : ErrorMessage & msg )
{
2012-07-04 18:21:56 +02:00
reportErr ( msg ) ;
2012-06-18 23:15:48 +02:00
}
2012-07-08 23:39:46 +02:00
void CppCheckExecutor : : reportStatus ( std : : size_t fileindex , std : : size_t filecount , std : : size_t sizedone , std : : size_t sizetotal )
2009-02-19 23:21:18 +01:00
{
2011-10-13 20:53:06 +02:00
if ( filecount > 1 ) {
2009-02-19 23:21:18 +01:00
std : : ostringstream oss ;
2017-08-29 16:51:56 +02:00
const long percentDone = ( sizetotal > 0 ) ? static_cast < long > ( static_cast < long double > ( sizedone ) / sizetotal * 100 ) : 0 ;
2012-02-18 11:55:05 +01:00
oss < < fileindex < < ' / ' < < filecount
2017-08-29 16:51:56 +02:00
< < " files checked " < < percentDone
2010-04-15 20:08:51 +02:00
< < " % done " ;
2009-02-19 23:21:18 +01:00
std : : cout < < oss . str ( ) < < std : : endl ;
}
}
2009-02-10 22:51:52 +01:00
void CppCheckExecutor : : reportErr ( const ErrorLogger : : ErrorMessage & msg )
2009-02-01 19:00:47 +01:00
{
2019-07-15 18:31:12 +02:00
if ( mShowAllErrors ) {
2017-07-29 18:56:22 +02:00
reportOut ( msg . toXML ( ) ) ;
2019-07-15 18:24:27 +02:00
} else if ( mSettings - > xml ) {
2017-07-29 18:56:22 +02:00
reportErr ( msg . toXML ( ) ) ;
2011-10-13 20:53:06 +02:00
} else {
2019-07-15 18:24:27 +02:00
reportErr ( msg . toString ( mSettings - > verbose , mSettings - > templateFormat , mSettings - > templateLocation ) ) ;
2009-02-09 21:51:04 +01:00
}
2009-02-01 19:00:47 +01:00
}
2014-05-25 08:47:37 +02:00
2019-07-15 18:11:11 +02:00
void CppCheckExecutor : : setExceptionOutput ( FILE * exceptionOutput )
2014-05-25 08:47:37 +02:00
{
2019-07-15 18:11:11 +02:00
mExceptionOutput = exceptionOutput ;
2014-05-25 08:47:37 +02:00
}
2014-05-25 15:53:26 +02:00
2015-11-25 22:37:38 +01:00
FILE * CppCheckExecutor : : getExceptionOutput ( )
2014-05-25 08:47:37 +02:00
{
2019-07-15 18:11:11 +02:00
return mExceptionOutput ;
2014-05-25 08:47:37 +02:00
}
2014-05-25 15:53:26 +02:00
2015-01-10 22:18:57 +01:00
bool CppCheckExecutor : : tryLoadLibrary ( Library & destination , const char * basepath , const char * filename )
{
2015-03-07 20:47:27 +01:00
const Library : : Error err = destination . load ( basepath , filename ) ;
2015-01-10 22:18:57 +01:00
if ( err . errorcode = = Library : : UNKNOWN_ELEMENT )
std : : cout < < " cppcheck: Found unknown elements in configuration file ' " < < filename < < " ': " < < err . reason < < std : : endl ;
else if ( err . errorcode ! = Library : : OK ) {
std : : string errmsg ;
switch ( err . errorcode ) {
case Library : : OK :
break ;
case Library : : FILE_NOT_FOUND :
errmsg = " File not found " ;
break ;
case Library : : BAD_XML :
errmsg = " Bad XML " ;
break ;
case Library : : UNKNOWN_ELEMENT :
errmsg = " Unexpected element " ;
break ;
case Library : : MISSING_ATTRIBUTE :
errmsg = " Missing attribute " ;
break ;
case Library : : BAD_ATTRIBUTE_VALUE :
errmsg = " Bad attribute value " ;
break ;
case Library : : UNSUPPORTED_FORMAT :
errmsg = " File is of unsupported format version " ;
break ;
case Library : : DUPLICATE_PLATFORM_TYPE :
errmsg = " Duplicate platform type " ;
break ;
case Library : : PLATFORM_TYPE_REDEFINED :
errmsg = " Platform type redefined " ;
break ;
}
if ( ! err . reason . empty ( ) )
errmsg + = " ' " + err . reason + " ' " ;
std : : cout < < " cppcheck: Failed to load library configuration file ' " < < filename < < " '. " < < errmsg < < std : : endl ;
return false ;
}
return true ;
}