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
Example #3
0
    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