JNA 分配缓冲区 FIXED_INFO 抛出无效内存访问
JNA allocate buffer FIXED_INFO throws Invalid memory access
我对 new FIXED_INFO(buffer) 进行了简单调用,导致 java.lang.Error:无效内存访问。我一辈子都弄不明白为什么会失败:
import com.sun.jna.platform.win32.IPHlpAPI;
import com.sun.jna.platform.win32.IPHlpAPI.FIXED_INFO;
public void fixedInfoTest() {
int bufferSize = 648;
Memory buffer = new Memory(bufferSize);
FIXED_INFO fixedInfo = new FIXED_INFO(buffer);
}
"new FIXED_INFO(buffer)" 调用引发异常。
java.lang.Error: Invalid memory access
at com.sun.jna.Native._getPointer(Native Method)
at com.sun.jna.Native.getPointer(Native.java:2211)
at com.sun.jna.Pointer.getPointer(Pointer.java:642)
at com.sun.jna.Pointer.getValue(Pointer.java:367)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.Structure.autoRead(Structure.java:2141)
at com.sun.jna.Structure.conditionalAutoRead(Structure.java:561)
at com.sun.jna.Structure.updateStructureByReference(Structure.java:690)
at com.sun.jna.Pointer.getValue(Pointer.java:367)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.platform.win32.IPHlpAPI$FIXED_INFO.<init>(IPHlpAPI.java:208)
at com.magnicomp.test.unit.WindowsNativeTest.fixedInfoTest(WindowsNativeTest.java:43)
上述测试有时确实有效,但经常失败。测试系统为Win 10, Win Server 2016. JNA version 5.4.0
在我的生产代码中,fixedInfo 用于:
IntByReference bufferSize = new IntByReference();
int result = IPHlpAPI.INSTANCE.GetNetworkParams(Pointer.NULL, bufferSize);
Validate.isTrue(result == WinNT.ERROR_BUFFER_OVERFLOW,
"GetNetworkParams buffer size failed: " + Win32Error.getErrorMessage(result));
Memory buffer = new Memory(bufferSize.getValue());
FIXED_INFO fixedInfo = new FIXED_INFO(buffer);
result = IPHlpAPI.INSTANCE.GetNetworkParams(fixedInfo.getPointer(), bufferSize);
if (result != WinNT.ERROR_SUCCESS) {
log.error("GetNetworkParams failed: %s", Win32Error.getErrorMessage(result));
return;
}
String domain = new String(fixedInfo.DomainName).trim();
log.info("GetNetworkParams gave domain=\"%s\"", domain);
以下是我找到的一些示例:
问题是您正在向 FIXED_INFO
的构造函数提供一个 Memory
实例 - 该构造函数用于在结构中包含正确数据的内存,而您只是传递清空未初始化的内存。 FIXED_INFO
的构造函数会尝试读取其中的结构体和指针,发现结构体中的数据无效。
您应该做的是调用 FIXED_INFO
的不带任何参数的构造函数。此构造函数将为您分配适量的内存并正确初始化它。
将您的代码更改为:
// Memory buffer = new Memory(bufferSize); -- remove this line
FIXED_INFO fixedInfo = new FIXED_INFO();
此信息的来源:查看 JNA 的源代码和包含 FIXED_INFO 的库。
- JNA
Structure
class(来自您的堆栈跟踪)
FIXED_INFO
我明白了。此代码有效:
IntByReference bufferSize = new IntByReference();
int result = IPHlpAPI.INSTANCE.GetNetworkParams(Pointer.NULL, bufferSize);
Validate.isTrue(result == WinNT.ERROR_BUFFER_OVERFLOW,
"GetNetworkParams buffer size failed: " + Win32Error.getErrorMessage(result));
log.info("BufferSize=%d", bufferSize.getValue());
Memory buffer = new Memory(bufferSize.getValue());
// Now retrieve the actual FIXED_INFO
result = IPHlpAPI.INSTANCE.GetNetworkParams(buffer, bufferSize);
if (result != WinNT.ERROR_SUCCESS) {
log.error("GetNetworkParams failed: %s", Win32Error.getErrorMessage(result));
return;
}
FIXED_INFO fixedInfo = new FIXED_INFO(buffer);
String domain = new String(fixedInfo.DomainName).trim();
log.info("GetNetworkParams gave domain=\"%s\"", domain);
我对 new FIXED_INFO(buffer) 进行了简单调用,导致 java.lang.Error:无效内存访问。我一辈子都弄不明白为什么会失败:
import com.sun.jna.platform.win32.IPHlpAPI;
import com.sun.jna.platform.win32.IPHlpAPI.FIXED_INFO;
public void fixedInfoTest() {
int bufferSize = 648;
Memory buffer = new Memory(bufferSize);
FIXED_INFO fixedInfo = new FIXED_INFO(buffer);
}
"new FIXED_INFO(buffer)" 调用引发异常。
java.lang.Error: Invalid memory access
at com.sun.jna.Native._getPointer(Native Method)
at com.sun.jna.Native.getPointer(Native.java:2211)
at com.sun.jna.Pointer.getPointer(Pointer.java:642)
at com.sun.jna.Pointer.getValue(Pointer.java:367)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.Structure.autoRead(Structure.java:2141)
at com.sun.jna.Structure.conditionalAutoRead(Structure.java:561)
at com.sun.jna.Structure.updateStructureByReference(Structure.java:690)
at com.sun.jna.Pointer.getValue(Pointer.java:367)
at com.sun.jna.Structure.readField(Structure.java:732)
at com.sun.jna.Structure.read(Structure.java:591)
at com.sun.jna.platform.win32.IPHlpAPI$FIXED_INFO.<init>(IPHlpAPI.java:208)
at com.magnicomp.test.unit.WindowsNativeTest.fixedInfoTest(WindowsNativeTest.java:43)
上述测试有时确实有效,但经常失败。测试系统为Win 10, Win Server 2016. JNA version 5.4.0
在我的生产代码中,fixedInfo 用于:
IntByReference bufferSize = new IntByReference();
int result = IPHlpAPI.INSTANCE.GetNetworkParams(Pointer.NULL, bufferSize);
Validate.isTrue(result == WinNT.ERROR_BUFFER_OVERFLOW,
"GetNetworkParams buffer size failed: " + Win32Error.getErrorMessage(result));
Memory buffer = new Memory(bufferSize.getValue());
FIXED_INFO fixedInfo = new FIXED_INFO(buffer);
result = IPHlpAPI.INSTANCE.GetNetworkParams(fixedInfo.getPointer(), bufferSize);
if (result != WinNT.ERROR_SUCCESS) {
log.error("GetNetworkParams failed: %s", Win32Error.getErrorMessage(result));
return;
}
String domain = new String(fixedInfo.DomainName).trim();
log.info("GetNetworkParams gave domain=\"%s\"", domain);
以下是我找到的一些示例:
问题是您正在向 FIXED_INFO
的构造函数提供一个 Memory
实例 - 该构造函数用于在结构中包含正确数据的内存,而您只是传递清空未初始化的内存。 FIXED_INFO
的构造函数会尝试读取其中的结构体和指针,发现结构体中的数据无效。
您应该做的是调用 FIXED_INFO
的不带任何参数的构造函数。此构造函数将为您分配适量的内存并正确初始化它。
将您的代码更改为:
// Memory buffer = new Memory(bufferSize); -- remove this line
FIXED_INFO fixedInfo = new FIXED_INFO();
此信息的来源:查看 JNA 的源代码和包含 FIXED_INFO 的库。
- JNA
Structure
class(来自您的堆栈跟踪) FIXED_INFO
我明白了。此代码有效:
IntByReference bufferSize = new IntByReference();
int result = IPHlpAPI.INSTANCE.GetNetworkParams(Pointer.NULL, bufferSize);
Validate.isTrue(result == WinNT.ERROR_BUFFER_OVERFLOW,
"GetNetworkParams buffer size failed: " + Win32Error.getErrorMessage(result));
log.info("BufferSize=%d", bufferSize.getValue());
Memory buffer = new Memory(bufferSize.getValue());
// Now retrieve the actual FIXED_INFO
result = IPHlpAPI.INSTANCE.GetNetworkParams(buffer, bufferSize);
if (result != WinNT.ERROR_SUCCESS) {
log.error("GetNetworkParams failed: %s", Win32Error.getErrorMessage(result));
return;
}
FIXED_INFO fixedInfo = new FIXED_INFO(buffer);
String domain = new String(fixedInfo.DomainName).trim();
log.info("GetNetworkParams gave domain=\"%s\"", domain);