Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #3708: javalib Inet6Address ipv6Address argumentsare now resistant to outside change. #3715

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 10 additions & 3 deletions javalib/src/main/scala/java/net/Inet6Address.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,11 @@ object Inet6Address {
* Explicitly specified 0 scopeIds are considered supplied.
* Elsewhere implicit 0 scopeIds, say from a sin6_scope_id, are not.
*/
val clonedAddr = addr.clone
if (scopeId < 0)
Inet6Address(addr, host)
Inet6Address(clonedAddr, host)
else
new Inet6Address(addr, host, true, scopeId, null)
new Inet6Address(clonedAddr, host, true, scopeId, null)
}

def getByAddress(
Expand All @@ -134,9 +135,15 @@ object Inet6Address {
* scopeId of 0.
*/

new Inet6Address(addr, host, false, 0, nif)
new Inet6Address(addr.clone, host, false, 0, nif)
}

/* All callers are under the control of java.net., so one can use the
* well performing but fragile convention that caller has provided addr
* bytes which not be mutated later. This means there need to pay the
* price of cloning bytes which have already been cloned (or
* carefully guarded).
*/
private[net] def apply(
addr: Array[Byte],
host: String
Expand Down
17 changes: 14 additions & 3 deletions javalib/src/main/scala/java/net/InetAddress.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,23 @@ class InetAddress protected (ipAddress: Array[Byte], originalHost: String)
if (obj == null || obj.getClass != this.getClass) {
false
} else {
val objIPAddress = obj.asInstanceOf[InetAddress].getAddress()
objIPAddress.indices.forall(i => objIPAddress(i) == ipAddress(i))
/* Both address bytes and hostname must be the same.
* This is stricter Java/Scala concept of equality.
*
* Scala Native has historically used a looser sense of
* comparing only address bytes and letting hostname differ.
*
* This is analogous to the difference between a case sensitive and
* insensitive test of strings. Each has its use case.
*
* Currently the looser comparison of InetAddress instances must be done
* manually.
*/
this.hashCode() == obj.asInstanceOf[InetAddress].hashCode()
}
}

def getAddress() = ipAddress.clone
def getAddress() = ipAddress.clone // Disallow outside change to arg contents

def getCanonicalHostName(): String = {
// reverse name lookup with cache
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.scalanative.testsuite.javalib.net

import java.io.IOException
import java.net.BindException
import java.net.DatagramPacket
import java.net.DatagramSocket
Expand All @@ -9,13 +10,12 @@ import java.net.NetworkInterface
import java.net.SocketAddress
import java.net.SocketException
import java.net.SocketTimeoutException
import java.{util => ju}

import org.junit.Test
import org.junit.Assert._
import org.junit.Assume._

import java.io.IOException

import org.scalanative.testsuite.utils.AssertThrows.assertThrows
import org.scalanative.testsuite.utils.Platform
import scala.collection.JavaConverters._
Expand Down Expand Up @@ -290,11 +290,16 @@ class DatagramSocketTest {
val remoteAddress =
result.getSocketAddress().asInstanceOf[InetSocketAddress]
assertEquals("Received incorrect data", data, receivedData)
assertEquals(

// Compare only address bytes, host names may vary (null, "", etc)
assertTrue(
"Received incorrect address",
ds1.getLocalAddress(),
remoteAddress.getAddress()
ju.Arrays.equals(
ds1.getLocalAddress().getAddress,
remoteAddress.getAddress().getAddress
)
)

assertEquals(
"Received incorrect port",
ds1.getLocalPort(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,51 @@ class Inet6AddressTest {
assertFalse("expected addr6_1 & addr6_3 to be !=", addr6_1 == addr6_3)
}

// Issue 3708
@Test def constructorIpAddressShouldBeImmutable(): Unit = {
val addrBytes = Array[Byte](
0xfe.toByte,
0x80.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0.toByte,
0x02.toByte,
0x11.toByte,
0x25.toByte,
0xff.toByte,
0xfe.toByte,
0xf8.toByte,
0x7c.toByte,
0xb2.toByte
)

val commonScopeId = 43 // Use an arbitrary non-zero positive number.

val addr6_1 = Inet6Address.getByAddress(null, addrBytes, commonScopeId)
val addr6_2 = Inet6Address.getByAddress(null, addrBytes, commonScopeId)

// Mutate common array. Pick an arbitrary index & arbitrary different value
val differentAddrBytes = addrBytes // mutate common array.
addrBytes(14) = 0xff.toByte
val addr6_3 =
Inet6Address.getByAddress(null, addrBytes, commonScopeId)

assertNotNull("addr6_1", addr6_1)
assertNotNull("addr6_2", addr6_2)
assertNotNull("addr6_3", addr6_3)

/* Careful here!
* See comment about difficulties using "assertEquals" &
* "assertNotEquals" with strings containing the '%' character
* in Test hashcodeShouldBeRobustToNullHostnames() above.
*/

assertTrue("expected addr6_1 & addr6_2 to be ==", addr6_1 == addr6_2)

assertFalse("expected addr6_1 & addr6_3 to be !=", addr6_1 == addr6_3)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,16 @@ class InetAddressTest {
val ia = InetAddress.getByName("127.0.0.1") // numeric lookup path

val ia2 = InetAddress.getByName("localhost") // non-numeric lookup path
assertEquals("a1", ia, ia2)

/* compare only address parts. host names may well differ because of
* the way the InternetAddresses were gotten.
* ia host should null or "". ia2 host should be "localhost".
*/
// assertEquals("a1", ia.getHostAddress(), ia2.getHostAddress)
assertTrue(
"ia and ia2 address bytes should be the same",
java.util.Arrays.equals(ia.getAddress(), ia2.getAddress())
)

// Test IPv4 archaic variant addresses.
val i1 = InetAddress.getByName("1.2.3")
Expand Down