/* * Sonar Cxx Plugin, open source software quality management tool. * Copyright (C) 2010 François DORIN * * Sonar Cxx Plugin is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Sonar Cxx Plugin 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Sonar Cxx Plugin; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ package org.sonar.plugins.cxx.rats; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.sonar.api.batch.Sensor; import org.sonar.api.batch.SensorContext; import org.sonar.api.resources.Project; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.Violation; import org.sonar.plugins.cxx.CxxFile; import org.sonar.plugins.cxx.CxxLanguage; public final class CxxRatsSensor implements Sensor { static final String PATH = "/src/main/native"; static final String EXEC = "rats"; static final String ARGS = "-w 3 --xml"; private RuleFinder ruleFinder; public CxxRatsSensor(RuleFinder ruleFinder) { this.ruleFinder = ruleFinder; } public boolean shouldExecuteOnProject(Project project) { return project.getLanguageKey().equals(CxxLanguage.KEY); } public void analyse(Project project, SensorContext sensorContext) { final StringBuilder sb = new StringBuilder(); String sourceDir; Process p; sb.append(project.getFileSystem().getBasedir().getAbsoluteFile()); sb.append(PATH); sourceDir = sb.toString(); try { File temp = File.createTempFile("temp", "rats"); p = Runtime.getRuntime().exec(EXEC + " " + ARGS + " " + sourceDir); temp.deleteOnExit(); writeFile(temp, p.getInputStream()); analyseXmlReport(temp, project, sensorContext); } catch(IOException ex) { } } void writeFile(File file, InputStream is) throws IOException { final OutputStream fo = new FileOutputStream(file); byte[] buf = new byte[1024]; int len; while ((len = is.read(buf)) > 0) { fo.write(buf, 0, len); } is.close(); fo.close(); } void analyseXmlReport(File xmlReport, Project project, SensorContext context) { final SAXBuilder builder = new SAXBuilder(false); try { final Document doc = builder.build(xmlReport); final Element root = doc.getRootElement(); @SuppressWarnings("unchecked") final List<Element> vulnerabilities = root.getChildren("vulnerability"); for (Element element : vulnerabilities) { analyseVulnerabilities(element, project, context); } } catch(JDOMException ex) { } catch(IOException ex) { } } /* * <vulnerability> * <severity>High</severity> * <type>fixed size global buffer</type> * <message> * Extra care should be taken to ensure that character arrays that are * allocated on the stack are used safely. They are prime targets for * buffer overflow attacks. * </message> * <file> * <name>ModuloCalculo/src/CompactaAReal.cpp</name> * <line>40</line> * <line>58</line> * </file> * </vulnerability> */ void analyseVulnerabilities(Element vulnerability, Project project, SensorContext context) { final String type = vulnerability.getChild("type").getTextTrim(); final String message = vulnerability.getChild("message").getTextTrim(); @SuppressWarnings("unchecked") final List<Element> files = vulnerability.getChildren("file"); for(Element file : files) { final String filename = file.getChild("name").getTextTrim(); @SuppressWarnings("unchecked") final List<Element> lines = file.getChildren("line"); for(Element line : lines) { final int lineNumber = Integer.parseInt(line.getTextTrim()); final CxxFile ressource = CxxFile.fromFileName(project, filename, false); final Rule rule = ruleFinder. findByKey(CxxRatsRuleRepository.REPOSITORY_KEY, type); final Violation violation = Violation.create(rule, ressource); violation.setMessage(message); violation.setLineId(lineNumber); context.saveViolation(violation); } } } @Override public String toString() { return getClass().getSimpleName(); } }