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:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
396
test/jdk/java/nio/charset/coders/BashStreams.java
Normal file
396
test/jdk/java/nio/charset/coders/BashStreams.java
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2016, 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
|
||||
* @summary Stochastic test of charset-based streams
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.charset.*;
|
||||
|
||||
|
||||
public class BashStreams {
|
||||
|
||||
static final PrintStream log = System.err;
|
||||
|
||||
|
||||
static class CharacterGenerator {
|
||||
|
||||
private final Random rand;
|
||||
private final int max;
|
||||
private final int limit;
|
||||
private int count = 0;
|
||||
|
||||
CharacterGenerator(long seed, String csn, int limit) {
|
||||
rand = new Random(seed);
|
||||
this.max = Character.MAX_CODE_POINT + 1;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
private char[] saved = new char[10];
|
||||
private int savedCount = 0;
|
||||
|
||||
void push(char c) {
|
||||
saved[savedCount++] = c;
|
||||
count--;
|
||||
}
|
||||
|
||||
int count() {
|
||||
return count;
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return count < limit;
|
||||
}
|
||||
|
||||
char next() {
|
||||
if (count >= limit)
|
||||
throw new RuntimeException("EOF");
|
||||
if (savedCount > 0) {
|
||||
savedCount--;
|
||||
count++;
|
||||
return saved[savedCount];
|
||||
}
|
||||
int c;
|
||||
for (;;) {
|
||||
c = rand.nextInt(max);
|
||||
if ((Character.isBmpCodePoint(c)
|
||||
&& (Character.isSurrogate((char) c)
|
||||
|| (c == 0xfffe) || (c == 0xffff))))
|
||||
continue;
|
||||
if (Character.isSupplementaryCodePoint(c)
|
||||
&& (count == limit - 1))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
if (Character.isSupplementaryCodePoint(c)) {
|
||||
count++;
|
||||
push(Character.lowSurrogate(c));
|
||||
return Character.highSurrogate(c);
|
||||
}
|
||||
return (char)c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void mismatch(String csn, int count, char c, char d) {
|
||||
throw new RuntimeException(csn + ": Mismatch at count "
|
||||
+ count
|
||||
+ ": " + Integer.toHexString(c)
|
||||
+ " != "
|
||||
+ Integer.toHexString(d));
|
||||
}
|
||||
|
||||
static void mismatchedEOF(String csn, int count, int cgCount) {
|
||||
throw new RuntimeException(csn + ": Mismatched EOFs: "
|
||||
+ count
|
||||
+ " != "
|
||||
+ cgCount);
|
||||
}
|
||||
|
||||
|
||||
static class Sink // One abomination...
|
||||
extends OutputStream
|
||||
implements WritableByteChannel
|
||||
{
|
||||
|
||||
private final String csn;
|
||||
private final CharacterGenerator cg;
|
||||
private int count = 0;
|
||||
|
||||
Sink(String csn, long seed) {
|
||||
this.csn = csn;
|
||||
this.cg = new CharacterGenerator(seed, csn, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
write (new byte[] { (byte)b }, 0, 1);
|
||||
}
|
||||
|
||||
private int check(byte[] ba, int off, int len) throws IOException {
|
||||
String s = new String(ba, off, len, csn);
|
||||
int n = s.length();
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = s.charAt(i);
|
||||
char d = cg.next();
|
||||
if (c != d) {
|
||||
if (c == '?') {
|
||||
if (Character.isHighSurrogate(d))
|
||||
cg.next();
|
||||
continue;
|
||||
}
|
||||
mismatch(csn, count + i, c, d);
|
||||
}
|
||||
}
|
||||
count += n;
|
||||
return len;
|
||||
}
|
||||
|
||||
public void write(byte[] ba, int off, int len) throws IOException {
|
||||
check(ba, off, len);
|
||||
}
|
||||
|
||||
public int write(ByteBuffer bb) throws IOException {
|
||||
int n = check(bb.array(),
|
||||
bb.arrayOffset() + bb.position(),
|
||||
bb.remaining());
|
||||
bb.position(bb.position() + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
count = -1;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return count >= 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void testWrite(String csn, int limit, long seed, Writer w)
|
||||
throws IOException
|
||||
{
|
||||
Random rand = new Random(seed);
|
||||
CharacterGenerator cg = new CharacterGenerator(seed, csn,
|
||||
Integer.MAX_VALUE);
|
||||
int count = 0;
|
||||
char[] ca = new char[16384];
|
||||
|
||||
int n = 0;
|
||||
while (count < limit) {
|
||||
n = rand.nextInt(ca.length);
|
||||
for (int i = 0; i < n; i++)
|
||||
ca[i] = cg.next();
|
||||
w.write(ca, 0, n);
|
||||
count += n;
|
||||
}
|
||||
if (Character.isHighSurrogate(ca[n - 1]))
|
||||
w.write(cg.next());
|
||||
w.close();
|
||||
}
|
||||
|
||||
static void testStreamWrite(String csn, int limit, long seed)
|
||||
throws IOException
|
||||
{
|
||||
log.println(" write stream");
|
||||
testWrite(csn, limit, seed,
|
||||
new OutputStreamWriter(new Sink(csn, seed), csn));
|
||||
}
|
||||
|
||||
static void testChannelWrite(String csn, int limit, long seed)
|
||||
throws IOException
|
||||
{
|
||||
log.println(" write channel");
|
||||
testWrite(csn, limit, seed,
|
||||
Channels.newWriter(new Sink(csn, seed),
|
||||
Charset.forName(csn)
|
||||
.newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE),
|
||||
8192));
|
||||
}
|
||||
|
||||
|
||||
static class Source // ... and another
|
||||
extends InputStream
|
||||
implements ReadableByteChannel
|
||||
{
|
||||
|
||||
private final String csn;
|
||||
private final CharsetEncoder enc;
|
||||
private final CharacterGenerator cg;
|
||||
private int count = 0;
|
||||
|
||||
Source(String csn, long seed, int limit) {
|
||||
this.csn = csn.startsWith("\1") ? csn.substring(1) : csn;
|
||||
this.enc = Charset.forName(this.csn).newEncoder()
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||
this.cg = new CharacterGenerator(seed, csn, limit);
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] b = new byte[1];
|
||||
read(b);
|
||||
return b[0];
|
||||
}
|
||||
|
||||
private CharBuffer cb = CharBuffer.allocate(8192);
|
||||
private ByteBuffer bb = null;
|
||||
|
||||
public int read(byte[] ba, int off, int len) throws IOException {
|
||||
if (!cg.hasNext())
|
||||
return -1;
|
||||
int end = off + len;
|
||||
int i = off;
|
||||
while (i < end) {
|
||||
if ((bb == null) || !bb.hasRemaining()) {
|
||||
cb.clear();
|
||||
while (cb.hasRemaining()) {
|
||||
if (!cg.hasNext())
|
||||
break;
|
||||
char c = cg.next();
|
||||
if (Character.isHighSurrogate(c)
|
||||
&& cb.remaining() == 1) {
|
||||
cg.push(c);
|
||||
break;
|
||||
}
|
||||
cb.put(c);
|
||||
}
|
||||
cb.flip();
|
||||
if (!cb.hasRemaining())
|
||||
break;
|
||||
bb = enc.encode(cb);
|
||||
}
|
||||
int d = Math.min(bb.remaining(), end - i);
|
||||
bb.get(ba, i, d);
|
||||
i += d;
|
||||
}
|
||||
return i - off;
|
||||
}
|
||||
|
||||
public int read(ByteBuffer bb) throws IOException {
|
||||
int n = read(bb.array(),
|
||||
bb.arrayOffset() + bb.position(),
|
||||
bb.remaining());
|
||||
if (n >= 0)
|
||||
bb.position(bb.position() + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
count = -1;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return count != -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void testRead(String csn, int limit, long seed, int max,
|
||||
Reader rd)
|
||||
throws IOException
|
||||
{
|
||||
Random rand = new Random(seed);
|
||||
CharacterGenerator cg = new CharacterGenerator(seed, csn, limit);
|
||||
int count = 0;
|
||||
char[] ca = new char[16384];
|
||||
|
||||
int n = 0;
|
||||
while (count < limit) {
|
||||
int rn = rand.nextInt(ca.length);
|
||||
n = rd.read(ca, 0, rn);
|
||||
if (n < 0)
|
||||
break;
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = ca[i];
|
||||
if (!cg.hasNext())
|
||||
mismatchedEOF(csn, count + i, cg.count());
|
||||
char d = cg.next();
|
||||
if (c == '?') {
|
||||
if (Character.isHighSurrogate(d)) {
|
||||
cg.next();
|
||||
continue;
|
||||
}
|
||||
if (d > max)
|
||||
continue;
|
||||
}
|
||||
if (c != d)
|
||||
mismatch(csn, count + i, c, d);
|
||||
}
|
||||
count += n;
|
||||
}
|
||||
if (cg.hasNext())
|
||||
mismatchedEOF(csn, count, cg.count());
|
||||
rd.close();
|
||||
}
|
||||
|
||||
static void testStreamRead(String csn, int limit, long seed, int max)
|
||||
throws IOException
|
||||
{
|
||||
log.println(" read stream");
|
||||
testRead(csn, limit, seed, max,
|
||||
new InputStreamReader(new Source(csn, seed, limit), csn));
|
||||
}
|
||||
|
||||
static void testChannelRead(String csn, int limit, long seed, int max)
|
||||
throws IOException
|
||||
{
|
||||
log.println(" read channel");
|
||||
testRead(csn, limit, seed, max,
|
||||
Channels.newReader(new Source(csn, seed, limit), csn));
|
||||
}
|
||||
|
||||
|
||||
static final int LIMIT = 1 << 21;
|
||||
|
||||
static void test(String csn, int limit, long seed, int max)
|
||||
throws Exception
|
||||
{
|
||||
log.println();
|
||||
log.println(csn);
|
||||
|
||||
testStreamWrite(csn, limit, seed);
|
||||
testChannelWrite(csn, limit, seed);
|
||||
testStreamRead(csn, limit, seed, max);
|
||||
testChannelRead(csn, limit, seed, max);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (System.getProperty("os.arch").equals("ia64")) {
|
||||
// This test requires 54 minutes on an Itanium-1 processor
|
||||
return;
|
||||
}
|
||||
|
||||
int ai = 0, an = args.length;
|
||||
|
||||
int limit;
|
||||
if (ai < an)
|
||||
limit = 1 << Integer.parseInt(args[ai++]);
|
||||
else
|
||||
limit = LIMIT;
|
||||
log.println("limit = " + limit);
|
||||
|
||||
long seed;
|
||||
if (ai < an)
|
||||
seed = Long.parseLong(args[ai++]);
|
||||
else
|
||||
seed = System.currentTimeMillis();
|
||||
log.println("seed = " + seed);
|
||||
|
||||
test("UTF-8", limit, seed, Integer.MAX_VALUE);
|
||||
test("US-ASCII", limit, seed, 0x7f);
|
||||
test("ISO-8859-1", limit, seed, 0xff);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue