1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.nio.file.FileVisitResult; 27 import java.nio.file.Files; 28 import java.nio.file.Path; 29 import java.nio.file.Paths; 30 import java.nio.file.SimpleFileVisitor; 31 import java.nio.file.attribute.BasicFileAttributes; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Properties; 35 import java.util.zip.ZipEntry; 36 import java.util.zip.ZipInputStream; 37 38 /* 39 * @test 40 * @bug 8226346 41 * @summary Check all output files for absolute path fragments 42 * @requires !vm.debug 43 * @run main AbsPathsInImage 44 */ 45 public class AbsPathsInImage { 46 47 // Set this property on command line to scan an alternate dir or file: 48 // JTREG=JAVA_OPTIONS=-Djdk.test.build.AbsPathInImage.dir=/path/to/dir 49 public static final String DIR_PROPERTY = "jdk.test.build.AbsPathsInImage.dir"; 50 51 private boolean matchFound = false; 52 53 public static void main(String[] args) throws Exception { 54 String jdkPathString = System.getProperty("test.jdk"); 55 Path jdkHome = Paths.get(jdkPathString); 56 57 Path dirToScan = jdkHome; 58 String overrideDir = System.getProperty(DIR_PROPERTY); 59 if (overrideDir != null) { 60 dirToScan = Paths.get(overrideDir); 61 } 62 63 String buildWorkspaceRoot = null; 64 String buildOutputRoot = null; 65 String testImageDirString = System.getenv("TEST_IMAGE_DIR"); 66 if (testImageDirString != null) { 67 Path testImageDir = Paths.get(testImageDirString); 68 Path buildInfoPropertiesFile = testImageDir.resolve("build-info.properties"); 69 System.out.println("Getting patterns from " + buildInfoPropertiesFile.toString()); 70 Properties buildInfoProperties = new Properties(); 71 try (InputStream inStream = Files.newInputStream(buildInfoPropertiesFile)) { 72 buildInfoProperties.load(inStream); 73 } 74 buildWorkspaceRoot = buildInfoProperties.getProperty("build.workspace.root"); 75 buildOutputRoot = buildInfoProperties.getProperty("build.output.root"); 76 } else { 77 System.out.println("Getting patterns from local environment"); 78 // Try to resolve the workspace root based on the jtreg test root dir 79 String testRootDirString = System.getProperty("test.root"); 80 if (testRootDirString != null) { 81 Path testRootDir = Paths.get(testRootDirString); 82 // Remove /test/jdk suffix 83 buildWorkspaceRoot = testRootDir.getParent().getParent().toString(); 84 } 85 // Remove /jdk 86 Path buildOutputRootPath = jdkHome.getParent(); 87 if (buildOutputRootPath.endsWith("images")) { 88 buildOutputRootPath = buildOutputRootPath.getParent(); 89 } 90 buildOutputRoot = buildOutputRootPath.toString(); 91 } 92 if (buildWorkspaceRoot == null) { 93 throw new Error("Could not find workspace root, test cannot run"); 94 } 95 if (buildOutputRoot == null) { 96 throw new Error("Could not find build output root, test cannot run"); 97 } 98 99 List<byte[]> searchPatterns = new ArrayList<>(); 100 expandPatterns(searchPatterns, buildWorkspaceRoot); 101 expandPatterns(searchPatterns, buildOutputRoot); 102 103 System.out.println("Looking for:"); 104 for (byte[] searchPattern : searchPatterns) { 105 System.out.println(new String(searchPattern)); 106 } 107 System.out.println(); 108 109 AbsPathsInImage absPathsInImage = new AbsPathsInImage(); 110 absPathsInImage.scanFiles(dirToScan, searchPatterns); 111 112 if (absPathsInImage.matchFound) { 113 throw new Exception("Test failed"); 114 } 115 } 116 117 /** 118 * Add path pattern to list of patterns to search for. Create all possible 119 * variants depending on platform. 120 */ 121 private static void expandPatterns(List<byte[]> searchPatterns, String pattern) { 122 if (System.getProperty("os.name").toLowerCase().contains("windows")) { 123 String forward = pattern.replace('\\', '/'); 124 String back = pattern.replace('/', '\\'); 125 if (pattern.charAt(1) == ':') { 126 String forwardUpper = String.valueOf(pattern.charAt(0)).toUpperCase() + forward.substring(1); 127 String forwardLower = String.valueOf(pattern.charAt(0)).toLowerCase() + forward.substring(1); 128 String backUpper = String.valueOf(pattern.charAt(0)).toUpperCase() + back.substring(1); 129 String backLower = String.valueOf(pattern.charAt(0)).toLowerCase() + back.substring(1); 130 searchPatterns.add(forwardUpper.getBytes()); 131 searchPatterns.add(forwardLower.getBytes()); 132 searchPatterns.add(backUpper.getBytes()); 133 searchPatterns.add(backLower.getBytes()); 134 } else { 135 searchPatterns.add(forward.getBytes()); 136 searchPatterns.add(back.getBytes()); 137 } 138 } else { 139 searchPatterns.add(pattern.getBytes()); 140 } 141 } 142 143 private void scanFiles(Path root, List<byte[]> searchPatterns) throws IOException { 144 Files.walkFileTree(root, new SimpleFileVisitor<>() { 145 @Override 146 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 147 String fileName = file.toString(); 148 if (Files.isSymbolicLink(file)) { 149 return super.visitFile(file, attrs); 150 } else if (fileName.endsWith(".debuginfo") || fileName.endsWith(".pdb")) { 151 // Do nothing 152 } else if (fileName.endsWith("jvm.dll")) { 153 // On Windows, the Microsoft toolchain does not provide a way 154 // to reliably remove all absolute paths from __FILE__ usage. 155 // Until that is fixed, we simply exclude jvm.dll from this 156 // test. 157 } else if (fileName.endsWith(".zip")) { 158 scanZipFile(file, searchPatterns); 159 } else { 160 scanFile(file, searchPatterns); 161 } 162 return super.visitFile(file, attrs); 163 } 164 }); 165 } 166 167 private void scanFile(Path file, List<byte[]> searchPatterns) throws IOException { 168 List<String> matches = scanBytes(Files.readAllBytes(file), searchPatterns); 169 if (matches.size() > 0) { 170 System.out.println(file + ":"); 171 for (String match : matches) { 172 System.out.println(match); 173 } 174 System.out.println(); 175 } 176 } 177 178 private void scanZipFile(Path zipFile, List<byte[]> searchPatterns) throws IOException { 179 try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(zipFile))) { 180 ZipEntry zipEntry; 181 while ((zipEntry = zipInputStream.getNextEntry()) != null) { 182 List<String> matches = scanBytes(zipInputStream.readAllBytes(), searchPatterns); 183 if (matches.size() > 0) { 184 System.out.println(zipFile + ", " + zipEntry.getName() + ":"); 185 for (String match : matches) { 186 System.out.println(match); 187 } 188 System.out.println(); 189 } 190 } 191 } 192 } 193 194 private List<String> scanBytes(byte[] data, List<byte[]> searchPatterns) { 195 List<String> matches = new ArrayList<>(); 196 for (int i = 0; i < data.length; i++) { 197 for (byte[] searchPattern : searchPatterns) { 198 boolean found = true; 199 for (int j = 0; j < searchPattern.length; j++) { 200 if ((i + j > data.length || data[i + j] != searchPattern[j])) { 201 found = false; 202 break; 203 } 204 } 205 if (found) { 206 matchFound = true; 207 matches.add(new String(data, charsStart(data, i), charsOffset(data, i, searchPattern.length))); 208 // No need to search the same string for multiple patterns 209 break; 210 } 211 } 212 } 213 return matches; 214 } 215 216 private int charsStart(byte[] data, int startIndex) { 217 int index = startIndex; 218 while (--index > 0) { 219 byte datum = data[index]; 220 if (datum < 32 || datum > 126) { 221 break; 222 } 223 } 224 return index + 1; 225 } 226 227 private int charsOffset(byte[] data, int startIndex, int startOffset) { 228 int offset = startOffset; 229 while (startIndex + ++offset < data.length) { 230 byte datum = data[startIndex + offset]; 231 if (datum < 32 || datum > 126) { 232 break; 233 } 234 } 235 return offset; 236 } 237 }