From b14804bfdc3eb5054d85c398a922601dc6c2edf5 Mon Sep 17 00:00:00 2001 From: Ben Liblit Date: Mon, 2 Apr 2018 14:23:13 -0500 Subject: [PATCH] Don't put fixed-name, writable files into "java.io.tmpdir" If multiple tests both write to "/tmp/cg.txt" (for example), then these tests cannot safely run concurrently. That never used to be a problem with Maven, since our Maven tests were all strictly sequential anyway. But parallelized testing using Gradle requires that we do better. Fortunately, Java has perfectly reasonable APIs for generating uniquely-named temporary files and directories. --- .../js/nodejs/NodejsRequiredCoreModule.java | 4 +- .../shrike/DynamicCallGraphTestBase.java | 37 ++++++++++++------- .../dalvik/classLoader/DexFileModule.java | 5 ++- .../shrike/instrumentation/CodeScraper.java | 19 ++++++---- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/com.ibm.wala.cast.js.nodejs/src/com/ibm/wala/cast/js/nodejs/NodejsRequiredCoreModule.java b/com.ibm.wala.cast.js.nodejs/src/com/ibm/wala/cast/js/nodejs/NodejsRequiredCoreModule.java index 2b8326013..c77b67a23 100644 --- a/com.ibm.wala.cast.js.nodejs/src/com/ibm/wala/cast/js/nodejs/NodejsRequiredCoreModule.java +++ b/com.ibm.wala.cast.js.nodejs/src/com/ibm/wala/cast/js/nodejs/NodejsRequiredCoreModule.java @@ -13,6 +13,7 @@ package com.ibm.wala.cast.js.nodejs; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; import java.util.Arrays; import java.util.Set; @@ -52,7 +53,8 @@ public class NodejsRequiredCoreModule extends NodejsRequiredSourceModule { } public static NodejsRequiredCoreModule make(String name) throws IOException { - File file = new File(System.getProperty("java.io.tmpdir"), name+".js"); + File file = Files.createTempFile(name, ".js").toFile(); + file.deleteOnExit(); TemporaryFile.streamToFile(file, getModule(name)); SourceFileModule sourceFileModule = CAstCallGraphUtil.makeSourceModule(file.toURI().toURL(), file.getName()); return new NodejsRequiredCoreModule(file, sourceFileModule); diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTestBase.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTestBase.java index 2a9807a83..8635d5173 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTestBase.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTestBase.java @@ -13,9 +13,9 @@ package com.ibm.wala.core.tests.shrike; import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -65,17 +65,26 @@ public abstract class DynamicCallGraphTestBase extends WalaTestCase { private boolean instrumentedJarBuilt = false; - private String instrumentedJarLocation = System.getProperty("java.io.tmpdir") + File.separator + "test.jar"; + private java.nio.file.Path instrumentedJarLocation; - private String cgLocation = System.getProperty("java.io.tmpdir") + File.separator + "cg.txt"; + private java.nio.file.Path cgLocation; + + protected DynamicCallGraphTestBase() { + try { + instrumentedJarLocation = Files.createTempFile("wala-test", ".jar"); + instrumentedJarLocation.toFile().deleteOnExit(); + cgLocation = Files.createTempFile("cg", ".txt"); + cgLocation.toFile().deleteOnExit(); + } catch (IOException problem) { + throw new RuntimeException(problem); + } + } protected void instrument(String testJarLocation) throws IOException, ClassNotFoundException, InvalidClassFileException, FailureException { if (! instrumentedJarBuilt) { System.err.println("core data jar to instrument: " + testJarLocation); - if (new File(instrumentedJarLocation).exists()) { - assert new File(instrumentedJarLocation).delete(); - } + Files.deleteIfExists(instrumentedJarLocation); String rtJar = null; for(String jar : WalaProperties.getJ2SEJarFiles()) { @@ -85,7 +94,7 @@ public abstract class DynamicCallGraphTestBase extends WalaTestCase { } List args = new ArrayList<>(); - args.addAll(Arrays.asList(testJarLocation, "-o", instrumentedJarLocation)); + args.addAll(Arrays.asList(testJarLocation, "-o", instrumentedJarLocation.toString())); if (rtJar != null) { args.addAll(Arrays.asList("--rt-jar", rtJar)); } @@ -93,14 +102,16 @@ public abstract class DynamicCallGraphTestBase extends WalaTestCase { args.add("--patch-calls"); } OfflineDynamicCallGraph.main(args.toArray(new String[ args.size() ])); - Assert.assertTrue("expected to create /tmp/test.jar", new File(instrumentedJarLocation).exists()); + Assert.assertTrue("expected to create " + instrumentedJarLocation, Files.exists(instrumentedJarLocation)); instrumentedJarBuilt = true; } } protected void run(String mainClass, String exclusionsFile, String... args) throws IOException, SecurityException, IllegalArgumentException, InterruptedException { Project p = new Project(); - p.setBaseDir(new File(System.getProperty("java.io.tmpdir"))); + final File projectDir = Files.createTempDirectory("wala-test").toFile(); + projectDir.deleteOnExit(); + p.setBaseDir(projectDir); p.init(); p.fireBuildStarted(); @@ -125,9 +136,7 @@ public abstract class DynamicCallGraphTestBase extends WalaTestCase { childJvm.setFailonerror(true); childJvm.setFork(true); - if (new File(cgLocation).exists()) { - new File(cgLocation).delete(); - } + Files.deleteIfExists(cgLocation); childJvm.init(); String commandLine = childJvm.getCommandLine().toString(); @@ -135,7 +144,7 @@ public abstract class DynamicCallGraphTestBase extends WalaTestCase { Process x = Runtime.getRuntime().exec(commandLine); x.waitFor(); - Assert.assertTrue("expected to create call graph", new File(cgLocation).exists()); + Assert.assertTrue("expected to create call graph", Files.exists(cgLocation)); } interface EdgesTest { @@ -186,7 +195,7 @@ public abstract class DynamicCallGraphTestBase extends WalaTestCase { protected void check(CallGraph staticCG, EdgesTest test, Predicate filter) throws IOException { int lines = 0; - try (final BufferedReader dynamicEdgesFile = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(cgLocation))))) { + try (final BufferedReader dynamicEdgesFile = new BufferedReader(new InputStreamReader(new GZIPInputStream(Files.newInputStream(cgLocation))))) { String line; loop: while ((line = dynamicEdgesFile.readLine()) != null) { if (line.startsWith("call to") || line.startsWith("return from")) { diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java index 42e294fd5..c20383b3d 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java @@ -49,6 +49,7 @@ package com.ibm.wala.dalvik.classLoader; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -83,12 +84,12 @@ public class DexFileModule implements Module { } } - private static File tf(JarFile f) { + private static File tf(JarFile f) throws IOException { String name = f.getName(); if (name.indexOf('/') >= 0) { name = name.substring(name.lastIndexOf('/')+1); } - File tf = new File(System.getProperty("java.io.tmpdir") + "/" + name + "_classes.dex"); + File tf = Files.createTempFile("name", "_classes.dex").toFile(); tf.deleteOnExit(); System.err.println("using " + tf); return tf; diff --git a/com.ibm.wala.shrike/src/com/ibm/wala/shrike/instrumentation/CodeScraper.java b/com.ibm.wala.shrike/src/com/ibm/wala/shrike/instrumentation/CodeScraper.java index 9a57d792f..7dfbe1dc8 100644 --- a/com.ibm.wala.shrike/src/com/ibm/wala/shrike/instrumentation/CodeScraper.java +++ b/com.ibm.wala.shrike/src/com/ibm/wala/shrike/instrumentation/CodeScraper.java @@ -1,11 +1,12 @@ package com.ibm.wala.shrike.instrumentation; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.ProtectionDomain; import com.ibm.wala.shrikeCT.ClassReader; @@ -15,11 +16,16 @@ import com.ibm.wala.shrikeCT.SourceFileReader; public class CodeScraper implements ClassFileTransformer { - private static final String prefix = System.getProperty("java.io.tmpdir") + File.separator + "loggedClasses" + File.separator + System.currentTimeMillis(); + private static final Path prefix; static { + try { + prefix = Files.createTempDirectory("loggedClasses"); + prefix.toFile().deleteOnExit(); + } catch (final IOException problem) { + throw new RuntimeException(problem); + } System.err.println("scraping to " + prefix); - (new File(prefix)).mkdirs(); } @Override @@ -38,9 +44,8 @@ public class CodeScraper implements ClassFileTransformer { } } if (className == null || sourceFile == null || !sourceFile.endsWith("java") || true) try { - String log = prefix + File.separator + reader.getName() + ".class"; - (new File(log)).getParentFile().mkdirs(); - try (final FileOutputStream f = new FileOutputStream(log)) { + Path log = prefix.resolve(reader.getName() + ".class"); + try (final OutputStream f = Files.newOutputStream(log)) { f.write(classfileBuffer); } } catch (IOException e) {