undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 1998, 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
@bug 4072173
@summary Test BufferdInputStream close method */
import java.io.*;
/**
* This class tests to see if BufferedInputStream closes
* properly
*/
public class CloseStream {
public static void main( String argv[] ) throws Exception {
BufferedInputStream in = new BufferedInputStream(new MyInputStream());
in.read();
in.close();
try {
in.read(); // IOException should be thrown here
throw new RuntimeException("No exception during read on closed stream");
}
catch (IOException e) {
System.err.println("Test passed: IOException is thrown");
}
}
}
class MyInputStream extends InputStream {
public MyInputStream() {
}
public void close() throws IOException {
if (status == OPEN) {
status = CLOSED;
} else throw new IOException();
}
public int read() throws IOException {
if (status == CLOSED)
throw new IOException();
return (byte)'a';
}
private final int OPEN = 1;
private final int CLOSED = 2;
private int status = OPEN;
}

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 1998, 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
* @bug 4054043
* @summary Test bufferedinputstream when stream is interrupted
*
*/
import java.io.*;
/**
* This class tests to see if bufferinputstream updates count
* when the stream is interrupted and restarted
* It was adapted from a test class provided in the bug report
*
*/
public class CountUpdate {
public static void main(String[] args) throws Exception {
BufferBreaker breaker = new BufferBreaker();
BufferedInputStream in = new BufferedInputStream(breaker, 1000);
byte b[] = new byte[100];
int total = 0;
for (int i=0; i<5; i++) {
if (i>0) breaker.breakIt = true;
try {
int n = in.read(b);
total += n;
//System.out.print("read "+n+" bytes: [");
//System.out.write(b, 0, n);
//System.out.println("]");
}
catch (IOException e) {
//System.out.println(e);
}
}
if (total>7)
throw new RuntimeException(
"BufferedInputStream did not reset count.");
}
}
class BufferBreaker extends InputStream {
public boolean breakIt = false;
public int read() {
return 'x';
}
public static final byte[] buffer = {(byte)'a',
(byte)'b',
(byte)'c',
(byte)'d',
(byte)'e',
(byte)'f',
(byte)'g'};
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
if (breakIt) throw new IOException("BREAK");
if (len > buffer.length) len = buffer.length;
System.arraycopy(buffer, 0, b, off, len);
return len;
}
public long skip(long n) {
return 0;
}
public int available() {
return 0;
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 1998, 2006, 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
@bug 4090383
@summary Ensure that BufferedInputStream's read method will fill the target
array whenever possible
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedInputStream;
public class Fill {
/**
* A simple InputStream that is always ready but may read fewer than the
* requested number of bytes
*/
static class Source extends InputStream {
int shortFall;
byte next = 0;
Source(int shortFall) {
this.shortFall = shortFall;
}
public int read() throws IOException {
return next++;
}
public int read(byte[] buf, int off, int len) throws IOException {
int n = len - shortFall;
for (int i = off; i < n; i++)
buf[i] = next++;
return n;
}
public int available() {
return Integer.MAX_VALUE;
}
public void close() throws IOException {
}
}
/**
* Test BufferedInputStream with an underlying source that always reads
* shortFall fewer bytes than requested
*/
static void go(int shortFall) throws Exception {
InputStream r = new BufferedInputStream(new Source(shortFall), 10);
byte[] buf = new byte[8];
int n1 = r.read(buf);
int n2 = r.read(buf);
System.err.println("Shortfall " + shortFall
+ ": Read " + n1 + ", then " + n2 + " bytes");
if (n1 != buf.length)
throw new Exception("First read returned " + n1);
if (n2 != buf.length)
throw new Exception("Second read returned " + n2);
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 8; i++) go(i);
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2013, 2021, 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
* @bug 7129312
* @requires (sun.arch.data.model == "64" & os.maxMemory > 4g)
* @summary BufferedInputStream calculates negative array size with large
* streams and mark
* @run main/othervm -Xmx4G -Xlog:gc,gc+heap,gc+ergo+heap -XX:+CrashOnOutOfMemoryError
-XX:+IgnoreUnrecognizedVMOptions -XX:+G1ExitOnExpansionFailure
-Xlog:cds=debug
LargeCopyWithMark
*/
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class LargeCopyWithMark {
static final int BUFF_SIZE = 8192;
static final int BIS_BUFF_SIZE = Integer.MAX_VALUE / 2 + 100;
static final long BYTES_TO_COPY = 2L * Integer.MAX_VALUE;
static {
assert BIS_BUFF_SIZE * 2 < 0 : "doubling must overflow";
}
public static void main(String[] args) throws Exception {
byte[] buff = new byte[BUFF_SIZE];
try (InputStream myis = new MyInputStream(BYTES_TO_COPY);
InputStream bis = new BufferedInputStream(myis, BIS_BUFF_SIZE);
OutputStream myos = new MyOutputStream()) {
// will require a buffer bigger than BIS_BUFF_SIZE
bis.mark(BIS_BUFF_SIZE + 100);
for (;;) {
int count = bis.read(buff, 0, BUFF_SIZE);
if (count == -1)
break;
myos.write(buff, 0, count);
}
}
}
}
class MyInputStream extends InputStream {
private long bytesLeft;
public MyInputStream(long bytesLeft) {
this.bytesLeft = bytesLeft;
}
@Override public int read() throws IOException {
return 0;
}
@Override public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override public int read(byte[] b, int off, int len) throws IOException {
if (bytesLeft <= 0)
return -1;
long result = Math.min(bytesLeft, (long)len);
bytesLeft -= result;
return (int)result;
}
@Override public int available() throws IOException {
return (bytesLeft > 0) ? 1 : 0;
}
}
class MyOutputStream extends OutputStream {
@Override public void write(int b) throws IOException {}
@Override public void write(byte[] b) throws IOException {}
@Override public void write(byte[] b, int off, int len) throws IOException {}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 1998, 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
@bug 4143651
@summary Test if I/O methods will check if the stream
has been closed.
*/
import java.io.*;
public class ReadAfterClose {
static void testRead(InputStream in) throws Exception {
in.close();
byte[] buf = new byte[2];
try {
in.read(buf, 0, 1);
throw new Exception("Should not allow read on a closed stream");
} catch (IOException e) {
}
try {
in.read(buf, 0, 0);
throw new Exception("Should not allow read on a closed stream");
} catch (IOException e) {
}
}
public static void main(String argv[]) throws Exception {
BufferedInputStream bis = new BufferedInputStream
(new ByteArrayInputStream(new byte[32]));
testRead(bis);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2004, 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
* @bug 5041041
* @summary Test BufferedInputStream read of zero byte array
*/
import java.io.*;
/**
* This class tests to see if BufferedInputStream of zero length array
* invokes the read method or not. Invoking read could block which is
* incompatible behavior for zero length array.
*/
public class ReadZeroBytes {
public static void main( String argv[] ) throws Exception {
BufferedInputStream in = new BufferedInputStream(
new ThrowingInputStream());
in.read(new byte[0], 0, 0);
}
}
class ThrowingInputStream extends InputStream {
public ThrowingInputStream() {
}
public int read() throws IOException {
return 0;
}
public int read(byte[] b, int off, int len) throws IOException {
throw new RuntimeException("Read invoked for len == 0");
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 1998, 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 1.1 98/01/12
* @bug 4022294
* @summary Test bufferedinputstream for data loss during skip
*
*/
import java.io.*;
import java.util.*;
/**
* This class tests to see if bufferinputstream can be reset
* to recover data that was skipped over when the buffer did
* not contain all the bytes to be skipped
*/
public class SkipTest {
public static void main(String[] args) throws Exception {
long skipped = 0;
// Create a tiny buffered stream so it can be easily
// set up to contain only some of the bytes to skip
DataSupplier source = new DataSupplier();
BufferedInputStream in = new BufferedInputStream(source, 4);
// Set up data to be skipped and recovered
// the skip must be longer than the buffer size
in.mark(30);
while (skipped < 15) {
skipped += in.skip(15-skipped);
}
int nextint = in.read();
in.reset();
// Resume reading and see if data was lost
nextint = in.read();
if (nextint != 'a')
throw new RuntimeException("BufferedInputStream skip lost data");
}
}
class DataSupplier extends InputStream {
private int aposition=0;
public int read() {
return 'x';
}
public long skip(long n) {
aposition += (int) n;
return n;
}
public static final byte[] buffer = {(byte)'a',(byte)'b',(byte)'c',
(byte)'d',(byte)'e',(byte)'f',(byte)'g',(byte)'h',(byte)'i',
(byte)'j',(byte)'k',(byte)'l',(byte)'m',(byte)'n',(byte)'o',
(byte)'p',(byte)'q',(byte)'r',(byte)'s',(byte)'t',(byte)'u',
(byte)'v',(byte)'w',(byte)'x',(byte)'y',(byte)'z'
};
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
if (len > buffer.length) len = buffer.length;
System.arraycopy(buffer, aposition, b, off, len);
return len;
}
}

View file

@ -0,0 +1,248 @@
/*
* Copyright (c) 2022, 2026, 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.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.Pipe;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
import jdk.test.lib.RandomFactory;
import static java.lang.String.format;
import static java.nio.file.StandardOpenOption.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*
* @test
* @library /test/lib
* @build jdk.test.lib.RandomFactory
* @run junit/othervm/timeout=180 -Xmx1280m TransferTo
* @bug 8279283 8294541
* @summary Tests whether java.io.BufferedInputStream.transferTo conforms to the
* InputStream.transferTo specification
* @key randomness
*/
public class TransferTo {
private static final int MIN_SIZE = 10_000;
private static final int MAX_SIZE_INCR = 100_000_000 - MIN_SIZE;
private static final int ITERATIONS = 10;
private static final Random RND = RandomFactory.getRandom();
/*
* Testing API compliance: input stream must throw NullPointerException
* when parameter "out" is null.
*/
@Test
public void testNullPointerException() throws Exception {
// factory for incoming data provider
InputStreamProvider inputStreamProvider = byteArrayInput();
// tests empty input stream
assertThrows(NullPointerException.class,
() -> inputStreamProvider.input().transferTo(null));
// tests single-byte input stream
assertThrows(NullPointerException.class,
() -> inputStreamProvider.input((byte) 1).transferTo(null));
// tests dual-byte input stream
assertThrows(NullPointerException.class,
() -> inputStreamProvider.input((byte) 1, (byte) 2).transferTo(null));
}
/*
* Testing API compliance: complete content of input stream must be
* transferred to output stream.
*/
@Test
public void testStreamContents() throws Exception {
// factory for incoming data provider
InputStreamProvider inputStreamProvider = byteArrayInput();
// factory for outgoing data recorder
OutputStreamProvider outputStreamProvider = byteArrayOutput();
// tests empty input stream
checkTransferredContents(inputStreamProvider,
outputStreamProvider, new byte[0]);
// tests input stream with a length between 1k and 4k
checkTransferredContents(inputStreamProvider,
outputStreamProvider, createRandomBytes(1024, 4096));
// tests input stream with several data chunks, as 16k is more than a
// single chunk can hold
checkTransferredContents(inputStreamProvider,
outputStreamProvider, createRandomBytes(16384, 16384));
// tests randomly chosen starting positions within source and
// target stream and random buffer level
for (int i = 0; i < ITERATIONS; i++) {
byte[] inBytes = createRandomBytes(MIN_SIZE, MAX_SIZE_INCR);
int posIn = RND.nextInt(inBytes.length);
int posOut = RND.nextInt(MIN_SIZE);
int bufferBytes = RND.nextInt(inBytes.length - posIn);
boolean markAndReset = RND.nextBoolean();
checkTransferredContents(inputStreamProvider,
outputStreamProvider, inBytes, posIn, posOut, bufferBytes, markAndReset);
}
// tests reading beyond source EOF (must not transfer any bytes)
checkTransferredContents(inputStreamProvider,
outputStreamProvider, createRandomBytes(4096, 0), 4096, 0, 0, false);
// tests writing beyond target EOF (must extend output stream)
checkTransferredContents(inputStreamProvider,
outputStreamProvider, createRandomBytes(4096, 0), 0, 4096, 0, false);
}
/*
* Asserts that the transferred content is correct, i.e., compares the bytes
* actually transferred to those expected. The position of the input and
* output streams before the transfer are zero (BOF).
*/
private static void checkTransferredContents(InputStreamProvider inputStreamProvider,
OutputStreamProvider outputStreamProvider, byte[] inBytes) throws Exception {
checkTransferredContents(inputStreamProvider,
outputStreamProvider, inBytes, 0, 0, 0, false);
}
/*
* Asserts that the transferred content is correct, i. e. compares the bytes
* actually transferred to those expected. The positions of the input and
* output streams before the transfer are provided by the caller.
*/
private static void checkTransferredContents(InputStreamProvider inputStreamProvider,
OutputStreamProvider outputStreamProvider, byte[] inBytes, int posIn,
int posOut, int bufferBytes, boolean markAndReset) throws Exception {
AtomicReference<Supplier<byte[]>> recorder = new AtomicReference<>();
try (InputStream in = inputStreamProvider.input(inBytes);
OutputStream out = outputStreamProvider.output(recorder::set)) {
// skip bytes until starting position
in.skipNBytes(posIn);
out.write(new byte[posOut]);
// fill buffer by reading some bytes before transferTo
byte[] bytes = new byte[bufferBytes];
in.read(bytes);
out.write(bytes);
// set mark at current position for later replay
if (markAndReset) {
in.mark(Integer.MAX_VALUE);
}
long reported = in.transferTo(out);
int count = inBytes.length - posIn;
int expected = count - bufferBytes;
assertEquals(expected, reported,
format("transferred %d bytes but should report %d", reported, expected));
byte[] outBytes = recorder.get().get();
assertTrue(Arrays.equals(inBytes, posIn, posIn + count,
outBytes, posOut, posOut + count),
format("inBytes.length=%d, outBytes.length=%d", count, outBytes.length));
// replay from marked position
if (markAndReset) {
in.reset();
reported = in.transferTo(out);
expected = count - bufferBytes;
assertEquals(expected, reported,
format("replayed %d bytes but should report %d", reported, expected));
outBytes = recorder.get().get();
assertTrue(Arrays.equals(inBytes, posIn + bufferBytes, inBytes.length,
outBytes, posOut + count, outBytes.length),
format("inBytes.length=%d, outBytes.length=%d",
inBytes.length - posIn - bufferBytes,
outBytes.length - posOut - count));
}
}
}
/*
* Creates an array of random size (between min and min + maxRandomAdditive)
* filled with random bytes
*/
private static byte[] createRandomBytes(int min, int maxRandomAdditive) {
byte[] bytes = new byte[min +
(maxRandomAdditive == 0 ? 0 : RND.nextInt(maxRandomAdditive))];
RND.nextBytes(bytes);
return bytes;
}
private interface InputStreamProvider {
InputStream input(byte... bytes) throws Exception;
}
private interface OutputStreamProvider {
OutputStream output(Consumer<Supplier<byte[]>> spy) throws Exception;
}
private static InputStreamProvider byteArrayInput() {
return bytes -> new BufferedInputStream(new ByteArrayInputStream(bytes));
}
private static OutputStreamProvider byteArrayOutput() {
return new OutputStreamProvider() {
@Override
public OutputStream output(Consumer<Supplier<byte[]>> spy) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
spy.accept(outputStream::toByteArray);
return outputStream;
}
};
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2023, 2024, 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.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.Random;
/*
* @test
* @bug 8320971
* @summary Verify BufferedInputStream.buf is used directly by
* BufferedInputStream.implTransferTo() only when its OutputStream
* parameter is trusted
* @key randomness
* @run main/othervm --add-opens=java.base/java.io=ALL-UNNAMED TransferToTrusted
*/
public class TransferToTrusted {
private static final Random RND = new Random(System.nanoTime());
private static final class UntrustedOutputStream extends OutputStream {
UntrustedOutputStream() {
super();
}
@Override
public void write(byte[] b, int off, int len) {
Objects.checkFromIndexSize(off, len, b.length);
byte[] tmp = new byte[len];
RND.nextBytes(tmp);
System.arraycopy(tmp, 0, b, off, len);
}
@Override
public void write(int b) throws IOException {
write(new byte[]{(byte) b});
}
}
public static void main(String[] args) throws Exception {
final int length = 128;
byte[] buf = new byte[length];
RND.nextBytes(buf);
var outputStreams = new OutputStream[]{
new ByteArrayOutputStream(),
new FileOutputStream(File.createTempFile(TransferToTrusted.class.getName(), null)),
new PipedOutputStream(new PipedInputStream(length)),
new UntrustedOutputStream()
};
for (var out : outputStreams) {
System.err.println("out: " + out.getClass().getName());
var bis = new BufferedInputStream(new ByteArrayInputStream(buf.clone()));
try (out; bis) {
bis.read();//need this to fill the BIS.buf in
bis.transferTo(out);
var internalBuffer = bis.getClass().getDeclaredField("buf");
internalBuffer.setAccessible(true);
if (!Arrays.equals(buf, Arrays.copyOf((byte[]) internalBuffer.get(bis), length))) {
throw new RuntimeException("Internal buffer was modified");
}
}
}
}
}