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 33import java.awt.image.BufferedImage; 34import java.io.ByteArrayInputStream; 35import java.io.IOException; 36import java.nio.ByteOrder; 37import java.util.Locale; 38import javax.imageio.ImageIO; 39import javax.imageio.ImageReader; 40import javax.imageio.spi.IIORegistry; 41import javax.imageio.spi.ImageReaderSpi; 42import javax.imageio.stream.IIOByteBuffer; 43import javax.imageio.stream.ImageInputStream; 44 45 46public 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 68 private NotClosingImageInputStream(ImageInputStream createImageInputStream) { 69 this.src = createImageInputStream; 70 } 71 72 @Override 73 public void setByteOrder(ByteOrder byteOrder) { 74 src.setByteOrder(byteOrder); 75 } 76 77 @Override 78 public ByteOrder getByteOrder() { 79 return src.getByteOrder(); 80 } 81 82 @Override 83 public int read() throws IOException { 84 return src.read(); 85 } 86 87 @Override 88 public int read(byte[] b) throws IOException { 89 return src.read(b); 90 } 91 92 @Override 93 public int read(byte[] b, int off, int len) throws IOException { 94 return src.read(b, off, len); 95 } 96 97 @Override 98 public void readBytes(IIOByteBuffer buf, int len) throws IOException { 99 src.readBytes(buf, len); 100 } 101 102 @Override 103 public boolean readBoolean() throws IOException { 104 return src.readBoolean(); 105 } 106 107 @Override 108 public byte readByte() throws IOException { 109 return src.readByte(); 110 } 111 112 @Override 113 public int readUnsignedByte() throws IOException { 114 return src.readUnsignedByte(); 115 } 116 117 @Override 118 public short readShort() throws IOException { 119 return src.readShort(); 120 } 121 122 @Override 123 public int readUnsignedShort() throws IOException { 124 return src.readUnsignedShort(); 125 } 126 127 @Override 128 public char readChar() throws IOException { 129 return src.readChar(); 130 } 131 132 @Override 133 public int readInt() throws IOException { 134 return src.readInt(); 135 } 136 137 @Override 138 public long readUnsignedInt() throws IOException { 139 return src.readUnsignedInt(); 140 } 141 142 @Override 143 public long readLong() throws IOException { 144 return src.readLong(); 145 } 146 147 @Override 148 public float readFloat() throws IOException { 149 return src.readFloat(); 150 } 151 152 @Override 153 public double readDouble() throws IOException { 154 return src.readDouble(); 155 } 156 157 @Override 158 public String readLine() throws IOException { 159 return src.readLine(); 160 } 161 162 @Override 163 public String readUTF() throws IOException { 164 return src.readUTF(); 165 } 166 167 @Override 168 public void readFully(byte[] b, int off, int len) throws IOException { 169 src.readFully(b, off, len); 170 } 171 172 @Override 173 public void readFully(byte[] b) throws IOException { 174 src.readFully(b); 175 } 176 177 @Override 178 public void readFully(short[] s, int off, int len) throws IOException { 179 src.readFully(s, off, len); 180 } 181 182 @Override 183 public void readFully(char[] c, int off, int len) throws IOException { 184 src.readFully(c, off, len); 185 } 186 187 @Override 188 public void readFully(int[] i, int off, int len) throws IOException { 189 src.readFully(i, off, len); 190 } 191 192 @Override 193 public void readFully(long[] l, int off, int len) throws IOException { 194 src.readFully(l, off, len); 195 } 196 197 @Override 198 public void readFully(float[] f, int off, int len) throws IOException { 199 src.readFully(f, off, len); 200 } 201 202 @Override 203 public void readFully(double[] d, int off, int len) throws IOException { 204 src.readFully(d, off, len); 205 } 206 207 @Override 208 public long getStreamPosition() throws IOException { 209 return src.getStreamPosition(); 210 } 211 212 @Override 213 public int getBitOffset() throws IOException { 214 return src.getBitOffset(); 215 } 216 217 @Override 218 public void setBitOffset(int bitOffset) throws IOException { 219 src.setBitOffset(bitOffset); 220 } 221 222 @Override 223 public int readBit() throws IOException { 224 return src.readBit(); 225 } 226 227 @Override 228 public long readBits(int numBits) throws IOException { 229 return src.readBits(numBits); 230 } 231 232 @Override 233 public long length() throws IOException { 234 return src.length(); 235 } 236 237 @Override 238 public int skipBytes(int n) throws IOException { 239 return src.skipBytes(n); 240 } 241 242 @Override 243 public long skipBytes(long n) throws IOException { 244 return src.skipBytes(n); 245 } 246 247 @Override 248 public void seek(long pos) throws IOException { 249 src.seek(pos); 250 } 251 252 @Override 253 public void mark() { 254 src.mark(); 255 } 256 257 @Override 258 public void reset() throws IOException { 259 src.reset(); 260 } 261 262 @Override 263 public void flushBefore(long pos) throws IOException { 264 src.flushBefore(pos); 265 } 266 267 @Override 268 public void flush() throws IOException { 269 src.flush(); 270 } 271 272 @Override 273 public long getFlushedPosition() { 274 return src.getFlushedPosition(); 275 } 276 277 @Override 278 public boolean isCached() { 279 return src.isCached(); 280 } 281 282 @Override 283 public boolean isCachedMemory() { 284 return src.isCachedMemory(); 285 } 286 287 @Override 288 public boolean isCachedFile() { 289 return src.isCachedFile(); 290 } 291 292 @Override 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 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 328 public String getDescription(Locale locale) { 329 return ""; 330 } 331 332 @Override 333 public boolean canDecodeInput(Object input) throws IOException { 334 throw new IOException("Bad luck"); 335 } 336 337 @Override 338 public ImageReader createReaderInstance(Object extension) { 339 return null; 340 } 341 } 342 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