Exemple #1
0
 def make_complex_analysis(self):
     """
     Construct a Analysis instance that uses all features
     """
     a = Analysis(
         metadata=Metadata(generator=Generator(name='cpychecker',
                                               version='0.11'),
                           sut=SourceRpm(name='python-ethtool',
                                         version='0.7',
                                         release='4.fc19',
                                         buildarch='x86_64'),
                           file_=File(givenpath='foo.c',
                                      abspath='/home/david/coding/foo.c'),
                           stats=Stats(wallclocktime=0.4)),
         results=[
             Issue(cwe=681,
                   testid='refcount-too-high',
                   location=Location(file=File(
                       givenpath='foo.c',
                       abspath='/home/david/coding/foo.c'),
                                     function=Function('bar'),
                                     point=Point(10, 15)),
                   message=Message(text='something bad involving pointers'),
                   notes=Notes('here is some explanatory text'),
                   trace=Trace([
                       State(location=Location(file=File('foo.c', None),
                                               function=Function('bar'),
                                               point=Point(7, 12)),
                             notes=Notes('first we do this')),
                       State(location=Location(file=File('foo.c', None),
                                               function=Function('bar'),
                                               point=Point(8, 10)),
                             notes=Notes('then we do that')),
                       State(location=Location(file=File('foo.c', None),
                                               function=Function('bar'),
                                               range_=Range(
                                                   Point(10, 15),
                                                   Point(10, 25))),
                             notes=Notes('then it crashes here'))
                   ]),
                   severity='really bad',
                   customfields=CustomFields(foo='bar')),
         ],
         customfields=CustomFields(
             gccinvocation='gcc -I/usr/include/python2.7 -c foo.c'),
     )
     return a, a.results[0]
Exemple #2
0
def parse_file(fileobj, sut=None, file_=None, stats=None):
    tree = ET.parse(fileobj)
    root = tree.getroot()
    node_cppcheck = root.find('cppcheck')
    version = node_cppcheck.get('version')
    node_errors = root.find('errors')

    generator = Generator(name='cppcheck',
                          version=node_cppcheck.get('version'))
    metadata = Metadata(generator, sut, file_, stats)
    analysis = Analysis(metadata, [])

    for node_error in node_errors.findall('error'):
        # e.g.:
        # <error id="nullPointer" severity="error" msg="Possible null pointer dereference: end - otherwise it is redundant to check it against null." verbose="Possible null pointer dereference: end - otherwise it is redundant to check it against null.">
        #  <location file="python-ethtool/ethtool.c" line="139"/>
        #  <location file="python-ethtool/ethtool.c" line="141"/>
        # </error>
        testid = node_error.get('id')
        str_msg = node_error.get('msg')
        str_verbose = node_error.get('verbose')
        message = Message(text=str_msg)
        if str_verbose != str_msg:
            notes = Notes(str_verbose)
        else:
            notes = None

        location_nodes = list(node_error.findall('location'))
        for node_location in location_nodes:
            location = Location(
                file=File(node_location.get('file'), None),

                # FIXME: doesn't tell us function name
                # TODO: can we patch this upstream?
                function=None,

                # doesn't emit column
                point=Point(int(node_location.get('line')),
                            0))  # FIXME: bogus column
            issue = Issue(None,
                          testid,
                          location,
                          message,
                          notes,
                          None,
                          severity=node_error.get('severity'))
            analysis.results.append(issue)

        if not location_nodes:
            customfields = CustomFields()
            if str_verbose != str_msg:
                customfields['verbose'] = str_verbose
            failure = Failure(failureid=testid,
                              location=None,
                              message=message,
                              customfields=customfields)
            analysis.results.append(failure)

    return analysis
Exemple #3
0
def label_warnings(reports):
    """This function labels each warning as true or false positive. Warnings
    whose label is not possible to determine according to Juliet documentation,
    are removed from the output list.

    in: list with Analysis objects from Juliet analyses
    out: list with Analysis objects labeled as true or false positives.
    """
    line_labels = get_line_labels()
    create_raw_cwe_vs_warning_file = False
    raw_cwe_warning_path = 'raw_cwe_versus_warning_msg.txt'
    raw_cwe_warning_fh = None
    if not os.path.exists(raw_cwe_warning_path):
        """This file is needed to perform the manual extractions of the
        regular expressions used in this function to determine which messages
        correspond to which CWEs. If the file does not exist, create it.
        """
        create_raw_cwe_vs_warning_file = True
        raw_cwe_warning_fh = open(raw_cwe_warning_path, 'w')

    for report in reports:
        # we want to iterate in a copy of results to be able to remove entries.
        for warning in report.results.copy():
            if not warning.location:
                # Discard non labelable warning (missing include warnings)
                report.results.remove(warning)
                continue  # discard
            file_name = os.path.basename(warning.location.file.givenpath)
            file_line = warning.location.point.line
            if((not re.search('^CWE[^.]*\.(c|cpp)$', file_name)) or
                    (file_line not in line_labels[file_name])):
                # Discard non labelable warning
                report.results.remove(warning)
                continue

            message = warning.message.text
            # cwe = warning.cwe
            # severity = warning.severity
            testcase_cwe = file_name.split('__')[0]
            if create_raw_cwe_vs_warning_file:
                print("%s\t%s" % (testcase_cwe, message), raw_cwe_warning_fh)

            if warning_match_cwe(testcase_cwe, message):
                if warning.customfields is None:
                    warning.customfields = CustomFields()
                if line_labels[file_name][file_line] == 'good':
                    warning.customfields['positive'] = 'true'
                elif line_labels[file_name][file_line] == 'bad':
                    warning.customfields['positive'] = 'false'
                else:
                    raise NameError("Cannot label warning")
            else:
                report.results.remove(warning)

    if raw_cwe_warning_fh is not None:
        raw_cwe_warning_fh.close()
    return reports
Exemple #4
0
def parse_json_v2(path):
    """
    Given a JSON file emitted by:
      cov-format-errors --json-output-v2=<filename>
    parse it and return an Analysis instance
    """
    with open(path) as f:
        js = json.load(f)
    if 0:
        pprint(js)

    generator = Generator(name='coverity')
    metadata = Metadata(generator, sut=None, file_=None, stats=None)
    analysis = Analysis(metadata, [])

    for issue in js['issues']:
        if 0:
            pprint(issue)

        cwe = None

        # Use checkerName (e.g. "RESOURCE_LEAK") for
        # the testid:
        testid = issue['checkerName']

        # Use the eventDescription of the final event for the message:
        message = Message(text=issue['events'][-1]['eventDescription'])

        location = Location(
            file=File(givenpath=issue['mainEventFilePathname'], abspath=None),
            function=Function(name=issue['functionDisplayName']),
            point=Point(int(issue['mainEventLineNumber']), int(0)))

        notes = None

        trace = make_trace(issue)

        customfields = CustomFields()
        for key in ['mergeKey', 'subcategory', 'domain']:
            if key in issue:
                customfields[key] = issue[key]

        issue = Issue(cwe,
                      testid,
                      location,
                      message,
                      notes,
                      trace,
                      customfields=customfields)

        analysis.results.append(issue)

    return analysis
Exemple #5
0
 def make_info(self):
     a = Analysis(
         metadata=Metadata(generator=Generator(name='an-invented-checker'),
                           sut=None,
                           file_=None,
                           stats=None),
         results=[
             Info(infoid='gimple-stats',
                  location=Location(file=File('bar.c', None),
                                    function=Function('sample_function'),
                                    point=Point(10, 15)),
                  message=Message('sample message'),
                  customfields=CustomFields(num_stmts=57,
                                            num_basic_blocks=10))
         ])
     return a, a.results[0]
Exemple #6
0
 def make_failed_analysis(self):
     a = Analysis(
         metadata=Metadata(generator=Generator(name='yet-another-checker'),
                           sut=None,
                           file_=None,
                           stats=None),
         results=[
             Failure(failureid='out-of-memory',
                     location=Location(
                         file=File('foo.c', None),
                         function=Function('something_complicated'),
                         point=Point(10, 15)),
                     message=Message('out of memory'),
                     customfields=CustomFields(stdout='sample stdout',
                                               stderr='sample stderr',
                                               returncode=-9))  # (killed)
         ])
     return a, a.results[0]
Exemple #7
0
def parse_plist(pathOrFile,
                analyzerversion=None,
                sut=None,
                file_=None,
                stats=None):
    """
    Given a .plist file emitted by clang-static-analyzer (e.g. via
    scan-build), parse it and return an Analysis instance
    """
    plist = plistlib.readPlist(pathOrFile)
    # We now have the .plist file as a hierarchy of dicts, lists, etc

    # Handy debug dump:
    if 0:
        pprint(plist)

    # A list of filenames, apparently referenced by index within
    # diagnostics:
    files = plist['files']

    generator = Generator(name='clang-analyzer', version=analyzerversion)
    metadata = Metadata(generator, sut, file_, stats)
    analysis = Analysis(metadata, [])

    if 'clang_version' in plist:
        generator.version = plist['clang_version']

    for diagnostic in plist['diagnostics']:
        if 0:
            pprint(diagnostic)

        cwe = None

        customfields = CustomFields()
        for key in ['category', 'issue_context', 'issue_context_kind']:
            if key in diagnostic:
                customfields[key] = diagnostic[key]

        message = Message(text=diagnostic['description'])

        loc = diagnostic['location']
        location = Location(
            file=File(givenpath=files[loc['file']], abspath=None),

            # FIXME: doesn't tell us function name
            # TODO: can we patch this upstream?
            function=None,
            point=Point(int(loc['line']), int(loc['col'])))

        notes = None

        trace = make_trace(files, diagnostic['path'])

        issue = Issue(
            cwe,
            # Use the 'type' field for the testid:
            diagnostic['type'],
            location,
            message,
            notes,
            trace,
            customfields=customfields)

        analysis.results.append(issue)

    return analysis