It has been found that while testing in an IPv6 only environment on Windows i.e. a system on which the command " netsh interface ipv4 uninstall" has been executed to disable IPv4 stack functionality, that a simple sanity check which executes the InetAddress.getLoopbackAddress results in the program silently crashing.
This has been found to be due to a local pointer variable not being properly initialised, and it being subsequently freed in the NetworkInterface.c code
functions:
Java_java_net_NetworkInterface_boundInetAddress0
MIB_IPADDRTABLE *tableP;
if ((lookupIPAddrTable(env, &tableP) >= 0) && (tableP != NULL)) {
for (i = 0; i < tableP->dwNumEntries; i++) {
if (tableP->table[i].dwAddr != 0 &&
(unsigned long)addr == ntohl(tableP->table[i].dwAddr)) {
found = JNI_TRUE;
break;
}
}
}
if (tableP != NULL) {
free(tableP);
}
Note tableP is not initialised to NULL and is a local variable, therefore its initial value is determined by what's on the stack. As such, it would be appropriate to initialise tableP to NULL
MIB_IPADDRTABLE *tableP = NULL;
lookupIPAddrTable - sanitise tablePP return value (NULL) for error cases
int lookupIPAddrTable(JNIEnv *env, MIB_IPADDRTABLE **tablePP)
{
MIB_IPADDRTABLE *tableP;
ULONG size;
DWORD ret;
/*
* Use GetIpAddrTable to enumerate the IP Addresses
*/
size = sizeof(MIB_IPADDRTABLE);
tableP = (MIB_IPADDRTABLE *)malloc(size);
if (tableP == NULL) {
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
// SHOULD ADD have *tablePP = NULL;
return -1;
}
ret = GetIpAddrTable(tableP, &size, FALSE);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
MIB_IPADDRTABLE * newTableP = (MIB_IPADDRTABLE *)realloc(tableP, size);
if (newTableP == NULL) {
free(tableP);
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
// SHOULD ADD have *tablePP = NULL;
return -1;
}
tableP = newTableP;
ret = GetIpAddrTable(tableP, &size, FALSE);
}
if (ret != NO_ERROR) {
if (tableP != NULL) {
free(tableP);
}
switch (ret) {
case ERROR_INVALID_PARAMETER:
JNU_ThrowInternalError(env,
"IP Helper Library GetIpAddrTable function failed: "
"invalid parameter");
break;
default:
SetLastError(ret);
JNU_ThrowByNameWithMessageAndLastError(env,
JNU_JAVANETPKG "SocketException",
"IP Helper Library GetIpAddrTable function failed");
break;
}
// this different error code is to handle the case when we call
// GetIpAddrTable in pure IPv6 environment
// SHOULD ADD have *tablePP = NULL;
return -2;
}
*tablePP = tableP;
return 0;
}
Note that in lookupIPAddrTable a that the out parameter tablePP is assigned only for a successful return, all error returns leave the variable in its initial inout state.
This has been found to be due to a local pointer variable not being properly initialised, and it being subsequently freed in the NetworkInterface.c code
functions:
Java_java_net_NetworkInterface_boundInetAddress0
MIB_IPADDRTABLE *tableP;
if ((lookupIPAddrTable(env, &tableP) >= 0) && (tableP != NULL)) {
for (i = 0; i < tableP->dwNumEntries; i++) {
if (tableP->table[i].dwAddr != 0 &&
(unsigned long)addr == ntohl(tableP->table[i].dwAddr)) {
found = JNI_TRUE;
break;
}
}
}
if (tableP != NULL) {
free(tableP);
}
Note tableP is not initialised to NULL and is a local variable, therefore its initial value is determined by what's on the stack. As such, it would be appropriate to initialise tableP to NULL
MIB_IPADDRTABLE *tableP = NULL;
lookupIPAddrTable - sanitise tablePP return value (NULL) for error cases
int lookupIPAddrTable(JNIEnv *env, MIB_IPADDRTABLE **tablePP)
{
MIB_IPADDRTABLE *tableP;
ULONG size;
DWORD ret;
/*
* Use GetIpAddrTable to enumerate the IP Addresses
*/
size = sizeof(MIB_IPADDRTABLE);
tableP = (MIB_IPADDRTABLE *)malloc(size);
if (tableP == NULL) {
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
// SHOULD ADD have *tablePP = NULL;
return -1;
}
ret = GetIpAddrTable(tableP, &size, FALSE);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
MIB_IPADDRTABLE * newTableP = (MIB_IPADDRTABLE *)realloc(tableP, size);
if (newTableP == NULL) {
free(tableP);
JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
// SHOULD ADD have *tablePP = NULL;
return -1;
}
tableP = newTableP;
ret = GetIpAddrTable(tableP, &size, FALSE);
}
if (ret != NO_ERROR) {
if (tableP != NULL) {
free(tableP);
}
switch (ret) {
case ERROR_INVALID_PARAMETER:
JNU_ThrowInternalError(env,
"IP Helper Library GetIpAddrTable function failed: "
"invalid parameter");
break;
default:
SetLastError(ret);
JNU_ThrowByNameWithMessageAndLastError(env,
JNU_JAVANETPKG "SocketException",
"IP Helper Library GetIpAddrTable function failed");
break;
}
// this different error code is to handle the case when we call
// GetIpAddrTable in pure IPv6 environment
// SHOULD ADD have *tablePP = NULL;
return -2;
}
*tablePP = tableP;
return 0;
}
Note that in lookupIPAddrTable a that the out parameter tablePP is assigned only for a successful return, all error returns leave the variable in its initial inout state.
- duplicates
-
JDK-8275640 (win) java.net.NetworkInterface issues with IPv6-only environments
- Resolved
- relates to
-
JDK-8279329 Remove hardcoded IPv4 available policy on Windows
- Resolved