1 /* 2 * Copyright (c) 2014, 2015, 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 * @bug 8047072 27 * @summary javap OOM on fuzzed classfile 28 * @modules jdk.jdeps 29 * @run main BadAttributeLength 30 */ 31 32 33 import java.io.*; 34 35 public class BadAttributeLength { 36 37 public static String source = "public class Test {\n" + 38 " public static void main(String[] args) {}\n" + 39 "}"; 40 41 public static void main(String[] args) throws Exception { 42 final File sourceFile = new File("Test.java"); 43 if (sourceFile.exists()) { 44 if (!sourceFile.delete()) { 45 throw new IOException("Can't override the Test.java file. " + 46 "Check permissions."); 47 } 48 } 49 try (FileWriter fw = new FileWriter(sourceFile)) { 50 fw.write(source); 51 } 52 53 final String[] javacOpts = {"Test.java"}; 54 55 if (com.sun.tools.javac.Main.compile(javacOpts) != 0) { 56 throw new Exception("Can't compile embedded test."); 57 } 58 59 RandomAccessFile raf = new RandomAccessFile("Test.class", "rw"); 60 long attPos = getFirstAttributePos(raf); 61 if (attPos < 0) { 62 throw new Exception("The class file contains no attributes at all."); 63 } 64 raf.seek(attPos + 2); // Jump to the attribute length 65 raf.writeInt(Integer.MAX_VALUE - 1); 66 raf.close(); 67 68 String[] opts = { "-v", "Test.class" }; 69 StringWriter sw = new StringWriter(); 70 PrintWriter pout = new PrintWriter(sw); 71 72 com.sun.tools.javap.Main.run(opts, pout); 73 pout.flush(); 74 75 if (sw.getBuffer().indexOf("OutOfMemoryError") != -1) { 76 throw new Exception("javap exited with OutOfMemoryError " + 77 "instead of giving the proper error message."); 78 } 79 } 80 81 private static long getFirstAttributePos(RandomAccessFile cfile) throws Exception { 82 cfile.seek(0); 83 int v1, v2; 84 v1 = cfile.readInt(); 85 // System.out.println("Magic: " + String.format("%X", v1)); 86 87 v1 = cfile.readUnsignedShort(); 88 v2 = cfile.readUnsignedShort(); 89 // System.out.println("Version: " + String.format("%d.%d", v1, v2)); 90 91 v1 = cfile.readUnsignedShort(); 92 // System.out.println("CPool size: " + v1); 93 // Exhaust the constant pool 94 for (; v1 > 1; v1--) { 95 // System.out.print("."); 96 byte tag = cfile.readByte(); 97 switch (tag) { 98 case 7 : // Class 99 case 8 : // String 100 // Data is 2 bytes long 101 cfile.skipBytes(2); 102 break; 103 case 3 : // Integer 104 case 4 : // Float 105 case 9 : // FieldRef 106 case 10 : // MethodRef 107 case 11 : // InterfaceMethodRef 108 case 12 : // Name and Type 109 // Data is 4 bytes long 110 cfile.skipBytes(4); 111 break; 112 case 5 : // Long 113 case 6 : // Double 114 // Data is 8 bytes long 115 cfile.skipBytes(8); 116 break; 117 case 1 : // Utf8 118 v2 = cfile.readUnsignedShort(); // Read buffer size 119 cfile.skipBytes(v2); // Skip buffer 120 break; 121 default : 122 throw new Exception("Unexpected tag in CPool: [" + tag + "] at " 123 + Long.toHexString(cfile.getFilePointer())); 124 } 125 } 126 // System.out.println(); 127 128 cfile.skipBytes(6); // Access flags, this_class and super_class 129 v1 = cfile.readUnsignedShort(); // Number of interfaces 130 // System.out.println("Interfaces: " + v1); 131 cfile.skipBytes(3 * v1); // Each interface_info record is 3 bytes long 132 v1 = cfile.readUnsignedShort(); // Number of fields 133 // System.out.println("Fields: " + v1); 134 // Exhaust the fields table 135 for (; v1 > 0; v1--) { 136 // System.out.print("."); 137 cfile.skipBytes(6); // Skip access_flags, name_index and descriptor_index 138 v2 = cfile.readUnsignedShort(); // Field attributes count 139 if (v2 > 0) { 140 // This field has some attributes - suits our needs 141 // System.out.println(); 142 return cfile.getFilePointer(); 143 } 144 } 145 // System.out.println(); 146 v1 = cfile.readUnsignedShort(); // Number of methods 147 // System.out.println("Methods: " + v1); 148 // Exhaust the methods table 149 for (; v1 > 0; v1--) { 150 // System.out.print("."); 151 cfile.skipBytes(6); // Skip access_flags, name_index and descriptor_index 152 v2 = cfile.readUnsignedShort(); // Method attributes count 153 if (v2 > 0) { 154 // This method got attributes - Ok with us, 155 // return position of the first one 156 // System.out.println(); 157 return cfile.getFilePointer(); 158 } 159 } 160 // System.out.println(); 161 // Class attributes section 162 v1 = cfile.readUnsignedShort(); // Counts of attributes in class 163 if (v1 > 0) { 164 // Class has some attributes, return position of the first one 165 return cfile.getFilePointer(); 166 } 167 // Bummer! No attributes in the entire class file. Not fair! 168 return -1L; 169 } 170 }