# HG changeset patch # User alanb # Date 1287394271 -3600 # Node ID 9a677f58dc8563abbc9b88d57fbe96f1d3a2eee5 # Parent 3352f88393203967add581a0e62e8d1ae35e4cd0# Parent 68f3d74dbda189c4b67add9742a0b01de8f226ea Merge diff -r 3352f8839320 -r 9a677f58dc85 jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java Mon Oct 18 10:29:59 2010 +0100 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java Mon Oct 18 10:31:11 2010 +0100 @@ -654,8 +654,8 @@ String layout; public FormatException(String message, int ctype, String name, String layout) { - super(ATTR_CONTEXT_NAME[ctype]+"."+name - +(message == null? "": (": "+message))); + super(ATTR_CONTEXT_NAME[ctype]+ " attribute \"" + name + "\"" + + (message == null? "" : (": " + message))); this.ctype = ctype; this.name = name; this.layout = layout; diff -r 3352f8839320 -r 9a677f58dc85 jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java Mon Oct 18 10:29:59 2010 +0100 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java Mon Oct 18 10:31:11 2010 +0100 @@ -30,6 +30,7 @@ import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.Package.InnerClass; import com.sun.java.util.jar.pack.ConstantPool.*; +import com.sun.tools.classfile.AttributeException; /** * Reader for a class file that is being incorporated into a package. @@ -246,7 +247,9 @@ fixups[fptr++] = in.readUnsignedShort(); break; default: - throw new IOException("Bad constant pool tag "+tag); + throw new ClassFormatException("Bad constant pool tag " + + tag + " in File: " + cls.file.nameString + + " at pos: " + inPos); } } @@ -403,7 +406,7 @@ skip(length, "unknown "+name+" attribute in "+h); continue; } else { - String message = "unknown in "+h; + String message = " is unknown attribute in class " + h; throw new Attribute.FormatException(message, ctype, name, unknownAttrCommand); } @@ -415,7 +418,12 @@ if (a.name() == "Code") { Class.Method m = (Class.Method) h; m.code = new Code(m); - readCode(m.code); + try { + readCode(m.code); + } catch (Instruction.FormatException iie) { + String message = iie.getMessage() + " in " + h; + throw new ClassReader.ClassFormatException(message); + } } else { assert(h == cls); readInnerClasses(cls); @@ -427,6 +435,10 @@ in.readFully(bytes); a = a.addContent(bytes); } + if (a.size() == 0 && !a.layout().isEmpty()) { + throw new ClassFormatException(name + + ": attribute length cannot be zero, in " + h); + } h.addAttribute(a); if (verbose > 2) Utils.log.fine("read "+a); @@ -438,6 +450,7 @@ code.max_locals = readUnsignedShort(); code.bytes = new byte[readInt()]; in.readFully(code.bytes); + Instruction.opcodeChecker(code.bytes); int nh = readUnsignedShort(); code.setHandlerCount(nh); for (int i = 0; i < nh; i++) { @@ -463,4 +476,10 @@ cls.innerClasses = ics; // set directly; do not use setInnerClasses. // (Later, ics may be transferred to the pkg.) } + + class ClassFormatException extends IOException { + public ClassFormatException(String message) { + super(message); + } + } } diff -r 3352f8839320 -r 9a677f58dc85 jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java Mon Oct 18 10:29:59 2010 +0100 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java Mon Oct 18 10:31:11 2010 +0100 @@ -25,6 +25,8 @@ package com.sun.java.util.jar.pack; +import java.io.IOException; + /** * A parsed bytecode instruction. * Provides accessors to various relevant bits. @@ -628,4 +630,21 @@ } } } + + public static void opcodeChecker(byte[] code) throws FormatException { + Instruction i = at(code, 0); + while (i != null) { + int opcode = i.getBC(); + if (opcode == _xxxunusedxxx || opcode < _nop || opcode > _jsr_w) { + String message = "illegal opcode: " + opcode + " " + i; + throw new FormatException(message); + } + i = i.next(); + } + } + static class FormatException extends IOException { + FormatException(String message) { + super(message); + } + } } diff -r 3352f8839320 -r 9a677f58dc85 jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Mon Oct 18 10:29:59 2010 +0100 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java Mon Oct 18 10:31:11 2010 +0100 @@ -496,15 +496,29 @@ reader.unknownAttrCommand = unknownAttrCommand; try { reader.read(); - } catch (Attribute.FormatException ee) { - // He passed up the category to us in layout. - if (ee.layout.equals(Pack200.Packer.PASS)) { - Utils.log.warning("Passing class file uncompressed due to unrecognized attribute: "+fname); - Utils.log.info(ee.toString()); - return null; + } catch (IOException ioe) { + String message = "Passing class file uncompressed due to"; + if (ioe instanceof Attribute.FormatException) { + Attribute.FormatException ee = (Attribute.FormatException) ioe; + // He passed up the category to us in layout. + if (ee.layout.equals(Pack200.Packer.PASS)) { + Utils.log.info(ee.toString()); + Utils.log.warning(message + " unrecognized attribute: " + + fname); + return null; + } + } else if (ioe instanceof ClassReader.ClassFormatException) { + ClassReader.ClassFormatException ce = (ClassReader.ClassFormatException) ioe; + // %% TODO: Do we invent a new property for this or reuse %% + if (unknownAttrCommand.equals(Pack200.Packer.PASS)) { + Utils.log.info(ce.toString()); + Utils.log.warning(message + " unknown class format: " + + fname); + return null; + } } // Otherwise, it must be an error. - throw ee; + throw ioe; } pkg.addClass(cls); return cls.file; diff -r 3352f8839320 -r 9a677f58dc85 jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java Mon Oct 18 10:29:59 2010 +0100 +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java Mon Oct 18 10:31:11 2010 +0100 @@ -182,11 +182,8 @@ } public void warning(String msg, Object param) { - int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); - if (verbose > 0) { getLogger().warning(msg, param); } - } public void warning(String msg) { warning(msg, null); diff -r 3352f8839320 -r 9a677f58dc85 jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/UnsyncByteArrayOutputStream.java --- a/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/UnsyncByteArrayOutputStream.java Mon Oct 18 10:29:59 2010 +0100 +++ b/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/UnsyncByteArrayOutputStream.java Mon Oct 18 10:31:11 2010 +0100 @@ -3,7 +3,7 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2010 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,66 +23,70 @@ import java.io.OutputStream; /** - * A simple Unsynced ByteArryOutputStream + * A simple Unsynced ByteArrayOutputStream * @author raul * */ public class UnsyncByteArrayOutputStream extends OutputStream { - private static ThreadLocal bufCahce = new ThreadLocal() { + private static final int INITIAL_SIZE = 8192; + private static ThreadLocal bufCache = new ThreadLocal() { protected synchronized Object initialValue() { - return new byte[8*1024]; + return new byte[INITIAL_SIZE]; } }; - byte[] buf; - int size=8*1024;//buf.length; - int pos=0; - public UnsyncByteArrayOutputStream() { - buf=(byte[])bufCahce.get(); + + private byte[] buf; + private int size = INITIAL_SIZE; + private int pos = 0; + + public UnsyncByteArrayOutputStream() { + buf = (byte[])bufCache.get(); + } + + public void write(byte[] arg0) { + int newPos = pos + arg0.length; + if (newPos > size) { + expandSize(newPos); } - /** @inheritDoc */ - public void write(byte[] arg0) { - int newPos=pos+arg0.length; - if (newPos>size) { - expandSize(); - } - System.arraycopy(arg0,0,buf,pos,arg0.length); - pos=newPos; - } - /** @inheritDoc */ - public void write(byte[] arg0, int arg1, int arg2) { - int newPos=pos+arg2; - if (newPos>size) { - expandSize(); - } - System.arraycopy(arg0,arg1,buf,pos,arg2); - pos=newPos; + System.arraycopy(arg0, 0, buf, pos, arg0.length); + pos = newPos; + } + + public void write(byte[] arg0, int arg1, int arg2) { + int newPos = pos + arg2; + if (newPos > size) { + expandSize(newPos); } - /** @inheritDoc */ - public void write(int arg0) { - if (pos>=size) { - expandSize(); - } - buf[pos++]=(byte)arg0; + System.arraycopy(arg0, arg1, buf, pos, arg2); + pos = newPos; + } + + public void write(int arg0) { + int newPos = pos + 1; + if (newPos > size) { + expandSize(newPos); } - /** @inheritDoc */ - public byte[] toByteArray() { - byte result[]=new byte[pos]; - System.arraycopy(buf,0,result,0,pos); - return result; - } + buf[pos++] = (byte)arg0; + } - /** @inheritDoc */ - public void reset() { - pos=0; - } + public byte[] toByteArray() { + byte result[] = new byte[pos]; + System.arraycopy(buf, 0, result, 0, pos); + return result; + } + + public void reset() { + pos = 0; + } - /** @inheritDoc */ - void expandSize() { - int newSize=size<<2; - byte newBuf[]=new byte[newSize]; - System.arraycopy(buf,0,newBuf,0,pos); - buf=newBuf; - size=newSize; - + private void expandSize(int newPos) { + int newSize = size; + while (newPos > newSize) { + newSize = newSize<<2; } + byte newBuf[] = new byte[newSize]; + System.arraycopy(buf, 0, newBuf, 0, pos); + buf = newBuf; + size = newSize; + } } diff -r 3352f8839320 -r 9a677f58dc85 jdk/test/com/sun/org/apache/xml/internal/security/utils/UnsyncByteArrayOutputStream/BufferOverflowTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/org/apache/xml/internal/security/utils/UnsyncByteArrayOutputStream/BufferOverflowTest.java Mon Oct 18 10:31:11 2010 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test %I% %E% + * @bug 6954275 + * @summary Check that UnsyncByteArrayOutputStream does not + * throw ArrayIndexOutOfBoundsException + * @compile -XDignore.symbol.file BufferOverflowTest.java + * @run main BufferOverflowTest + */ + +import com.sun.org.apache.xml.internal.security.utils.UnsyncByteArrayOutputStream; + +public class BufferOverflowTest { + + public static void main(String[] args) throws Exception { + try { + UnsyncByteArrayOutputStream out = new UnsyncByteArrayOutputStream(); + out.write(new byte[(8192) << 2 + 1]); + System.out.println("PASSED"); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("FAILED, got ArrayIndexOutOfBoundsException"); + throw new Exception(e); + } + } +} diff -r 3352f8839320 -r 9a677f58dc85 jdk/test/tools/pack200/AttributeTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/pack200/AttributeTests.java Mon Oct 18 10:31:11 2010 +0100 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +/* + * @test + * @bug 6982312 + * @summary tests various classfile format and attribute handling by pack200 + * @compile -XDignore.symbol.file Utils.java AttributeTests.java + * @run main AttributeTests + * @author ksrini + */ +public class AttributeTests { + + public static void main(String... args) throws Exception { + test6982312(); + test6746111(); + } + /* + * This is an interim test, which ensures pack200 handles JSR-292 related + * classfile changes seamlessly, until all the classfile changes in jdk7 + * and jdk8 are fully supported. At that time this test should be jettisoned, + * along with the associated jar file. + * + * The jar file contains sources and classes noting the classes were + * derived by using the javac from the lambda project, + * see http://openjdk.java.net/projects/lambda/. + * Therefore the classes contained in the jar cannot be compiled, using + * the standard jdk7's javac compiler. + */ + static void test6982312() throws IOException { + String pack200Cmd = Utils.getPack200Cmd(); + File dynJar = new File(".", "dyn.jar"); + Utils.copyFile(new File(Utils.TEST_SRC_DIR, "dyn.jar"), dynJar); + File testJar = new File(".", "test.jar"); + List cmds = new ArrayList(); + cmds.add(pack200Cmd); + cmds.add("--repack"); + cmds.add(testJar.getAbsolutePath()); + cmds.add(dynJar.getAbsolutePath()); + Utils.runExec(cmds); + /* + * compare the repacked jar bit-wise, as all the files + * should be transmitted "as-is". + */ + Utils.doCompareBitWise(dynJar.getAbsoluteFile(), testJar.getAbsoluteFile()); + testJar.delete(); + dynJar.delete(); + } + + /* + * this test checks to see if we get the expected strings for output + */ + static void test6746111() throws Exception { + String pack200Cmd = Utils.getPack200Cmd(); + File badAttrJar = new File(".", "badattr.jar"); + Utils.copyFile(new File(Utils.TEST_SRC_DIR, "badattr.jar"), badAttrJar); + File testJar = new File(".", "test.jar"); + List cmds = new ArrayList(); + cmds.add(pack200Cmd); + cmds.add("--repack"); + cmds.add("-v"); + cmds.add(testJar.getAbsolutePath()); + cmds.add(badAttrJar.getAbsolutePath()); + List output = Utils.runExec(cmds); + /* + * compare the repacked jar bit-wise, as all the files + * should be transmitted "as-is". + */ + Utils.doCompareBitWise(badAttrJar.getAbsoluteFile(), testJar.getAbsoluteFile()); + String[] expectedStrings = { + "WARNING: Passing class file uncompressed due to unrecognized" + + " attribute: Foo.class", + "INFO: com.sun.java.util.jar.pack.Attribute$FormatException: " + + "class attribute \"XourceFile\": is unknown attribute " + + "in class Foo", + "INFO: com.sun.java.util.jar.pack.ClassReader$ClassFormatException: " + + "AnnotationDefault: attribute length cannot be zero, in Test.message()", + "WARNING: Passing class file uncompressed due to unknown class format: Test.class" + }; + List notfoundList = new ArrayList(); + notfoundList.addAll(Arrays.asList(expectedStrings)); + // make sure the expected messages are emitted + for (String x : output) { + findString(x, notfoundList, expectedStrings); + } + if (!notfoundList.isEmpty()) { + System.out.println("Not found:"); + for (String x : notfoundList) { + System.out.println(x); + } + throw new Exception("Test fails: " + notfoundList.size() + + " expected strings not found"); + } + testJar.delete(); + badAttrJar.delete(); + } + + private static void findString(String outputStr, List notfoundList, + String[] expectedStrings) { + for (String y : expectedStrings) { + if (outputStr.contains(y)) { + notfoundList.remove(y); + return; + } + } + } +} diff -r 3352f8839320 -r 9a677f58dc85 jdk/test/tools/pack200/badattr.jar Binary file jdk/test/tools/pack200/badattr.jar has changed diff -r 3352f8839320 -r 9a677f58dc85 jdk/test/tools/pack200/dyn.jar Binary file jdk/test/tools/pack200/dyn.jar has changed