/* * Copyright 2015 Red Hat, Inc. * 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 * @bug 8144071 * @run main/othervm MarkTryFinallyReproducer * @summary Test that call to canDecodeInput in ImageIO don't corrupt * mark/reset stack in ImageInputStream * @author Jiri Vanek */ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.ByteOrder; import java.util.Locale; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageReaderSpi; import javax.imageio.stream.IIOByteBuffer; import javax.imageio.stream.ImageInputStream; public class MarkTryFinallyReproducer { private static final byte[] bmp = new byte[]{ 127,127, 66, 77, -86, 0, 0, 0, 0, 0, 0, 0, 122, 0, 0, 0, 108, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 1, 0, 24, 0, 0, 0, 0, 0, 48, 0, 0, 0, 19, 11, 0, 0, 19, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 71, 82, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0, 0, 0, -17, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, -1 }; //first two are evil, we are skipping them later. Others are normal BMP private static class NotClosingImageInputStream implements ImageInputStream { private final ImageInputStream src; private NotClosingImageInputStream(ImageInputStream createImageInputStream) { this.src = createImageInputStream; } @Override public void setByteOrder(ByteOrder byteOrder) { src.setByteOrder(byteOrder); } @Override public ByteOrder getByteOrder() { return src.getByteOrder(); } @Override public int read() throws IOException { return src.read(); } @Override public int read(byte[] b) throws IOException { return src.read(b); } @Override public int read(byte[] b, int off, int len) throws IOException { return src.read(b, off, len); } @Override public void readBytes(IIOByteBuffer buf, int len) throws IOException { src.readBytes(buf, len); } @Override public boolean readBoolean() throws IOException { return src.readBoolean(); } @Override public byte readByte() throws IOException { return src.readByte(); } @Override public int readUnsignedByte() throws IOException { return src.readUnsignedByte(); } @Override public short readShort() throws IOException { return src.readShort(); } @Override public int readUnsignedShort() throws IOException { return src.readUnsignedShort(); } @Override public char readChar() throws IOException { return src.readChar(); } @Override public int readInt() throws IOException { return src.readInt(); } @Override public long readUnsignedInt() throws IOException { return src.readUnsignedInt(); } @Override public long readLong() throws IOException { return src.readLong(); } @Override public float readFloat() throws IOException { return src.readFloat(); } @Override public double readDouble() throws IOException { return src.readDouble(); } @Override public String readLine() throws IOException { return src.readLine(); } @Override public String readUTF() throws IOException { return src.readUTF(); } @Override public void readFully(byte[] b, int off, int len) throws IOException { src.readFully(b, off, len); } @Override public void readFully(byte[] b) throws IOException { src.readFully(b); } @Override public void readFully(short[] s, int off, int len) throws IOException { src.readFully(s, off, len); } @Override public void readFully(char[] c, int off, int len) throws IOException { src.readFully(c, off, len); } @Override public void readFully(int[] i, int off, int len) throws IOException { src.readFully(i, off, len); } @Override public void readFully(long[] l, int off, int len) throws IOException { src.readFully(l, off, len); } @Override public void readFully(float[] f, int off, int len) throws IOException { src.readFully(f, off, len); } @Override public void readFully(double[] d, int off, int len) throws IOException { src.readFully(d, off, len); } @Override public long getStreamPosition() throws IOException { return src.getStreamPosition(); } @Override public int getBitOffset() throws IOException { return src.getBitOffset(); } @Override public void setBitOffset(int bitOffset) throws IOException { src.setBitOffset(bitOffset); } @Override public int readBit() throws IOException { return src.readBit(); } @Override public long readBits(int numBits) throws IOException { return src.readBits(numBits); } @Override public long length() throws IOException { return src.length(); } @Override public int skipBytes(int n) throws IOException { return src.skipBytes(n); } @Override public long skipBytes(long n) throws IOException { return src.skipBytes(n); } @Override public void seek(long pos) throws IOException { src.seek(pos); } @Override public void mark() { src.mark(); } @Override public void reset() throws IOException { src.reset(); } @Override public void flushBefore(long pos) throws IOException { src.flushBefore(pos); } @Override public void flush() throws IOException { src.flush(); } @Override public long getFlushedPosition() { return src.getFlushedPosition(); } @Override public boolean isCached() { return src.isCached(); } @Override public boolean isCachedMemory() { return src.isCachedMemory(); } @Override public boolean isCachedFile() { return src.isCachedFile(); } @Override public void close() throws IOException { //the only important one. nothing } } static final String readerClassName = MarkTryFinallyReproducerSpi.class.getName(); static final String[] localNames = {"myNames"}; static final String[] localSuffixes = {"mySuffixes"}; static final String[] localMIMETypes = {"myMimes"}; public static class MarkTryFinallyReproducerSpi extends ImageReaderSpi { public MarkTryFinallyReproducerSpi() { super("MarkTryFinallyReproducerSpi", "1.0", localNames, localSuffixes, localMIMETypes, readerClassName, new Class[]{ImageInputStream.class}, new String[0], false, null, null, new String[0], new String[0], false, null, null, new String[0], new String[0]); } @Override public String getDescription(Locale locale) { return ""; } @Override public boolean canDecodeInput(Object input) throws IOException { throw new IOException("Bad luck"); } @Override public ImageReader createReaderInstance(Object extension) { return null; } } public static void main(String[] args) throws IOException { MarkTryFinallyReproducerSpi spi = new MarkTryFinallyReproducerSpi(); IIORegistry.getDefaultInstance().registerServiceProvider(spi); ImageInputStream iis1 = new NotClosingImageInputStream(ImageIO.createImageInputStream(new ByteArrayInputStream(bmp))); iis1.readByte(); iis1.mark(); long p1 = iis1.getStreamPosition(); iis1.readByte(); iis1.mark(); long p2 = iis1.getStreamPosition(); BufferedImage bi1 = ImageIO.read(iis1); iis1.reset(); long pn2 = iis1.getStreamPosition(); iis1.reset(); long pn1 = iis1.getStreamPosition(); if (p1 != pn1 || p2!= pn2) { throw new RuntimeException("Exception from call to canDecodeInput in ImageIO. " + "Corrupted stack in ImageInputStream"); } } }