1 /*
2  * Copyright 2015 Red Hat, Inc.
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 8144071
27  * @run main/othervm MarkTryFinallyReproducer
28  * @summary Test that call to canDecodeInput in ImageIO don't corrupt
29  *           mark/reset stack in ImageInputStream
30  * @author Jiri Vanek
31  */
32 
33 import java.awt.image.BufferedImage;
34 import java.io.ByteArrayInputStream;
35 import java.io.IOException;
36 import java.nio.ByteOrder;
37 import java.util.Locale;
38 import javax.imageio.ImageIO;
39 import javax.imageio.ImageReader;
40 import javax.imageio.spi.IIORegistry;
41 import javax.imageio.spi.ImageReaderSpi;
42 import javax.imageio.stream.IIOByteBuffer;
43 import javax.imageio.stream.ImageInputStream;
44 
45 
46 public class MarkTryFinallyReproducer {
47 
48     private static final byte[] bmp = new byte[]{
49         127,127, 66, 77, -86, 0, 0, 0, 0, 0, 0, 0,
50         122, 0, 0, 0, 108, 0, 0, 0, 4, 0, 0, 0, 4,
51         0, 0, 0, 1, 0, 24, 0, 0, 0, 0, 0, 48, 0, 0,
52         0, 19, 11, 0, 0, 19, 11, 0, 0, 0, 0, 0, 0, 0,
53         0, 0, 0, 66, 71, 82, 115, 0, 0, 0, 0, 0, 0, 0,
54         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56         0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
57         0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, -1, -1,
58         -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0, 0, 0, -17,
59         0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, -1, -1,
60         -1, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, -1
61     };
62     //first two are evil, we are skipping them later. Others are normal BMP
63 
64     private static class NotClosingImageInputStream implements ImageInputStream {
65 
66         private final ImageInputStream src;
67 
NotClosingImageInputStream(ImageInputStream createImageInputStream)68         private NotClosingImageInputStream(ImageInputStream createImageInputStream) {
69             this.src = createImageInputStream;
70         }
71 
72         @Override
setByteOrder(ByteOrder byteOrder)73         public void setByteOrder(ByteOrder byteOrder) {
74             src.setByteOrder(byteOrder);
75         }
76 
77         @Override
getByteOrder()78         public ByteOrder getByteOrder() {
79             return src.getByteOrder();
80         }
81 
82         @Override
read()83         public int read() throws IOException {
84             return src.read();
85         }
86 
87         @Override
read(byte[] b)88         public int read(byte[] b) throws IOException {
89             return src.read(b);
90         }
91 
92         @Override
read(byte[] b, int off, int len)93         public int read(byte[] b, int off, int len) throws IOException {
94             return src.read(b, off, len);
95         }
96 
97         @Override
readBytes(IIOByteBuffer buf, int len)98         public void readBytes(IIOByteBuffer buf, int len) throws IOException {
99             src.readBytes(buf, len);
100         }
101 
102         @Override
readBoolean()103         public boolean readBoolean() throws IOException {
104             return src.readBoolean();
105         }
106 
107         @Override
readByte()108         public byte readByte() throws IOException {
109             return src.readByte();
110         }
111 
112         @Override
readUnsignedByte()113         public int readUnsignedByte() throws IOException {
114             return src.readUnsignedByte();
115         }
116 
117         @Override
readShort()118         public short readShort() throws IOException {
119             return src.readShort();
120         }
121 
122         @Override
readUnsignedShort()123         public int readUnsignedShort() throws IOException {
124             return src.readUnsignedShort();
125         }
126 
127         @Override
readChar()128         public char readChar() throws IOException {
129             return src.readChar();
130         }
131 
132         @Override
readInt()133         public int readInt() throws IOException {
134             return src.readInt();
135         }
136 
137         @Override
readUnsignedInt()138         public long readUnsignedInt() throws IOException {
139             return src.readUnsignedInt();
140         }
141 
142         @Override
readLong()143         public long readLong() throws IOException {
144             return src.readLong();
145         }
146 
147         @Override
readFloat()148         public float readFloat() throws IOException {
149             return src.readFloat();
150         }
151 
152         @Override
readDouble()153         public double readDouble() throws IOException {
154             return src.readDouble();
155         }
156 
157         @Override
readLine()158         public String readLine() throws IOException {
159             return src.readLine();
160         }
161 
162         @Override
readUTF()163         public String readUTF() throws IOException {
164             return src.readUTF();
165         }
166 
167         @Override
readFully(byte[] b, int off, int len)168         public void readFully(byte[] b, int off, int len) throws IOException {
169             src.readFully(b, off, len);
170         }
171 
172         @Override
readFully(byte[] b)173         public void readFully(byte[] b) throws IOException {
174             src.readFully(b);
175         }
176 
177         @Override
readFully(short[] s, int off, int len)178         public void readFully(short[] s, int off, int len) throws IOException {
179             src.readFully(s, off, len);
180         }
181 
182         @Override
readFully(char[] c, int off, int len)183         public void readFully(char[] c, int off, int len) throws IOException {
184             src.readFully(c, off, len);
185         }
186 
187         @Override
readFully(int[] i, int off, int len)188         public void readFully(int[] i, int off, int len) throws IOException {
189             src.readFully(i, off, len);
190         }
191 
192         @Override
readFully(long[] l, int off, int len)193         public void readFully(long[] l, int off, int len) throws IOException {
194             src.readFully(l, off, len);
195         }
196 
197         @Override
readFully(float[] f, int off, int len)198         public void readFully(float[] f, int off, int len) throws IOException {
199             src.readFully(f, off, len);
200         }
201 
202         @Override
readFully(double[] d, int off, int len)203         public void readFully(double[] d, int off, int len) throws IOException {
204             src.readFully(d, off, len);
205         }
206 
207         @Override
getStreamPosition()208         public long getStreamPosition() throws IOException {
209             return src.getStreamPosition();
210         }
211 
212         @Override
getBitOffset()213         public int getBitOffset() throws IOException {
214             return src.getBitOffset();
215         }
216 
217         @Override
setBitOffset(int bitOffset)218         public void setBitOffset(int bitOffset) throws IOException {
219             src.setBitOffset(bitOffset);
220         }
221 
222         @Override
readBit()223         public int readBit() throws IOException {
224             return src.readBit();
225         }
226 
227         @Override
readBits(int numBits)228         public long readBits(int numBits) throws IOException {
229             return src.readBits(numBits);
230         }
231 
232         @Override
length()233         public long length() throws IOException {
234             return src.length();
235         }
236 
237         @Override
skipBytes(int n)238         public int skipBytes(int n) throws IOException {
239             return src.skipBytes(n);
240         }
241 
242         @Override
skipBytes(long n)243         public long skipBytes(long n) throws IOException {
244             return src.skipBytes(n);
245         }
246 
247         @Override
seek(long pos)248         public void seek(long pos) throws IOException {
249             src.seek(pos);
250         }
251 
252         @Override
mark()253         public void mark() {
254             src.mark();
255         }
256 
257         @Override
reset()258         public void reset() throws IOException {
259             src.reset();
260         }
261 
262         @Override
flushBefore(long pos)263         public void flushBefore(long pos) throws IOException {
264             src.flushBefore(pos);
265         }
266 
267         @Override
flush()268         public void flush() throws IOException {
269             src.flush();
270         }
271 
272         @Override
getFlushedPosition()273         public long getFlushedPosition() {
274             return src.getFlushedPosition();
275         }
276 
277         @Override
isCached()278         public boolean isCached() {
279             return src.isCached();
280         }
281 
282         @Override
isCachedMemory()283         public boolean isCachedMemory() {
284             return src.isCachedMemory();
285         }
286 
287         @Override
isCachedFile()288         public boolean isCachedFile() {
289             return src.isCachedFile();
290         }
291 
292         @Override
close()293         public void close() throws IOException {
294             //the only important one. nothing
295         }
296     }
297 
298     static final String readerClassName
299             = MarkTryFinallyReproducerSpi.class.getName();
300     static final String[] localNames = {"myNames"};
301     static final String[] localSuffixes = {"mySuffixes"};
302     static final String[] localMIMETypes = {"myMimes"};
303 
304     public static class MarkTryFinallyReproducerSpi extends ImageReaderSpi {
305 
MarkTryFinallyReproducerSpi()306         public MarkTryFinallyReproducerSpi() {
307             super("MarkTryFinallyReproducerSpi",
308                     "1.0",
309                     localNames,
310                     localSuffixes,
311                     localMIMETypes,
312                     readerClassName,
313                     new Class[]{ImageInputStream.class},
314                     new String[0],
315                     false,
316                     null,
317                     null,
318                     new String[0],
319                     new String[0],
320                     false,
321                     null,
322                     null,
323                     new String[0],
324                     new String[0]);
325         }
326 
327         @Override
getDescription(Locale locale)328         public String getDescription(Locale locale) {
329             return "";
330         }
331 
332         @Override
canDecodeInput(Object input)333         public boolean canDecodeInput(Object input) throws IOException {
334             throw new IOException("Bad luck");
335         }
336 
337         @Override
createReaderInstance(Object extension)338         public ImageReader createReaderInstance(Object extension) {
339             return null;
340         }
341     }
342 
main(String[] args)343     public static void main(String[] args) throws IOException {
344         MarkTryFinallyReproducerSpi spi = new MarkTryFinallyReproducerSpi();
345         IIORegistry.getDefaultInstance().registerServiceProvider(spi);
346 
347         ImageInputStream iis1 =
348           new NotClosingImageInputStream(ImageIO.createImageInputStream(new ByteArrayInputStream(bmp)));
349         iis1.readByte();
350         iis1.mark();
351         long p1 = iis1.getStreamPosition();
352         iis1.readByte();
353         iis1.mark();
354         long p2 = iis1.getStreamPosition();
355         BufferedImage bi1 = ImageIO.read(iis1);
356         iis1.reset();
357         long pn2 = iis1.getStreamPosition();
358         iis1.reset();
359         long pn1 = iis1.getStreamPosition();
360         if (p1 != pn1 || p2!= pn2) {
361             throw new RuntimeException("Exception from call to canDecodeInput in ImageIO. " +
362                                        "Corrupted stack in ImageInputStream");
363         }
364 
365     }
366 
367 }
368