Sat, 18 Dec 2010 09:38:39 -0800
6567415: Neverending loop in ClassReader
Reviewed-by: jjg
src/share/classes/com/sun/tools/javac/jvm/ClassReader.java | file | annotate | diff | comparison | revisions | |
test/tools/javac/6567415/T6567415.java | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Dec 15 06:39:51 2010 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Sat Dec 18 09:38:39 2010 -0800 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -77,6 +77,8 @@ 1.11 protected static final Context.Key<ClassReader> classReaderKey = 1.12 new Context.Key<ClassReader>(); 1.13 1.14 + public static final int INITIAL_BUFFER_SIZE = 0x0fff0; 1.15 + 1.16 Annotate annotate; 1.17 1.18 /** Switch: verbose output. 1.19 @@ -185,7 +187,7 @@ 1.20 1.21 /** The buffer containing the currently read class file. 1.22 */ 1.23 - byte[] buf = new byte[0x0fff0]; 1.24 + byte[] buf = new byte[INITIAL_BUFFER_SIZE]; 1.25 1.26 /** The current input pointer. 1.27 */ 1.28 @@ -2419,8 +2421,14 @@ 1.29 } 1.30 } 1.31 } 1.32 + /* 1.33 + * ensureCapacity will increase the buffer as needed, taking note that 1.34 + * the new buffer will always be greater than the needed and never 1.35 + * exactly equal to the needed size or bp. If equal then the read (above) 1.36 + * will infinitely loop as buf.length - bp == 0. 1.37 + */ 1.38 private static byte[] ensureCapacity(byte[] buf, int needed) { 1.39 - if (buf.length < needed) { 1.40 + if (buf.length <= needed) { 1.41 byte[] old = buf; 1.42 buf = new byte[Integer.highestOneBit(needed) << 1]; 1.43 System.arraycopy(old, 0, buf, 0, old.length);
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/test/tools/javac/6567415/T6567415.java Sat Dec 18 09:38:39 2010 -0800 2.3 @@ -0,0 +1,146 @@ 2.4 +/* 2.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + */ 2.26 + 2.27 +/* 2.28 + * @test 2.29 + * @bug 6567415 2.30 + * @summary Test to ensure javac does not go into an infinite loop, while 2.31 + * reading a classfile of a specific length. 2.32 + * @compile -XDignore.symbol.file T6567415.java 2.33 + * @run main T6567415 2.34 + * @author ksrini 2.35 + */ 2.36 + 2.37 +import java.io.File; 2.38 +import java.io.FileInputStream; 2.39 +import java.io.FileOutputStream; 2.40 +import java.io.IOException; 2.41 +import java.io.PrintStream; 2.42 +import java.io.RandomAccessFile; 2.43 +import java.nio.ByteBuffer; 2.44 +import java.nio.MappedByteBuffer; 2.45 +import java.nio.channels.FileChannel; 2.46 + 2.47 +/* 2.48 + * this test compiles Bar.java into a classfile and enlarges the file to the 2.49 + * magic file length, then use this mutated file on the classpath to compile 2.50 + * Foo.java which references Bar.java and Ka-boom. QED. 2.51 + */ 2.52 +public class T6567415 { 2.53 + final static String TEST_FILE_NAME = "Bar"; 2.54 + final static String TEST_JAVA = TEST_FILE_NAME + ".java"; 2.55 + final static String TEST_CLASS = TEST_FILE_NAME + ".class"; 2.56 + 2.57 + final static String TEST2_FILE_NAME = "Foo"; 2.58 + final static String TEST2_JAVA = TEST2_FILE_NAME + ".java"; 2.59 + 2.60 + /* 2.61 + * the following is the initial buffer length set in ClassReader.java 2.62 + * thus this value needs to change if ClassReader buf length changes. 2.63 + */ 2.64 + 2.65 + final static int BAD_FILE_LENGTH = 2.66 + com.sun.tools.javac.jvm.ClassReader.INITIAL_BUFFER_SIZE; 2.67 + 2.68 + static void createClassFile() throws IOException { 2.69 + FileOutputStream fos = null; 2.70 + try { 2.71 + fos = new FileOutputStream(TEST_JAVA); 2.72 + PrintStream ps = new PrintStream(fos); 2.73 + ps.println("public class " + TEST_FILE_NAME + " {}"); 2.74 + } finally { 2.75 + fos.close(); 2.76 + } 2.77 + String cmds[] = {TEST_JAVA}; 2.78 + com.sun.tools.javac.Main.compile(cmds); 2.79 + } 2.80 + 2.81 + static void enlargeClassFile() throws IOException { 2.82 + File f = new File(TEST_CLASS); 2.83 + if (!f.exists()) { 2.84 + System.out.println("file not found: " + TEST_CLASS); 2.85 + System.exit(1); 2.86 + } 2.87 + File tfile = new File(f.getAbsolutePath() + ".tmp"); 2.88 + f.renameTo(tfile); 2.89 + 2.90 + RandomAccessFile raf = null; 2.91 + FileChannel wfc = null; 2.92 + 2.93 + FileInputStream fis = null; 2.94 + FileChannel rfc = null; 2.95 + 2.96 + try { 2.97 + raf = new RandomAccessFile(f, "rw"); 2.98 + wfc = raf.getChannel(); 2.99 + 2.100 + fis = new FileInputStream(tfile); 2.101 + rfc = fis.getChannel(); 2.102 + 2.103 + ByteBuffer bb = MappedByteBuffer.allocate(BAD_FILE_LENGTH); 2.104 + rfc.read(bb); 2.105 + bb.rewind(); 2.106 + wfc.write(bb); 2.107 + wfc.truncate(BAD_FILE_LENGTH); 2.108 + } finally { 2.109 + wfc.close(); 2.110 + raf.close(); 2.111 + rfc.close(); 2.112 + fis.close(); 2.113 + } 2.114 + System.out.println("file length = " + f.length()); 2.115 + } 2.116 + 2.117 + static void createJavaFile() throws IOException { 2.118 + FileOutputStream fos = null; 2.119 + try { 2.120 + fos = new FileOutputStream(TEST2_JAVA); 2.121 + PrintStream ps = new PrintStream(fos); 2.122 + ps.println("public class " + TEST2_FILE_NAME + 2.123 + " {" + TEST_FILE_NAME + " b = new " + 2.124 + TEST_FILE_NAME + " ();}"); 2.125 + } finally { 2.126 + fos.close(); 2.127 + } 2.128 + } 2.129 + 2.130 + public static void main(String... args) throws Exception { 2.131 + createClassFile(); 2.132 + enlargeClassFile(); 2.133 + createJavaFile(); 2.134 + Thread t = new Thread () { 2.135 + @Override 2.136 + public void run() { 2.137 + String cmds[] = {"-verbose", "-cp", ".", TEST2_JAVA}; 2.138 + int ret = com.sun.tools.javac.Main.compile(cmds); 2.139 + System.out.println("test compilation returns: " + ret); 2.140 + } 2.141 + }; 2.142 + t.start(); 2.143 + t.join(1000*10); 2.144 + System.out.println(t.getState()); 2.145 + if (t.isAlive()) { 2.146 + throw new RuntimeException("Error: compilation is looping"); 2.147 + } 2.148 + } 2.149 +}