1010import signal
1111import tarfile
1212import shlex
13+ import psutil
1314
1415
1516# Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/
1617# Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic
1718# changes)
18- CLIENT_VERSION = "1.3.8 "
19+ CLIENT_VERSION = "1.3.9 "
1920
2021# Timeout for analysis with Cppcheck in seconds
2122CPPCHECK_TIMEOUT = 30 * 60
@@ -255,14 +256,25 @@ def has_include(path, includes):
255256def run_command (cmd ):
256257 print (cmd )
257258 startTime = time .time ()
259+ comm = None
258260 p = subprocess .Popen (shlex .split (cmd ), stdout = subprocess .PIPE , stderr = subprocess .PIPE , preexec_fn = os .setsid )
259261 try :
260262 comm = p .communicate (timeout = CPPCHECK_TIMEOUT )
261263 return_code = p .returncode
264+ p = None
262265 except subprocess .TimeoutExpired :
263- os .killpg (os .getpgid (p .pid ), signal .SIGTERM ) # Send the signal to all the process groups
264- comm = p .communicate ()
265266 return_code = RETURN_CODE_TIMEOUT
267+ # terminate all the child processes so we get messages about which files were hanging
268+ child_procs = psutil .Process (p .pid ).children (recursive = True )
269+ if len (child_procs ) > 0 :
270+ for child in child_procs :
271+ child .terminate ()
272+ comm = p .communicate ()
273+ p = None
274+ finally :
275+ if p :
276+ os .killpg (os .getpgid (p .pid ), signal .SIGTERM ) # Send the signal to all the process groups
277+ comm = p .communicate ()
266278 stop_time = time .time ()
267279 stdout = comm [0 ].decode (encoding = 'utf-8' , errors = 'ignore' )
268280 stderr = comm [1 ].decode (encoding = 'utf-8' , errors = 'ignore' )
@@ -290,16 +302,51 @@ def scan_package(work_path, cppcheck_path, jobs, libraries):
290302 cppcheck_cmd = cppcheck_path + '/cppcheck' + ' ' + options
291303 cmd = 'nice ' + cppcheck_cmd
292304 returncode , stdout , stderr , elapsed_time = run_command (cmd )
305+
306+ # collect messages
307+ information_messages_list = []
308+ issue_messages_list = []
309+ internal_error_messages_list = []
310+ count = 0
311+ for line in stderr .split ('\n ' ):
312+ if ': information: ' in line :
313+ information_messages_list .append (line + '\n ' )
314+ elif line :
315+ issue_messages_list .append (line + '\n ' )
316+ if re .match (r'.*:[0-9]+:.*\]$' , line ):
317+ count += 1
318+ if ': error: Internal error: ' in line :
319+ internal_error_messages_list .append (line + '\n ' )
320+ print ('Number of issues: ' + str (count ))
321+ # Collect timing information
322+ stdout_lines = stdout .split ('\n ' )
323+ timing_info_list = []
324+ overall_time_found = False
325+ max_timing_lines = 6
326+ current_timing_lines = 0
327+ for reverse_line in reversed (stdout_lines ):
328+ if reverse_line .startswith ('Overall time:' ):
329+ overall_time_found = True
330+ if overall_time_found :
331+ if not reverse_line or current_timing_lines >= max_timing_lines :
332+ break
333+ timing_info_list .insert (0 , ' ' + reverse_line + '\n ' )
334+ current_timing_lines += 1
335+ timing_str = '' .join (timing_info_list )
336+
337+ # detect errors
293338 sig_num = - 1
294339 sig_msg = 'Internal error: Child process crashed with signal '
295340 sig_pos = stderr .find (sig_msg )
296341 if sig_pos != - 1 :
297342 sig_start_pos = sig_pos + len (sig_msg )
298343 sig_num = int (stderr [sig_start_pos :stderr .find (' ' , sig_start_pos )])
299344 print ('cppcheck finished with ' + str (returncode ) + ('' if sig_num == - 1 else ' (signal ' + str (sig_num ) + ')' ))
345+
300346 if returncode == RETURN_CODE_TIMEOUT :
301347 print ('Timeout!' )
302- return returncode , stdout , '' , elapsed_time , options , ''
348+ return returncode , '' .join (internal_error_messages_list ), '' , elapsed_time , options , ''
349+
303350 # generate stack trace for SIGSEGV, SIGABRT, SIGILL, SIGFPE, SIGBUS
304351 if returncode in (- 11 , - 6 , - 4 , - 8 , - 7 ) or sig_num in (11 , 6 , 4 , 8 , 7 ):
305352 print ('Crash!' )
@@ -319,48 +366,24 @@ def scan_package(work_path, cppcheck_path, jobs, libraries):
319366 if not stacktrace :
320367 stacktrace = stdout
321368 return returncode , stacktrace , '' , returncode , options , ''
369+
322370 if returncode != 0 :
323371 print ('Error!' )
324372 if returncode > 0 :
325373 returncode = - 100 - returncode
326374 return returncode , stdout , '' , returncode , options , ''
327- err_s = 'Internal error: Child process crashed with signal '
328- err_pos = stderr .find (err_s )
329- if err_pos != - 1 :
375+
376+ if sig_pos != - 1 :
330377 print ('Error!' )
331- pos2 = stderr .find (' [cppcheckError]' , err_pos )
332- signr = int (stderr [err_pos + len (err_s ):pos2 ])
378+ pos2 = stderr .find (' [cppcheckError]' , sig_pos )
379+ signr = int (stderr [sig_pos + len (sig_msg ):pos2 ])
333380 return - signr , '' , '' , - signr , options , ''
381+
334382 thr_pos = stderr .find ('#### ThreadExecutor' )
335383 if thr_pos != - 1 :
336384 print ('Thread!' )
337385 return - 222 , stderr [thr_pos :], '' , - 222 , options , ''
338- information_messages_list = []
339- issue_messages_list = []
340- count = 0
341- for line in stderr .split ('\n ' ):
342- if ': information: ' in line :
343- information_messages_list .append (line + '\n ' )
344- elif line :
345- issue_messages_list .append (line + '\n ' )
346- if re .match (r'.*:[0-9]+:.*\]$' , line ):
347- count += 1
348- print ('Number of issues: ' + str (count ))
349- # Collect timing information
350- stdout_lines = stdout .split ('\n ' )
351- timing_info_list = []
352- overall_time_found = False
353- max_timing_lines = 6
354- current_timing_lines = 0
355- for reverse_line in reversed (stdout_lines ):
356- if reverse_line .startswith ('Overall time:' ):
357- overall_time_found = True
358- if overall_time_found :
359- if not reverse_line or current_timing_lines >= max_timing_lines :
360- break
361- timing_info_list .insert (0 , ' ' + reverse_line + '\n ' )
362- current_timing_lines += 1
363- timing_str = '' .join (timing_info_list )
386+
364387 return count , '' .join (issue_messages_list ), '' .join (information_messages_list ), elapsed_time , options , timing_str
365388
366389
0 commit comments