From 1d91cf67118b1ed1850ff9971f55861737421ac2 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 26 May 2017 12:05:08 -0400
Subject: [PATCH 24/28] FIXME: add splint support

---
 checkers/Makefile                                  |  1 +
 checkers/splint.py                                 | 81 ++++++++++++++++++++++
 checkers/test-sources/unconditional-file-leak.c    |  6 +-
 .../selftests/checker-policy/test-policy.json      |  2 +
 4 files changed, 88 insertions(+), 2 deletions(-)
 create mode 100755 checkers/splint.py

diff --git a/checkers/Makefile b/checkers/Makefile
index a5da135..c08cac4 100644
--- a/checkers/Makefile
+++ b/checkers/Makefile
@@ -5,5 +5,6 @@ check-all:
 	python clang_analyzer.py unittest
 	python cppcheck.py unittest
 	python flawfinder.py unittest
+	python splint.py unittest
 	python always_fails.py unittest
 	python ianal.py unittest
diff --git a/checkers/splint.py b/checkers/splint.py
new file mode 100755
index 0000000..4bb8035
--- /dev/null
+++ b/checkers/splint.py
@@ -0,0 +1,81 @@
+#!/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
+import unittest
+
+from gccinvocation import GccInvocation
+
+from checker import Checker, Context, CheckerTests, make_file, make_stats, \
+    tool_main
+
+from firehose.model import Analysis, Generator, Metadata, Failure, \
+    Location, File, Message, Issue, Trace
+from firehose.parsers.splint import parse_splint_csv, parse_splint_stderr
+
+class InvokeSplint(Checker):
+    """
+    Checker subclass that invokes "splint -strict"
+    """
+    def __init__(self, ctxt):
+        Checker.__init__(self, 'splint', 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):
+        ctxt = self.make_ctxt()
+        return InvokeSplint(ctxt)
+
+    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))
diff --git a/checkers/test-sources/unconditional-file-leak.c b/checkers/test-sources/unconditional-file-leak.c
index b4c6153..3c6655c 100644
--- a/checkers/test-sources/unconditional-file-leak.c
+++ b/checkers/test-sources/unconditional-file-leak.c
@@ -2,7 +2,9 @@
 
 void test (const char *filename)
 {
-  FILE *f = fopen (filename, "w");
-  for (int i = 0; i < 10; i++)
+  int i;
+  FILE *f;
+  f = fopen (filename, "w");
+  for (i = 0; i < 10; i++)
     fprintf (f, "%i: %i",  i,  i * i);
 }
diff --git a/gcc/testsuite/selftests/checker-policy/test-policy.json b/gcc/testsuite/selftests/checker-policy/test-policy.json
index 90532b2..0d50d1b 100644
--- a/gcc/testsuite/selftests/checker-policy/test-policy.json
+++ b/gcc/testsuite/selftests/checker-policy/test-policy.json
@@ -4,4 +4,6 @@
    "languages": ["c", "c++"] },
  { "executable": "../../src/checkers/flawfinder.py",
    "languages": ["c", "c++"] },
+ { "executable": "../../src/checkers/splint.py",
+   "languages": ["c"] },
  { "executable": "../../src/checkers/ianal.py"}]
-- 
1.8.5.3

