T6622260.java revision 2942:08092deced3f
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.jdeps
29 */
30
31import java.io.*;
32
33public 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}
200