blob: 7efd06a62f46366f83b4d6b28c963dbd809f6062 [file] [log] [blame]
/*
* 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");
}
}
}