1 /* 2 * Copyright (c) 2015, 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 /* 25 * @test 26 * @summary Unit test for libjimage JIMAGE_Open/Read/Close 27 * @modules java.base/jdk.internal.jimage 28 * @run testng JImageReadTest 29 */ 30 31 import java.io.File; 32 import java.io.FileWriter; 33 import java.io.IOException; 34 import java.nio.ByteBuffer; 35 import java.nio.ByteOrder; 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 import java.nio.file.Paths; 39 import java.util.Arrays; 40 41 import jdk.internal.jimage.BasicImageReader; 42 import jdk.internal.jimage.ImageReader; 43 import jdk.internal.jimage.ImageLocation; 44 45 import org.testng.annotations.DataProvider; 46 import org.testng.annotations.Optional; 47 import org.testng.annotations.Parameters; 48 import org.testng.annotations.Test; 49 import org.testng.Assert; 50 import org.testng.TestNG; 51 52 @Test 53 public class JImageReadTest { 54 55 static String javaHome = System.getProperty("java.home"); 56 static Path imageFile = Paths.get(javaHome, "lib", "modules"); 57 58 @DataProvider(name="classes") loadClasses()59 static Object[][] loadClasses() { 60 return new Object[][] { 61 {"java.base", "java/lang/String.class"}, 62 {"java.base", "java/lang/Object.class"}, 63 {"java.base", "sun/reflect/generics/tree/TypeArgument.class"}, 64 {"java.base", "sun/net/www/content-types.properties"}, 65 {"java.logging", "java/util/logging/Logger.class"}, 66 {"java.base", "java/NOSUCHCLASS/yyy.class"}, // non-existent 67 {"NOSUCHMODULE", "java/lang/Class.class"}, // non-existent 68 }; 69 } 70 71 /** 72 * Test a class is correctly accessible from the image in a module. 73 * 74 * @param moduleName the module name 75 * @param className the classname 76 * @throws Exception is thrown if there is a test error 77 */ 78 @Test(dataProvider="classes") test1_ReadClasses(String moduleName, String className)79 public static void test1_ReadClasses(String moduleName, String className) throws Exception { 80 final int classMagic = 0xCAFEBABE; 81 82 if (!Files.exists(imageFile)) { 83 System.out.printf("Test skipped; no jimage file"); 84 return; 85 } 86 87 BasicImageReader reader = BasicImageReader.open(imageFile); 88 Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile); 89 90 ImageLocation location = reader.findLocation(moduleName, className); 91 92 if (location != null && !location.verify("/" + moduleName + "/" + className)) { 93 location = null; 94 } 95 96 long size = location != null ? location.getUncompressedSize() : 0; 97 98 System.out.printf("reading: module: %s, path: %s, size: %d%n", 99 moduleName, className, size); 100 if (moduleName.contains("NOSUCH") || className.contains("NOSUCH")) { 101 Assert.assertTrue(location == null, 102 "location found for non-existing module: " 103 + moduleName 104 + ", or class: " + className); 105 return; // no more to test for non-existing class 106 } else { 107 Assert.assertTrue(location != null, "location not found: " + className); 108 Assert.assertTrue(size > 0, "size of should be > 0: " + className); 109 } 110 111 // positive: read whole class 112 ByteBuffer buffer = reader.getResourceBuffer(location); 113 Assert.assertTrue(buffer != null, "bytes read not equal bytes requested"); 114 115 if (className.endsWith(".class")) { 116 int m = buffer.getInt(); 117 Assert.assertEquals(m, classMagic, "Classfile has bad magic number"); 118 } 119 120 reader.close(); 121 } 122 123 /** 124 * For all the resource names, check the name and approximate count. 125 * 126 * @throws IOException thrown if an error occurs 127 */ 128 @Test test2_ImageResources()129 static void test2_ImageResources() throws IOException { 130 if (!Files.exists(imageFile)) { 131 System.out.printf("Test skipped; no jimage file"); 132 return; 133 } 134 135 BasicImageReader reader = BasicImageReader.open(imageFile); 136 Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile); 137 138 String[] names = reader.getEntryNames(); 139 140 // Repeat with count available 141 int count = names.length; 142 143 System.out.printf(" count: %d, a class: %s\n", count, names[0]); 144 145 int minEntryCount = 16000; 146 Assert.assertTrue(minEntryCount < count, 147 "unexpected count of entries, count: " + count 148 + ", min: " + minEntryCount); 149 for (int i = 0; i < count; i++) { 150 checkFullName(names[i]); 151 } 152 153 reader.close(); 154 } 155 156 static void checkFullName(String path) { 157 if (path.startsWith("/packages") || path.startsWith("/modules")) { 158 return; 159 } 160 161 int next = 0; 162 String m = null; 163 String p = null; 164 String b = null; 165 String e = null; 166 if (path.startsWith("/")) { 167 next = path.indexOf('/', 1); 168 m = path.substring(1, next); 169 next = next + 1; 170 } 171 int lastSlash = path.lastIndexOf('/'); 172 if (lastSlash > next) { 173 // has a parent 174 p = path.substring(next, lastSlash); 175 next = lastSlash + 1; 176 } 177 int period = path.indexOf('.', next); 178 if (period > next) { 179 b = path.substring(next, period); 180 e = path.substring(period + 1); 181 } else { 182 b = path.substring(next); 183 } 184 Assert.assertNotNull(m, "module must be non-empty"); 185 Assert.assertNotNull(b, "base name must be non-empty"); 186 } 187 188 /** 189 * Verify that all of the resource names from BasicImageReader 190 * match those returned from the native JIMAGE_Resources iterator. 191 * Names that start with /modules, /packages, and bootmodules.jdata 192 * must appear in the names from JIMAGE_Resource iterator; 193 * from the BasicImageReader they are ignored. 194 */ 195 @Test test3_verifyNames()196 static void test3_verifyNames() { 197 if (!Files.exists(imageFile)) { 198 System.out.printf("Test skipped; no jimage file"); 199 return; 200 } 201 202 try { 203 String[] names = BasicImageReader_Names(); 204 //writeNames("/tmp/basic-names.txt", names); // debug 205 206 // Read all the names from the native JIMAGE API 207 String[] nativeNames = JIMAGE_Names(); 208 //writeNames("/tmp/native-names.txt", nativeNames); // debug 209 210 211 int modCount = 0; 212 int pkgCount = 0; 213 int otherCount = 0; 214 for (String n : nativeNames) { 215 if (n.startsWith("/modules/")) { 216 modCount++; 217 } else if (n.startsWith("/packages/")) { 218 pkgCount++; 219 } else { 220 otherCount++; 221 } 222 } 223 System.out.printf("native name count: %d, modCount: %d, pkgCount: %d, otherCount: %d%n", 224 names.length, modCount, pkgCount, otherCount); 225 226 // Sort and merge the two arrays. Every name should appear exactly twice. 227 Arrays.sort(names); 228 Arrays.sort(nativeNames); 229 String[] combined = Arrays.copyOf(names, nativeNames.length + names.length); 230 System.arraycopy(nativeNames,0, combined, names.length, nativeNames.length); 231 Arrays.sort(combined); 232 int missing = 0; 233 for (int i = 0; i < combined.length; i++) { 234 String s = combined[i]; 235 if (isMetaName(s)) { 236 // Ignore /modules and /packages in BasicImageReader names 237 continue; 238 } 239 240 if (i < combined.length - 1 && s.equals(combined[i + 1])) { 241 i++; // string appears in both java and native 242 continue; 243 } 244 245 missing++; 246 int ndx = Arrays.binarySearch(names, s); 247 String which = (ndx >= 0) ? "java BasicImageReader" : "native JIMAGE_Resources"; 248 System.out.printf("Missing Resource: %s found only via %s%n", s, which); 249 } 250 Assert.assertEquals(missing, 0, "Resources missing"); 251 252 } catch (IOException ioe) { 253 Assert.fail("I/O exception", ioe); 254 } 255 } 256 257 /** 258 * Return true if the name is one of the meta-data names 259 * @param name a name 260 * @return return true if starts with either /packages or /modules 261 */ isMetaName(String name)262 static boolean isMetaName(String name) { 263 return name.startsWith("/modules") 264 || name.startsWith("/packages") 265 || name.startsWith("META-INF") 266 || name.equals("bootmodules.jdata"); 267 } 268 269 /** 270 * Return all of the names from BasicImageReader. 271 * @return the names returned from BasicImageReader 272 */ BasicImageReader_Names()273 static String[] BasicImageReader_Names() throws IOException { 274 String[] names = null; 275 try (BasicImageReader reader = BasicImageReader.open(imageFile)) { 276 names = reader.getEntryNames(); 277 } catch (IOException ioe) { 278 Assert.fail("I/O exception", ioe); 279 } 280 return names; 281 } 282 283 /** 284 * Returns an array of all of the names returned from JIMAGE_Resources 285 */ JIMAGE_Names()286 static String[] JIMAGE_Names() throws IOException { 287 288 BasicImageReader reader = BasicImageReader.open(imageFile); 289 Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile); 290 291 String[] names = reader.getEntryNames(); 292 293 reader.close(); 294 295 return names; 296 } 297 298 // Write an array of names to a file for debugging writeNames(String fname, String[] names)299 static void writeNames(String fname, String[] names) throws IOException { 300 try (FileWriter wr = new FileWriter(new File(fname))) { 301 for (String s : names) { 302 wr.write(s); 303 wr.write("\n"); 304 } 305 306 } 307 System.out.printf(" %s: %d names%n", fname, names.length); 308 } 309 310 //@Test test4_nameTooLong()311 static void test4_nameTooLong() throws IOException { 312 long[] size = new long[1]; 313 String moduleName = "FictiousModuleName"; 314 String className = String.format("A%09999d", 1); 315 316 BasicImageReader reader = BasicImageReader.open(imageFile); 317 Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile); 318 319 String name = "/" + moduleName + "/" + className; 320 ImageLocation location = reader.findLocation(name); 321 322 if (location != null && !location.verify(name)) { 323 location = null; 324 } 325 Assert.assertTrue(location == null, "Too long name should have failed"); 326 327 reader.close(); 328 } 329 330 /** 331 * Verify that the ImageReader returned by ImageReader.open has the 332 * the requested endianness or fails with an IOException if not. 333 */ 334 @Test test5_imageReaderEndianness()335 static void test5_imageReaderEndianness() throws IOException { 336 ImageReader nativeReader = ImageReader.open(imageFile); 337 Assert.assertEquals(nativeReader.getByteOrder(), ByteOrder.nativeOrder()); 338 339 try { 340 ImageReader leReader = ImageReader.open(imageFile, ByteOrder.LITTLE_ENDIAN); 341 Assert.assertEquals(leReader.getByteOrder(), ByteOrder.LITTLE_ENDIAN); 342 leReader.close(); 343 } catch (IOException io) { 344 // IOException expected if LITTLE_ENDIAN not the nativeOrder() 345 Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.LITTLE_ENDIAN); 346 } 347 348 try { 349 ImageReader beReader = ImageReader.open(imageFile, ByteOrder.BIG_ENDIAN); 350 Assert.assertEquals(beReader.getByteOrder(), ByteOrder.BIG_ENDIAN); 351 beReader.close(); 352 } catch (IOException io) { 353 // IOException expected if LITTLE_ENDIAN not the nativeOrder() 354 Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.BIG_ENDIAN); 355 } 356 357 nativeReader.close(); 358 } 359 // main method to run standalone from jtreg 360 361 @Test(enabled=false) 362 @Parameters({"x"}) 363 @SuppressWarnings("raw_types") main(@ptional String[] args)364 public static void main(@Optional String[] args) { 365 Class<?>[] testclass = { JImageReadTest.class}; 366 TestNG testng = new TestNG(); 367 testng.setTestClasses(testclass); 368 testng.run(); 369 } 370 371 } 372