8153490: Cannot setBytes() if incoming buffer's length is bigger than number of elements we want to insert.

Reviewed-by: lancea
This commit is contained in:
Mitsuru Kariya 2021-10-28 15:56:17 +00:00 committed by Lance Andersen
parent cb989cf3a1
commit 63b9f8c0da
4 changed files with 257 additions and 98 deletions
src/java.sql.rowset/share/classes/javax/sql/rowset/serial
test/jdk/javax/sql/testng/test/rowset/serial

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -298,22 +298,21 @@ public class SerialBlob implements Blob, Serializable, Cloneable {
}
/**
* Writes the given array of bytes to the <code>BLOB</code> value that
* this <code>Blob</code> object represents, starting at position
* <code>pos</code>, and returns the number of bytes written.
* Writes the given array of bytes to the {@code BLOB} value that
* this {@code Blob} object represents, starting at position
* {@code pos}, and returns the number of bytes written.
*
* @param pos the position in the SQL <code>BLOB</code> value at which
* to start writing. The first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object.
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* value that this <code>Blob</code> object represents
* @param pos the position in the SQL {@code BLOB} value at which
* to start writing. The first position is {@code 1};
* must not be less than {@code 1} nor greater than
* the length+1 of this {@code SerialBlob} object.
* @param bytes the array of bytes to be written to the {@code BLOB}
* value that this {@code Blob} object represents
* @return the number of bytes written
* @throws SerialException if there is an error accessing the
* <code>BLOB</code> value; or if an invalid position is set; if an
* invalid offset value is set;
* {@code BLOB} value; or if an invalid position is set;
* if {@code free} had previously been called on this object
* @throws SQLException if there is an error accessing the <code>BLOB</code>
* @throws SQLException if there is an error accessing the {@code BLOB}
* value from the database
* @see #getBytes
*/
@ -323,33 +322,33 @@ public class SerialBlob implements Blob, Serializable, Cloneable {
}
/**
* Writes all or part of the given <code>byte</code> array to the
* <code>BLOB</code> value that this <code>Blob</code> object represents
* Writes all or part of the given {@code byte} array to the
* {@code BLOB} value that this {@code Blob} object represents
* and returns the number of bytes written.
* Writing starts at position <code>pos</code> in the <code>BLOB</code>
* value; <i>len</i> bytes from the given byte array are written.
* Writing starts at position {@code pos} in the {@code BLOB}
* value; {@code length} bytes from the given byte array are written.
*
* @param pos the position in the <code>BLOB</code> object at which
* to start writing. The first position is <code>1</code>;
* must not be less than <code>1</code> nor greater than
* the length of this <code>SerialBlob</code> object.
* @param bytes the array of bytes to be written to the <code>BLOB</code>
* @param pos the position in the {@code BLOB} object at which
* to start writing. The first position is {@code 1};
* must not be less than {@code 1} nor greater than
* the length+1 of this {@code SerialBlob} object.
* @param bytes the array of bytes to be written to the {@code BLOB}
* value
* @param offset the offset in the <code>byte</code> array at which
* to start reading the bytes. The first offset position is
* <code>0</code>; must not be less than <code>0</code> nor greater
* than the length of the <code>byte</code> array
* @param offset the offset into the array {@code byte}s at which
* to start reading the bytes to be set. The first offset position is
* {@code 0}; must not be less than {@code 0} nor greater
* than the length of the array {@code byte}s
* @param length the number of bytes to be written to the
* <code>BLOB</code> value from the array of bytes <i>bytes</i>.
* {@code BLOB} value from the array of bytes {@code byte}s
*
* @return the number of bytes written
* @throws SerialException if there is an error accessing the
* <code>BLOB</code> value; if an invalid position is set; if an
* invalid offset value is set; if number of bytes to be written
* is greater than the <code>SerialBlob</code> length; or the combined
* values of the length and offset is greater than the Blob buffer;
* {@code BLOB} value; if an invalid position is set; if an
* invalid offset value is set; or the combined values of the
* {@code length} and {@code offset} is greater than the length of
* {@code byte}s;
* if {@code free} had previously been called on this object
* @throws SQLException if there is an error accessing the <code>BLOB</code>
* @throws SQLException if there is an error accessing the {@code BLOB}
* value from the database.
* @see #getBytes
*/
@ -361,26 +360,34 @@ public class SerialBlob implements Blob, Serializable, Cloneable {
throw new SerialException("Invalid offset in byte array set");
}
if (pos < 1 || pos > this.length()) {
if (length < 0) {
throw new SerialException("Invalid arguments: length cannot be "
+ "negative");
}
if (pos < 1 || pos > len + 1) {
throw new SerialException("Invalid position in BLOB object set");
}
if ((long)(length) > origLen) {
throw new SerialException("Buffer is not sufficient to hold the value");
}
if ((length + offset) > bytes.length) {
if (length > bytes.length - offset) {
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
"and length that is greater that the Blob buffer");
"and length that is greater than the length of bytes");
}
int i = 0;
pos--; // correct to array indexing
while ( i < length || (offset + i +1) < (bytes.length-offset) ) {
this.buf[(int)pos + i] = bytes[offset + i ];
i++;
if (pos - 1 + length > Integer.MAX_VALUE) {
throw new SerialException("Invalid length. Cannot have combined pos " +
"and length that is greater than Integer.MAX_VALUE");
}
return i;
pos--; // correct to array indexing
if (pos + length > len) {
len = pos + length;
byte[] newbuf = new byte[(int)len];
System.arraycopy(buf, 0, newbuf, 0, (int)pos);
buf = newbuf;
}
System.arraycopy(bytes, offset, buf, (int)pos, length);
return length;
}
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -361,22 +361,19 @@ public class SerialClob implements Clob, Serializable, Cloneable {
}
/**
* Writes the given Java <code>String</code> to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents, at the position
* <code>pos</code>.
* Writes the given Java {@code String} to the {@code CLOB}
* value that this {@code SerialClob} object represents, at the position
* {@code pos}.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents; the first
* position is <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents
* @param pos the position at which to start writing to the {@code CLOB}
* value that this {@code SerialClob} object represents; the first
* position is {@code 1}; must not be less than {@code 1} nor
* greater than the length+1 of this {@code SerialClob} object
* @param str the string to be written to the {@code CLOB}
* value that this {@code SerialClob} object represents
* @return the number of characters written
* @throws SerialException if there is an error accessing the
* <code>CLOB</code> value; if an invalid position is set; if an
* invalid offset value is set; if number of bytes to be written
* is greater than the <code>SerialClob</code> length; or the combined
* values of the length and offset is greater than the Clob buffer;
* {@code CLOB} value; if an invalid position is set;
* if the {@code free} method had been previously called on this object
*/
public int setString(long pos, String str) throws SerialException {
@ -384,58 +381,66 @@ public class SerialClob implements Clob, Serializable, Cloneable {
}
/**
* Writes <code>len</code> characters of <code>str</code>, starting
* at character <code>offset</code>, to the <code>CLOB</code> value
* that this <code>Clob</code> represents.
* Writes {@code len} characters of {@code str}, starting
* at character {@code offset}, to the {@code CLOB} value
* that this {@code Clob} represents.
*
* @param pos the position at which to start writing to the <code>CLOB</code>
* value that this <code>SerialClob</code> object represents; the first
* position is <code>1</code>; must not be less than <code>1</code> nor
* greater than the length of this <code>SerialClob</code> object
* @param str the string to be written to the <code>CLOB</code>
* value that this <code>Clob</code> object represents
* @param offset the offset into <code>str</code> to start reading
* @param pos the position at which to start writing to the {@code CLOB}
* value that this {@code SerialClob} object represents; the first
* position is {@code 1}; must not be less than {@code 1} nor
* greater than the length+1 of this {@code SerialClob} object
* @param str the string to be written to the {@code CLOB}
* value that this {@code Clob} object represents
* @param offset the offset into {@code str} to start reading
* the characters to be written
* @param length the number of characters to be written
* @return the number of characters written
* @throws SerialException if there is an error accessing the
* <code>CLOB</code> value; if an invalid position is set; if an
* invalid offset value is set; if number of bytes to be written
* is greater than the <code>SerialClob</code> length; or the combined
* values of the length and offset is greater than the Clob buffer;
* {@code CLOB} value; if an invalid position is set; if an
* invalid offset value is set; or the combined values of the
* {@code length} and {@code offset} is greater than the length of
* {@code str};
* if the {@code free} method had been previously called on this object
*/
public int setString(long pos, String str, int offset, int length)
throws SerialException {
isValid();
String temp = str.substring(offset);
char cPattern[] = temp.toCharArray();
if (offset < 0 || offset > str.length()) {
throw new SerialException("Invalid offset in byte array set");
throw new SerialException("Invalid offset in String object set");
}
if (pos < 1 || pos > this.length()) {
if (length < 0) {
throw new SerialException("Invalid arguments: length cannot be "
+ "negative");
}
if (pos < 1 || pos > len + 1) {
throw new SerialException("Invalid position in Clob object set");
}
if ((long)(length) > origLen) {
throw new SerialException("Buffer is not sufficient to hold the value");
}
if ((length + offset) > str.length()) {
// need check to ensure length + offset !> bytes.length
if (length > str.length() - offset) {
// need check to ensure length + offset !> str.length
throw new SerialException("Invalid OffSet. Cannot have combined offset " +
" and length that is greater that the Blob buffer");
" and length that is greater than the length of str");
}
int i = 0;
pos--; //values in the array are at position one less
while ( i < length || (offset + i +1) < (str.length() - offset ) ) {
this.buf[(int)pos + i ] = cPattern[offset + i ];
i++;
if (pos - 1 + length > Integer.MAX_VALUE) {
throw new SerialException("Invalid length. Cannot have combined pos " +
"and length that is greater than Integer.MAX_VALUE");
}
return i;
pos--; //values in the array are at position one less
if (pos + length > len) {
len = pos + length;
char[] newbuf = new char[(int)len];
System.arraycopy(buf, 0, newbuf, 0, (int)pos);
buf = newbuf;
}
String temp = str.substring(offset, offset + length);
char cPattern[] = temp.toCharArray();
System.arraycopy(cPattern, 0, buf, (int)pos, length);
return length;
}
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -396,4 +396,78 @@ public class SerialBlobTests extends BaseTest {
long pos = sb.position(pattern, 2);
assertEquals(pos, expectedPos);
}
/*
* Validate that setBytes will properly write a set of bytes to the
* specified location in the SerialBlob and the correct count is returned
* for bytes written (writePos - 1 + diff.length > sb.length() &&
* writePos - 1 + bytesToWrite <= sb.length())
*/
@Test
public void test31() throws Exception {
int writePos = 5;
int bytesToWrite = 1;
byte[] diff = new byte[]{7, 8, 9};
byte[] expected = new byte[]{1, 2, 3, 4, 7};
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(writePos, diff, 0, bytesToWrite);
assertEquals(written, bytesToWrite);
assertEquals(sb.getBytes(1, (int) sb.length()), expected);
}
/*
* Validate that setBytes will properly write a set of bytes to the
* specified location in the SerialBlob and the correct count is returned
* for bytes written (writePos - 1 + bytesToWrite > sb.length())
*/
@Test
public void test32() throws Exception {
int writePos = 5;
int bytesToWrite = 2;
byte[] diff = new byte[]{7, 8, 9, 0};
byte[] expected = new byte[]{1, 2, 3, 4, 8, 9};
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(writePos, diff, 1, bytesToWrite);
assertEquals(written, bytesToWrite);
assertEquals(sb.getBytes(1, (int) sb.length()), expected);
}
/*
* Validate that setBytes will properly write a set of bytes to the
* specified location in the SerialBlob and the correct count is returned
* for bytes written (writePos == sb.length() + 1)
*/
@Test
public void test33() throws Exception {
int writePos = 6;
int bytesToWrite = 3;
byte[] diff = new byte[]{7, 8, 9, 0};
byte[] expected = new byte[]{1, 2, 3, 4, 5, 8, 9, 0};
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(writePos, diff, 1, bytesToWrite);
assertEquals(written, bytesToWrite);
assertEquals(sb.getBytes(1, (int) sb.length()), expected);
}
/*
* Validate a SerialException is thrown if length < 0 for setBytes
*/
@Test(expectedExceptions = SerialException.class)
public void test34() throws Exception {
int length = -1;
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(1, new byte[]{1}, 1, length);
}
/*
* Validate a SerialException is thrown if length + offset >
* Integer.MAX_VALUE for setBytes
*/
@Test(expectedExceptions = SerialException.class)
public void test35() throws Exception {
int offset = 1;
int length = Integer.MAX_VALUE;
SerialBlob sb = new SerialBlob(bytes);
int written = sb.setBytes(1, new byte[]{1, 2, 3}, offset, length);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -407,18 +407,21 @@ public class SerialClobTests extends BaseTest {
/*
* Check that setString() updates the appropriate characters in the
* SerialClob
* SerialClob (writePos - 1 + val1.length() - offset > sc.length() &&
* writePos - 1 + expectedWritten <= sc.length())
*/
@Test(enabled = false)
@Test
public void test32() throws Exception {
int writePos = 10;
int offset = 7;
int expectedWritten = 9;
String val = "Hi, I am Catwoman!!!!!!";
String val1 = "Hahaha the Joker, who are you?!";
String expected = "Hi, I am the Joker!";
String expected = "Hi, I am the Joker!!!!!";
SerialClob sc = new SerialClob(val.toCharArray());
int written = sc.setString(10, val1, 8, expectedWritten+1);
int written = sc.setString(writePos, val1, offset, expectedWritten);
assertEquals(written, expectedWritten);
assertEquals(sc.getSubString(1, (int) sc.length()), expected);
}
/*
@ -496,4 +499,74 @@ public class SerialClobTests extends BaseTest {
SerialClob sc2 = serializeDeserializeObject(sc);
assertTrue(sc.equals(sc2), "SerialClobs not equal");
}
/*
* Check calling setString() with offset > val1.length() throws a
* SerialException
*/
@Test(expectedExceptions = SerialException.class)
public void test39() throws Exception {
String val1 = "hello";
int offset = val1.length() + 1;
SerialClob sc = new SerialClob(chars);
sc.setString(1, val1, offset, 0);
}
/*
* Check that setString() updates the appropriate characters in the
* SerialClob (writePos - 1 + expectedWritten > sc.length())
*/
@Test
public void test40() throws Exception {
int writePos = 13;
int offset = 7;
int expectedWritten = 24;
String val = "Hello, I am Bruce Wayne";
String val1 = "Hahaha the Joker, who are you?!";
String expected = "Hello, I am the Joker, who are you?!";
SerialClob sc = new SerialClob(val.toCharArray());
int written = sc.setString(writePos, val1, offset, expectedWritten);
assertEquals(written, expectedWritten);
assertEquals(sc.getSubString(1, (int) sc.length()), expected);
}
/*
* Check that setString() updates the appropriate characters in the
* SerialClob (writePos == sc.length() + 1)
*/
@Test
public void test41() throws Exception {
int writePos = 10;
int offset = 7;
int expectedWritten = 10;
String val = "Hi, I am ";
String val1 = "Hahaha the Joker!";
String expected = "Hi, I am the Joker!";
SerialClob sc = new SerialClob(val.toCharArray());
int written = sc.setString(writePos, val1, offset, expectedWritten);
assertEquals(written, expectedWritten);
assertEquals(sc.getSubString(1, (int) sc.length()), expected);
}
/*
* Validate a SerialException is thrown if length < 0 for setString
*/
@Test(expectedExceptions = SerialException.class)
public void test42() throws Exception {
int length = -1;
SerialClob sc = new SerialClob(chars);
int written = sc.setString(1, "hello", 1, length);
}
/*
* Validate a SerialException is thrown if length + offset >
* Integer.MAX_VALUE for setString
*/
@Test(expectedExceptions = SerialException.class)
public void test43() throws Exception {
int offset = 1;
int length = Integer.MAX_VALUE;
SerialClob sc = new SerialClob(chars);
int written = sc.setString(1, "hello", offset, length);
}
}