7021373: DatagramPacket exception conditions are not clear

Specification is clarified by adding or clarifying @throws clauses where required

Reviewed-by: alanb, chegar, darcy, dfuchs
This commit is contained in:
Patrick Concannon 2020-02-07 11:10:41 +00:00
parent 38f0c08ee0
commit 00c40ae1e3
3 changed files with 323 additions and 170 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -35,6 +35,16 @@ package java.net;
* differently, and might arrive in any order. Packet delivery is * differently, and might arrive in any order. Packet delivery is
* not guaranteed. * not guaranteed.
* *
* <p>
* Unless otherwise specified, passing a {@code null} argument causes
* a {@link NullPointerException NullPointerException} to be thrown.
*
* <p>
* Methods and constructors of {@code DatagramPacket} accept parameters
* of type {@link SocketAddress}. {@code DatagramPacket} supports
* {@link InetSocketAddress}, and may support additional {@code SocketAddress}
* sub-types.
*
* @author Pavani Diwanji * @author Pavani Diwanji
* @author Benjamin Renaud * @author Benjamin Renaud
* @since 1.0 * @since 1.0
@ -68,11 +78,15 @@ class DatagramPacket {
* The {@code length} argument must be less than or equal to * The {@code length} argument must be less than or equal to
* {@code buf.length}. * {@code buf.length}.
* *
* @param buf buffer for holding the incoming datagram. * @param buf buffer for holding the incoming datagram.
* @param offset the offset for the buffer * @param offset the offset for the buffer
* @param length the number of bytes to read. * @param length the number of bytes to read.
* *
* @since 1.2 * @throws IllegalArgumentException if the length or offset
* is negative, or if the length plus the offset is
* greater than the length of the packet's given buffer.
*
* @since 1.2
*/ */
public DatagramPacket(byte buf[], int offset, int length) { public DatagramPacket(byte buf[], int offset, int length) {
setData(buf, offset, length); setData(buf, offset, length);
@ -87,8 +101,12 @@ class DatagramPacket {
* The {@code length} argument must be less than or equal to * The {@code length} argument must be less than or equal to
* {@code buf.length}. * {@code buf.length}.
* *
* @param buf buffer for holding the incoming datagram. * @param buf buffer for holding the incoming datagram.
* @param length the number of bytes to read. * @param length the number of bytes to read.
*
* @throws IllegalArgumentException if the length is negative
* or if the length is greater than the length of the
* packet's given buffer.
*/ */
public DatagramPacket(byte buf[], int length) { public DatagramPacket(byte buf[], int length) {
this (buf, 0, length); this (buf, 0, length);
@ -101,14 +119,20 @@ class DatagramPacket {
* {@code length} argument must be less than or equal to * {@code length} argument must be less than or equal to
* {@code buf.length}. * {@code buf.length}.
* *
* @param buf the packet data. * @param buf the packet data.
* @param offset the packet data offset. * @param offset the packet data offset.
* @param length the packet data length. * @param length the packet data length.
* @param address the destination address. * @param address the destination address, or {@code null}.
* @param port the destination port number. * @param port the destination port number.
* @see java.net.InetAddress
* *
* @since 1.2 * @throws IllegalArgumentException if the length or offset
* is negative, or if the length plus the offset is
* greater than the length of the packet's given buffer,
* or if the port is out of range.
*
* @see java.net.InetAddress
*
* @since 1.2
*/ */
public DatagramPacket(byte buf[], int offset, int length, public DatagramPacket(byte buf[], int offset, int length,
InetAddress address, int port) { InetAddress address, int port) {
@ -124,14 +148,19 @@ class DatagramPacket {
* {@code length} argument must be less than or equal to * {@code length} argument must be less than or equal to
* {@code buf.length}. * {@code buf.length}.
* *
* @param buf the packet data. * @param buf the packet data.
* @param offset the packet data offset. * @param offset the packet data offset.
* @param length the packet data length. * @param length the packet data length.
* @param address the destination socket address. * @param address the destination socket address.
* @throws IllegalArgumentException if address type is not supported
* @see java.net.InetAddress
* *
* @since 1.4 * @throws IllegalArgumentException if address is null or its
* type is not supported, or if the length or offset is
* negative, or if the length plus the offset is greater
* than the length of the packet's given buffer.
*
* @see java.net.InetAddress
*
* @since 1.4
*/ */
public DatagramPacket(byte buf[], int offset, int length, SocketAddress address) { public DatagramPacket(byte buf[], int offset, int length, SocketAddress address) {
setData(buf, offset, length); setData(buf, offset, length);
@ -144,10 +173,15 @@ class DatagramPacket {
* host. The {@code length} argument must be less than or equal * host. The {@code length} argument must be less than or equal
* to {@code buf.length}. * to {@code buf.length}.
* *
* @param buf the packet data. * @param buf the packet data.
* @param length the packet length. * @param length the packet length.
* @param address the destination address. * @param address the destination address, or {@code null}.
* @param port the destination port number. * @param port the destination port number.
*
* @throws IllegalArgumentException if the length is negative,
* or if the length is greater than the length of the
* packet's given buffer, or if the port is out of range.
*
* @see java.net.InetAddress * @see java.net.InetAddress
*/ */
public DatagramPacket(byte buf[], int length, public DatagramPacket(byte buf[], int length,
@ -161,12 +195,18 @@ class DatagramPacket {
* host. The {@code length} argument must be less than or equal * host. The {@code length} argument must be less than or equal
* to {@code buf.length}. * to {@code buf.length}.
* *
* @param buf the packet data. * @param buf the packet data.
* @param length the packet length. * @param length the packet length.
* @param address the destination address. * @param address the destination address.
* @throws IllegalArgumentException if address type is not supported *
* @since 1.4 * @throws IllegalArgumentException if address is null or its type is
* not supported, or if the length is negative, or if the length
* is greater than the length of the packet's given buffer, or
* if the port is out of range.
*
* @see java.net.InetAddress * @see java.net.InetAddress
*
* @since 1.4
*/ */
public DatagramPacket(byte buf[], int length, SocketAddress address) { public DatagramPacket(byte buf[], int length, SocketAddress address) {
this(buf, 0, length, address); this(buf, 0, length, address);
@ -238,20 +278,20 @@ class DatagramPacket {
* Set the data buffer for this packet. This sets the * Set the data buffer for this packet. This sets the
* data, length and offset of the packet. * data, length and offset of the packet.
* *
* @param buf the buffer to set for this packet * @param buf the buffer to set for this packet
* @param offset the offset into the data
* @param length the length of the data
* and/or the length of the buffer used to receive data
* *
* @param offset the offset into the data * @throws IllegalArgumentException if the length or offset
* is negative, or if the length plus the offset is
* greater than the length of the packet's given buffer.
* *
* @param length the length of the data * @see #getData
* and/or the length of the buffer used to receive data * @see #getOffset
* @see #getLength
* *
* @throws NullPointerException if the argument is null * @since 1.2
*
* @see #getData
* @see #getOffset
* @see #getLength
*
* @since 1.2
*/ */
public synchronized void setData(byte[] buf, int offset, int length) { public synchronized void setData(byte[] buf, int offset, int length) {
/* this will check to see if buf is null */ /* this will check to see if buf is null */
@ -269,9 +309,12 @@ class DatagramPacket {
/** /**
* Sets the IP address of the machine to which this datagram * Sets the IP address of the machine to which this datagram
* is being sent. * is being sent.
* @param iaddr the {@code InetAddress} *
* @param iaddr the {@code InetAddress}, or {@code null}.
*
* @see #getAddress()
*
* @since 1.1 * @since 1.1
* @see #getAddress()
*/ */
public synchronized void setAddress(InetAddress iaddr) { public synchronized void setAddress(InetAddress iaddr) {
address = iaddr; address = iaddr;
@ -280,9 +323,14 @@ class DatagramPacket {
/** /**
* Sets the port number on the remote host to which this datagram * Sets the port number on the remote host to which this datagram
* is being sent. * is being sent.
* @param iport the port number *
* @param iport the port number
*
* @throws IllegalArgumentException if the port is out of range
*
* @see #getPort()
*
* @since 1.1 * @since 1.1
* @see #getPort()
*/ */
public synchronized void setPort(int iport) { public synchronized void setPort(int iport) {
if (iport < 0 || iport > 0xFFFF) { if (iport < 0 || iport > 0xFFFF) {
@ -295,12 +343,14 @@ class DatagramPacket {
* Sets the SocketAddress (usually IP address + port number) of the remote * Sets the SocketAddress (usually IP address + port number) of the remote
* host to which this datagram is being sent. * host to which this datagram is being sent.
* *
* @param address the {@code SocketAddress} * @param address the {@code SocketAddress}
* @throws IllegalArgumentException if address is null or is a
* SocketAddress subclass not supported by this socket
* *
* @since 1.4 * @throws IllegalArgumentException if address is null or is a
* @see #getSocketAddress * SocketAddress subclass not supported.
*
* @see #getSocketAddress
*
* @since 1.4
*/ */
public synchronized void setSocketAddress(SocketAddress address) { public synchronized void setSocketAddress(SocketAddress address) {
if (address == null || !(address instanceof InetSocketAddress)) if (address == null || !(address instanceof InetSocketAddress))
@ -316,9 +366,11 @@ class DatagramPacket {
* Gets the SocketAddress (usually IP address + port number) of the remote * Gets the SocketAddress (usually IP address + port number) of the remote
* host that this packet is being sent to or is coming from. * host that this packet is being sent to or is coming from.
* *
* @return the {@code SocketAddress} * @return the {@code SocketAddress}
* @since 1.4 *
* @see #setSocketAddress * @see #setSocketAddress
*
* @since 1.4
*/ */
public synchronized SocketAddress getSocketAddress() { public synchronized SocketAddress getSocketAddress() {
return new InetSocketAddress(getAddress(), getPort()); return new InetSocketAddress(getAddress(), getPort());
@ -329,14 +381,12 @@ class DatagramPacket {
* this DatagramPacket set to 0, and the length set to * this DatagramPacket set to 0, and the length set to
* the length of {@code buf}. * the length of {@code buf}.
* *
* @param buf the buffer to set for this packet. * @param buf the buffer to set for this packet.
* *
* @throws NullPointerException if the argument is null. * @see #getLength
* @see #getData
* *
* @see #getLength * @since 1.1
* @see #getData
*
* @since 1.1
*/ */
public synchronized void setData(byte[] buf) { public synchronized void setData(byte[] buf) {
if (buf == null) { if (buf == null) {
@ -355,16 +405,16 @@ class DatagramPacket {
* will be used for receiving data. The length must be lesser or * will be used for receiving data. The length must be lesser or
* equal to the offset plus the length of the packet's buffer. * equal to the offset plus the length of the packet's buffer.
* *
* @param length the length to set for this packet. * @param length the length to set for this packet.
* *
* @throws IllegalArgumentException if the length is negative * @throws IllegalArgumentException if the length is negative,
* of if the length is greater than the packet's data buffer * or if the length plus the offset is greater than the
* length. * length of the packet's data buffer.
* *
* @see #getLength * @see #getLength
* @see #setData * @see #setData
* *
* @since 1.1 * @since 1.1
*/ */
public synchronized void setLength(int length) { public synchronized void setLength(int length) {
if ((length + offset) > buf.length || length < 0 || if ((length + offset) > buf.length || length < 0 ||

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -22,130 +22,98 @@
*/ */
/* @test /* @test
* * @bug 4091803 7021373
* @bug 4091803
*
* @summary this tests that the constructor of DatagramPacket rejects * @summary this tests that the constructor of DatagramPacket rejects
* bogus arguments properly. * bogus arguments properly.
* * @run testng Constructor
* @author Benjamin Renaud
*/ */
import java.io.*;
import java.net.*; import java.net.DatagramPacket;
import java.util.*; import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.testng.annotations.Test;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.expectThrows;
public class Constructor { public class Constructor {
public static void main(String[] args) throws Exception { private static final byte[] buf = new byte[128];
testNullPacket();
testNegativeBufferLength(); private static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress();
testPacketLengthTooLarge(); private static final Class<NullPointerException> NPE = NullPointerException.class;
testNegativePortValue(); private static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
testPortValueTooLarge();
testSimpleConstructor(); @Test
testFullConstructor(); public void testNullPacket() {
System.err.println("all passed!"); expectThrows(NPE,
() -> new DatagramPacket(null, 100));
}
@Test
public void testNull() throws Exception {
expectThrows(NPE, () -> new DatagramPacket(null, 100));
expectThrows(NPE, () -> new DatagramPacket(null, 0, 10));
expectThrows(NPE, () -> new DatagramPacket(null, 0, 10, LOOPBACK, 80));
expectThrows(NPE, () -> new DatagramPacket(null, 10, LOOPBACK, 80));
expectThrows(NPE, () -> new DatagramPacket(null, 0, 10, new InetSocketAddress(80)));
expectThrows(NPE, () -> new DatagramPacket(null, 10, new InetSocketAddress(80)));
// no Exception expected for null addresses
new DatagramPacket(buf, 10, null, 0);
new DatagramPacket(buf, 10, 10, null, 0);
} }
static void testNullPacket() throws Exception { @Test
boolean error = true; public void testNegativeBufferLength() {
try { /* length lesser than buffer length */
new DatagramPacket(null, 100); expectThrows(IAE,
} catch (NullPointerException e) { () -> new DatagramPacket(buf, -128));
/* correct exception */
error = false;
}
if (error) {
throw new RuntimeException("test 1 failed.");
}
} }
static void testNegativeBufferLength() throws Exception { @Test
boolean error = true; public void testPacketLengthTooLarge() {
byte[] buf = new byte[128]; /* length greater than buffer length */
try { expectThrows(IAE,
/* length lesser than buffer length */ () -> new DatagramPacket(buf, 256));
new DatagramPacket(buf, -128);
} catch (IllegalArgumentException e) {
/* correct exception */
error = false;
}
if (error) {
throw new RuntimeException("test 2 failed.");
}
} }
static void testPacketLengthTooLarge() throws Exception { @Test
boolean error = true; public void testNegativePortValue() throws Exception {
byte[] buf = new byte[128]; /* negative port */
try { InetAddress addr = InetAddress.getLocalHost();
/* length greater than buffer length */
new DatagramPacket(buf, 256); expectThrows(IAE,
} catch (IllegalArgumentException e) { () -> new DatagramPacket(buf, 100, addr, -1));
/* correct exception */
error = false;
}
if (error) {
throw new RuntimeException("test 3 failed.");
}
} }
static void testNegativePortValue() throws Exception { @Test
boolean error = true; public void testPortValueTooLarge() {
byte[] buf = new byte[128]; /* invalid port value */
InetAddress host = InetAddress.getLocalHost(); expectThrows(IAE,
try { () -> new DatagramPacket(buf, 128, LOOPBACK, Integer.MAX_VALUE));
/* negative port */
new DatagramPacket(buf, 100, host, -1);
} catch (IllegalArgumentException e) {
/* correct exception */
error = false;
}
if (error) {
throw new RuntimeException("test 5 failed.");
}
} }
static void testPortValueTooLarge() throws Exception { @Test
boolean error = true; public void testSimpleConstructor() {
byte[] buf = new byte[256];
InetAddress address = InetAddress.getLocalHost();
try {
/* invalid port value */
new DatagramPacket(buf, 256, address, Integer.MAX_VALUE);
} catch (IllegalArgumentException e) {
/* correct exception */
error = false;
}
if (error) {
throw new RuntimeException("test 6 failed.");
}
}
static void testSimpleConstructor() {
byte[] buf = new byte[128];
int offset = 10; int offset = 10;
int length = 50; int length = 50;
DatagramPacket packet = new DatagramPacket(buf, offset, length); DatagramPacket pkt = new DatagramPacket(buf, offset, length);
if (packet.getData() != buf || packet.getOffset() != offset ||
packet.getLength() != length) { assertFalse((pkt.getData() != buf || pkt.getOffset() != offset ||
throw new RuntimeException("simple constructor failed"); pkt.getLength() != length), "simple constructor failed");
}
} }
static void testFullConstructor() throws Exception { @Test
byte[] buf = new byte[128]; public void testFullConstructor() {
int offset = 10; int offset = 10;
int length = 50; int length = 50;
InetAddress address = InetAddress.getLocalHost();
int port = 8080; int port = 8080;
DatagramPacket packet = new DatagramPacket(buf, offset, length, DatagramPacket packet = new DatagramPacket(buf, offset, length, LOOPBACK, port);
address, port);
if (packet.getData() != buf || packet.getOffset() != offset || assertFalse((packet.getData() != buf || packet.getOffset() != offset ||
packet.getLength() != length || packet.getLength() != length ||
packet.getAddress() != address || packet.getAddress() != LOOPBACK ||
packet.getPort() != port) { packet.getPort() != port), "full constructor failed");
throw new RuntimeException("full constructor failed");
}
} }
} }

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2020, 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 7021373
* @summary check that the DatagramPacket setter methods
* throw the correct exceptions
* @run testng Setters
*/
import java.net.DatagramPacket;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
public class Setters {
private static final byte[] buf = new byte[128];
private static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
private static final Class<NullPointerException> NPE = NullPointerException.class;
@Test
public void testSetAddress() throws Exception {
DatagramPacket pkt = new DatagramPacket(buf, 8);
// No Exception expected for null addresses
pkt.setAddress(null);
assertTrue(pkt.getAddress() == null);
}
@DataProvider
Object[][] data() { // add checks for setAddress with null - add getAddress to verify
return new Object[][]{
{ buf, 0, -1, IAE },
{ buf, -1, 1, IAE },
{ buf, 128, 128, IAE },
{ null, 0, 0, NPE },
{ new byte[8], 2, 2, null },
{ buf, 2, 2, null },
{ buf, 20, 20, null },
};
}
@Test(dataProvider = "data")
public void testSetData(byte[] buf,
int offset,
int length,
Class<? extends Exception> exception) {
DatagramPacket pkt = new DatagramPacket(new byte[8], 8);
if (exception != null) {
expectThrows(exception, () -> pkt.setData(buf, offset, length));
} else if (buf == null) {
expectThrows(exception, () -> pkt.setData(buf));
} else {
pkt.setData(buf, offset, length);
}
}
@DataProvider
Object[][] lengths() {
return new Object[][]{
{ 0, -1, IAE },
{ 8, 1, IAE },
{ 4, -2, IAE },
{ 0, 9, IAE },
{ 2, 2, null },
{ 4, 4, null }
};
}
@Test(dataProvider = "lengths")
public void testSetLength(int offset, int length,
Class<? extends Exception> exception) {
DatagramPacket pkt = new DatagramPacket(new byte[8], offset, 0);
if (exception != null) {
expectThrows(exception, () -> pkt.setLength(length));
} else {
pkt.setLength(length);
}
}
@DataProvider
Object[][] ports() {
return new Object[][]{
{ -1, IAE },
{ -666, IAE },
{ Integer.MAX_VALUE, IAE },
{ 0xFFFF + 1, IAE },
{ 0xFFFFFF, IAE },
{ 0, null },
{ 1, null },
{ 666, null },
{ 0xFFFE, null },
{ 0xFFFF, null },
};
}
@Test(dataProvider = "ports")
public void testSetPort(int port, Class<? extends Exception> exception) {
DatagramPacket pkt = new DatagramPacket(new byte[8], 0);
if (exception != null) {
expectThrows(exception, () -> pkt.setPort(port));
} else {
pkt.setPort(port);
}
}
}