From 78c517168a4148ea4c5ee2cb41de876907ae2c37 Mon Sep 17 00:00:00 2001 From: Marcelo Luiz Onhate Date: Fri, 26 May 2017 16:23:39 -0300 Subject: [PATCH] avoid srcml infinite loop https://github.com/GumTreeDiff/gumtree/issues/50 --- .../gen/srcml/AbstractSrcmlTreeGenerator.java | 76 ++++++++++++++----- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/gen.srcml/src/main/java/com/github/gumtreediff/gen/srcml/AbstractSrcmlTreeGenerator.java b/gen.srcml/src/main/java/com/github/gumtreediff/gen/srcml/AbstractSrcmlTreeGenerator.java index c41e77c6d..b0d14bb9b 100644 --- a/gen.srcml/src/main/java/com/github/gumtreediff/gen/srcml/AbstractSrcmlTreeGenerator.java +++ b/gen.srcml/src/main/java/com/github/gumtreediff/gen/srcml/AbstractSrcmlTreeGenerator.java @@ -24,20 +24,33 @@ import com.github.gumtreediff.tree.ITree; import com.github.gumtreediff.tree.TreeContext; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.events.*; -import java.io.*; -import java.util.*; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; public abstract class AbstractSrcmlTreeGenerator extends TreeGenerator { private static final String SRCML_CMD = System.getProperty("gumtree.srcml.path", "srcml"); - private static final QName LINE = new QName("http://www.srcML.org/srcML/position", "line", "pos"); + private static final QName LINE = new QName("http://www.srcML.org/srcML/position", "line", "pos"); - private static final QName COLUMN = new QName("http://www.srcML.org/srcML/position", "column", "pos"); + private static final QName COLUMN = new QName("http://www.srcML.org/srcML/position", "column", "pos"); private LineReader lr; @@ -62,9 +75,9 @@ public TreeContext getTreeContext(String xml) { if (ev.isStartElement()) { StartElement s = ev.asStartElement(); String typeLabel = s.getName().getLocalPart(); - if (typeLabel.equals("position")) + if (typeLabel.equals("position")) { setLength(trees.peek(), s); - else { + } else { int type = typeLabel.hashCode(); ITree t = context.createTree(type, "", typeLabel); @@ -79,14 +92,16 @@ public TreeContext getTreeContext(String xml) { } } else if (ev.isEndElement()) { EndElement end = ev.asEndElement(); - if (!end.getName().getLocalPart().equals("position")) + if (!end.getName().getLocalPart().equals("position")) { trees.pop(); + } } else if (ev.isCharacters()) { Characters chars = ev.asCharacters(); if (!chars.isWhiteSpace() && trees.peek().getLabel().equals("") - && labeled.contains(context.getTypeLabel(trees.peek().getType()))) + && labeled.contains(context.getTypeLabel(trees.peek().getType()))) { trees.peek().setLabel(chars.getData().trim()); + } } } fixPos(context); @@ -104,9 +119,9 @@ private void fixPos(TreeContext ctx) { if (t.getPos() == ITree.NO_VALUE || t.getLength() == ITree.NO_VALUE) { ITree firstChild = t.getChild(0); t.setPos(firstChild.getPos()); - if (t.getChildren().size() == 1) + if (t.getChildren().size() == 1) { t.setLength(firstChild.getLength()); - else { + } else { ITree lastChild = t.getChild(t.getChildren().size() - 1); t.setLength(lastChild.getEndPos() - firstChild.getPos()); } @@ -124,8 +139,9 @@ private void setPos(ITree t, StartElement e) { } private void setLength(ITree t, StartElement e) { - if (t.getPos() == -1) + if (t.getPos() == -1) { return; + } if (e.getAttributeByName(LINE) != null) { int line = Integer.parseInt(e.getAttributeByName(LINE).getValue()); int column = Integer.parseInt(e.getAttributeByName(COLUMN).getValue()); @@ -135,7 +151,7 @@ private void setLength(ITree t, StartElement e) { public String getXml(Reader r) throws IOException { //FIXME this is not efficient but I am not sure how to speed up things here. - File f = File.createTempFile("gumtree", ""); + File f = createTempFile(); FileWriter w = new FileWriter(f); BufferedReader br = new BufferedReader(r); String line = br.readLine(); @@ -147,30 +163,48 @@ public String getXml(Reader r) throws IOException { w.close(); br.close(); ProcessBuilder b = new ProcessBuilder(getArguments(f.getAbsolutePath())); + b.redirectErrorStream(true); b.directory(f.getParentFile()); try { Process p = b.start(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); br = new BufferedReader(new InputStreamReader(p.getInputStream())); - // TODO Why do we need to read and bufferize everything, when we could/should only use generateFromStream - line = null; - while ((line = br.readLine()) != null) - buf.append(line + "\n"); + while ((line = br.readLine()) != null) { + buf.append(line).append("\n"); + } + p.waitFor(); - if (p.exitValue() != 0) throw new RuntimeException(); + if (p.exitValue() != 0) { + throw new RuntimeException(); + } r.close(); - String xml = buf.toString(); - return xml; + return buf.toString(); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); throw new RuntimeException(e); } finally { f.delete(); } } + private static File DEV_SHM = new File("/dev/shm"); + + private File createTempFile() throws IOException { + if (DEV_SHM.exists()) { + return Files.createTempFile(DEV_SHM.toPath(), "gumtree", "").toFile(); + } + return File.createTempFile("gumtree", ""); + } + public abstract String getLanguage(); public String[] getArguments(String file) { + if (IS_UNIX) { + return new String[]{"timeout", "5", SRCML_CMD, "-l", getLanguage(), "--position", file}; + } return new String[]{SRCML_CMD, "-l", getLanguage(), "--position", file}; } + + private static String OS = System.getProperty("os.name").toLowerCase(); + private static boolean IS_UNIX = (OS.contains("nix") || OS.contains("nux") || OS.contains("aix")); }