new file mode 100755
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+# Copyright 2017 David Malcolm <dmalcolm@redhat.com>
+# Copyright 2017 Red Hat, Inc.
+#
+# This 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
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+import tempfile
+
+from firehose.model import File, Issue
+from firehose.parsers.splint import parse_splint_csv, parse_splint_stderr
+
+from checker import Checker, CheckerTests, tool_main
+
+class InvokeSplint(Checker):
+ """
+ Checker subclass that invokes "splint -strict"
+ """
+ name = 'splint'
+
+ def __init__(self, ctxt):
+ Checker.__init__(self, ctxt)
+ self.tempfile = None
+
+ def __del__(self):
+ del self.tempfile
+
+ def raw_invoke(self, gccinv, sourcefile):
+ self.tempfile = tempfile.NamedTemporaryFile()
+ args = ['splint', '-csv', self.tempfile.name, '+csvoverwrite', '-strict', sourcefile]
+ # FIXME: why is overwrite needed?
+ return self._run_subprocess(sourcefile, args)
+
+ def handle_output(self, result):
+ analysis = parse_splint_csv(self.tempfile.name)
+ analysis.metadata.file_ = File(result.sourcefile, None)
+ analysis.metadata.version = parse_splint_stderr(result.err)
+ self.set_custom_fields(result, analysis)
+ return analysis
+
+ def set_custom_fields(self, result, analysis):
+ analysis.set_custom_field('splint-invocation',
+ ' '.join(result.argv))
+ result.set_custom_fields(analysis)
+
+class SplintTests(CheckerTests):
+ def make_tool(self):
+ return self.make_tool_from_class(InvokeSplint)
+
+ def verify_basic_metadata(self, analysis, sourcefile):
+ # Verify basic metadata:
+ self.assert_metadata(analysis, 'splint', sourcefile)
+ self.assert_has_custom_field(analysis, 'splint-invocation')
+ self.assert_has_custom_field(analysis, 'stdout')
+ self.assert_has_custom_field(analysis, 'stderr')
+
+ def test_unconditional_leak(self):
+ analysis = self.invoke('test-sources/unconditional-file-leak.c')
+ self.assertEqual(len(analysis.results), 8)
+ r0 = analysis.results[0]
+ self.assertIsInstance(r0, Issue)
+ self.assertEqual(r0.testid, 'internalglobs')
+
+if __name__ == '__main__':
+ sys.exit(tool_main(sys.argv, InvokeSplint))