def invoke_side_effects(argv): log("invoke_side_effects: %s" % ' '.join(sys.argv)) gccinv = GccInvocation(argv) # Try to run each side effect in a subprocess, passing in a path # for the XML results to be written to. # Cover a multitude of possible failures by detecting if no output # was written, and capturing *that* as a failure for sourcefile in gccinv.sources: if sourcefile.endswith('.c'): # FIXME: other extensions? for script, genname in [('invoke-cppcheck', 'cppcheck'), ('invoke-clang-analyzer', 'clang-analyzer'), ('invoke-cpychecker', 'cpychecker'), # Uncomment the following to test a # checker that fails to write any XML: # ('echo', 'failing-checker'), ]: with tempfile.NamedTemporaryFile() as f: dstxmlpath = f.name assert not os.path.exists(dstxmlpath) # Restrict the invocation to just one source file at a # time: singleinv = gccinv.restrict_to_one_source(sourcefile) singleargv = singleinv.argv TIMEOUT=60 t = Timer() args = [script, dstxmlpath] + singleargv log('invoking args: %r' % args) p = Popen(args, stdout=PIPE, stderr=PIPE) try: out, err = p.communicate(timeout=TIMEOUT) write_streams(script, out, err) if os.path.exists(dstxmlpath): with open(dstxmlpath) as f: analysis = Analysis.from_xml(f) else: analysis = make_failed_analysis(genname, sourcefile, t, msgtext=('Unable to locate XML output from %s' % script), failureid='no-output-found') analysis.set_custom_field('stdout', out) analysis.set_custom_field('stderr', err) analysis.set_custom_field('returncode', p.returncode) except TimeoutExpired: analysis = make_failed_analysis(genname, sourcefile, t, msgtext='Timeout running %s' % genname, failureid='timeout') analysis.set_custom_field('timeout', TIMEOUT) analysis.set_custom_field('gcc-invocation', ' '.join(argv)) write_analysis_as_xml(analysis)
def invoke(self, argv): """FIXME""" self.log("Driver.invoke: %s" % ' '.join(sys.argv)) gccinv = GccInvocation(argv) self.log(' gccinv.sources: %r' % gccinv.sources) # Run the side effects on each source file: for sourcefile in gccinv.sources: self.log(' sourcefile: %r' % sourcefile) if sourcefile.endswith('.c'): # FIXME: other extensions? single_source_gccinv = gccinv.restrict_to_one_source(sourcefile) # Avoid linker errors due to splitting up the build into # multiple gcc invocations: single_source_gccinv.argv += ['-c'] self.log(' single_source_gccinv: %r' % single_source_gccinv) for side_effect in self.side_effects: analysis = self.invoke_tool(side_effect, single_source_gccinv, sourcefile) #analysis.set_custom_field('gcc-invocation', ' '.join(argv)) self.write_analysis_as_xml(analysis) # Now run the real driver. # Note that we already ran the real gcc earlier as a # side-effect per source-file, capturing warnings there. # We have to do it separately from here since the invocation # might cover multiple source files. argv = [self.real_driver] + gccinv.argv[1:] env=os.environ.copy() # FIXME: this probably shouldn't be hardcoded env['LANG'] = 'C' p = Popen(argv, stdout=PIPE, stderr=PIPE, env=env) out, err = p.communicate() self.ctxt.stdout.write(out) self.ctxt.stderr.write(err) self.returncode = p.returncode
def __init__(self, path): self.stats = {} self.utimes = Counter() self.lifetimes = Counter() if path.endswith('.gz'): opener = gzip.open else: opener = open self.error_count = 0 with opener(path) as f: for linenum, line in enumerate(f): m = pattern.match(line) if m: utime, lifetime, cmdline = m.groups() utime = int(utime) lifetime = int(lifetime) #print(cmdline) progname = os.path.basename(cmdline.split()[0]) if progname not in GCC_PROGRAMS: # Skip commands that GccInvocation can't parse: continue gccinv = GccInvocation.from_cmdline(cmdline) #print(gccinv) #print(gccinv.executable) #print(gccinv.progname) if gccinv.progname in GCC_PROGRAMS: # Don't try to handle collect2 yet: if gccinv.progname == 'collect2': continue # Ensure that we're reliably extracting the name of the # source file from the log: if not gccinv.sources: if '-print-file-name=include' in gccinv.otherargs: continue if len(gccinv.sources) != 1: # Skip linkage invocations of gcc: if all(src.endswith('.o') for src in gccinv.sources): continue sys.stderr.write('%s:%i: more that one source: sources: %r in %r line: %r\n' % (path, linenum + 1, gccinv.sources, gccinv, line)) self.error_count += 1 srcfile = gccinv.sources[0] self.stats[(gccinv.progname, srcfile)] = (utime, lifetime) if gccinv.progname == 'cc1': self.utimes[srcfile] = utime self.lifetimes[srcfile] = lifetime