1 /* 2 * Copyright (c) 2008, 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 6622260 27 * @summary javap prints negative bytes incorrectly in hex 28 * @modules jdk.compiler 29 */ 30 31 import java.io.*; 32 33 public class T6622260 { 34 public static void main(String[] args) throws Exception { 35 new T6622260().run(); 36 } 37 38 public void run() throws IOException { 39 File javaFile = writeTestFile(); 40 File classFile = compileTestFile(javaFile); 41 modifyClassFile(classFile); 42 String output = javap(classFile); 43 verify(output); 44 } 45 46 File writeTestFile() throws IOException { 47 File f = new File("Test.java"); 48 PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f))); 49 out.println("@Deprecated class Test { int f; void m() { } }"); 50 out.close(); 51 return f; 52 } 53 54 File compileTestFile(File f) { 55 int rc = com.sun.tools.javac.Main.compile(new String[] { f.getPath() }); 56 if (rc != 0) 57 throw new Error("compilation failed. rc=" + rc); 58 String path = f.getPath(); 59 return new File(path.substring(0, path.length() - 5) + ".class"); 60 } 61 62 void modifyClassFile(File f) throws IOException { 63 String newAttributeName = "NonstandardAttribute"; 64 byte[] newAttributeData = { 0, 1, 2, 127, (byte)128, (byte)129, (byte)254, (byte)255 }; 65 66 DataInputStream in = new DataInputStream(new FileInputStream(f)); 67 byte[] data = new byte[(int) f.length()]; 68 in.readFully(data); 69 in.close(); 70 71 in = new DataInputStream(new ByteArrayInputStream(data)); 72 in.skipBytes(4); // magic 73 in.skipBytes(2); // minor 74 in.skipBytes(2); // minor 75 76 int constantPoolPos = data.length - in.available(); 77 int constant_pool_count = skipConstantPool(in); 78 79 int flagsPos = data.length - in.available(); 80 in.skipBytes(2); // access_flags 81 in.skipBytes(2); // this_class 82 in.skipBytes(2); // super_class 83 84 int interfaces_count = in.readUnsignedShort(); 85 in.skipBytes(interfaces_count * 2); 86 87 int field_count = in.readUnsignedShort(); 88 for (int i = 0; i < field_count; i++) { 89 in.skipBytes(6); // access_flags, name_index, descriptor_index 90 skipAttributes(in); 91 } 92 93 int method_count = in.readUnsignedShort(); 94 for (int i = 0; i < method_count; i++) { 95 in.skipBytes(6); // access_flags, name_index, descriptor_index 96 skipAttributes(in); 97 } 98 99 int classAttributesPos = data.length - in.available(); 100 int attributes_count = in.readUnsignedShort(); 101 102 f.renameTo(new File(f.getPath() + ".BAK")); 103 DataOutputStream out = new DataOutputStream(new FileOutputStream(f)); 104 105 // copy head 106 out.write(data, 0, constantPoolPos); 107 108 // copy constant pool, adding in name of new attribute 109 out.writeShort(constant_pool_count + 1); 110 out.write(data, constantPoolPos + 2, flagsPos - constantPoolPos - 2); 111 out.write(1); // CONSTANT_Utf8 112 out.writeUTF(newAttributeName); 113 114 // copy flags, class, superclass, interfaces, fields and methods 115 out.write(data, flagsPos, classAttributesPos - flagsPos); 116 117 // copy class attributes, adding in new attribute 118 out.writeShort(attributes_count + 1); 119 out.write(data, classAttributesPos + 2, data.length - classAttributesPos - 2); 120 out.writeShort(constant_pool_count); // index of new attribute name 121 out.writeInt(newAttributeData.length); 122 out.write(newAttributeData); 123 out.close(); 124 } 125 126 int skipConstantPool(DataInputStream in) throws IOException { 127 int constant_pool_count = in.readUnsignedShort(); 128 for (int i = 1; i < constant_pool_count; i++) { 129 int tag = in.readUnsignedByte(); 130 switch (tag) { 131 case 1: // CONSTANT_Utf8 132 int length = in.readUnsignedShort(); 133 in.skipBytes(length); // bytes 134 break; 135 136 case 3: // CONSTANT_Integer 137 case 4: // CONSTANT_Float 138 in.skipBytes(4); // bytes 139 break; 140 141 case 5: // CONSTANT_Long 142 case 6: // CONSTANT_Double 143 in.skipBytes(8); // high_bytes, low_bytes 144 break; 145 146 case 7: // CONSTANT_Class 147 in.skipBytes(2); // name_index 148 break; 149 150 case 8: // CONSTANT_String 151 in.skipBytes(2); // string_index 152 break; 153 154 case 9: // CONSTANT_FieldRef 155 case 10: // CONSTANT_Methodref 156 case 11: // CONSTANT_InterfaceMethodref 157 in.skipBytes(4); // class_index, name_and_type_index 158 break; 159 160 case 12: // CONSTANT_NameAndType 161 in.skipBytes(4); // name_index, descriptor_index 162 break; 163 164 default: 165 throw new Error("constant pool tag: " + tag); 166 } 167 } 168 return constant_pool_count; 169 } 170 171 int skipAttributes(DataInputStream in) throws IOException { 172 int attributes_count = in.readUnsignedShort(); 173 for (int i = 0; i < attributes_count; i++) { 174 in.skipBytes(2); // attribute_name_index; 175 int length = in.readInt(); 176 in.skipBytes(length); // info 177 } 178 return attributes_count; 179 } 180 181 String javap(File f) { 182 StringWriter sw = new StringWriter(); 183 PrintWriter out = new PrintWriter(sw); 184 int rc = com.sun.tools.javap.Main.run(new String[] { "-v", f.getPath() }, out); 185 if (rc != 0) 186 throw new Error("javap failed. rc=" + rc); 187 out.close(); 188 return sw.toString(); 189 } 190 191 void verify(String output) { 192 System.out.println(output); 193 output = output.substring(output.indexOf("Test.java")); 194 if (output.indexOf("-") >= 0) 195 throw new Error("- found in output"); 196 if (output.indexOf("FFFFFF") >= 0) 197 throw new Error("FFFFFF found in output"); 198 } 199 }