尝试从指针读取字节数组时 JNA 无效的内存访问
JNA Invalid memory access when trying to read byte array from pointer
我正在尝试使用 JNA 从指针读取字节数组,但我不断收到:
Decompress with insz 11107, and outsize 65536
recieved 1
Decompression complete!
Decompress with insz 22112, and outsize 65536
recieved 1
Decompression complete!
Decompress with insz 22041, and outsize 65536
recieved 1
Decompression complete, final out size of 0!
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.read(Native Method)
at com.sun.jna.Pointer.read(Pointer.java:149)
at com.sun.jna.Pointer.getByteArray(Pointer.java:715)
at me.TTARCHExtract.redo(TTARCHExtract.java:330)
at me.TTARCHExtract.redo(TTARCHExtract.java:323)
at me.TTARCHExtract.z_decompress(TTARCHExtract.java:313)
当我执行下面的代码时:
public static final Pointer toPointer(byte[] array, int length){
Memory ret = new Memory(length);
ret.write(0, array, 0, length);
return ret;
}
//code starts here
private byte[] z_decompress(byte[] in,int insize,byte[] out,int outsize) {
if(in==null)return null;
System.out.println("Decompress with insz "+insize+", and outsize "+outsize);
Pointer inptr = toPointer(in, insize);
Pointer outptr = toPointer(out, outsize);
ZStream deflate = new ZStream();
ZStream z = new ZStream();
TTARCHHelper.load();
ZlibLibrary lib = TTARCHHelper.ZLIB_LIBRARY;
this.initz(lib, z, 15);
this.initz(lib, deflate, -15);
return this.redo(insize, outsize, z, lib, inptr, outptr, true, deflate);
}
private byte[] redo(int insize,int outsize,ZStream z,ZlibLibrary lib,Pointer inptr,Pointer outptr,boolean first,ZStream deflate) {
lib.inflateReset(z);
z.next_in=inptr;
z.next_out=outptr;
z.avail_in=insize;
z.avail_out=outsize;
int out = lib.inflate(z, ZlibLibrary.Z_FINISH);
if(!first)System.out.println("recieved "+out);
if(out != ZlibLibrary.Z_STREAM_END) {
if(first)return this.redo(insize, outsize, deflate, lib, inptr, outptr, false, null);
System.out.println("Compressed zlib/deflate input at offset "
+ ""+dgboff+" ("+insize+" > "+outsize+") is wrong or complete");
System.exit(-1);
return null;
}
System.out.println("Decompression complete!");
return z.next_out.getByteArray(0, outsize);
}
private void initz(ZlibLibrary lib,ZStream z, int w) {
lib.inflateInit2_(z, w, lib.zlibVersion(), z.size());
}
getByteArray 是发生错误的地方。可能是什么原因造成的?
这个错误有时会发生,而且并不是所有的 zlib 输入流都会发生,所以它与输出大小有关吗?
代码来自C写的项目ttarchext
JNA 中的 Invalid Memory Access
错误表明您正在尝试访问尚未分配的内存。在本例中,next_out
指针的全长为 outsize
。要对此进行调试,您需要查阅 API 以查看该函数是否希望您分配内存并将其传递给本机函数,或者本机函数本身是否会分配必要的内存。 (在后一种情况下,本机代码通常会告诉您如何在用完内存后释放内存。)对于这个 API,分配显然是在 inflateInit2()
调用中完成的,所以这是错误根本原因的提示。
输出具有指导意义,因为它表明使用较小的 insz
成功了一次,但使用较大的 insz
第二次失败了。崩溃的堆栈跟踪中的差异也很明显,表明递归调用发生在第二种情况(更大的输入)中,但可能没有出现在第一种情况中。 (要在调试中确认这一点,您应该添加更多输出。)
对于递归调用,唯一的变化是第三个参数从 ZStream z
改为 Zstream deflate
(其中 null
作为可能的下一个值传递给迭代。)虽然将 z
更改为 deflate
似乎是正确的,但我看不到原始代码中应该有 null
的位置。这似乎是为了在完成之前作为“下一个”类型的迭代进行递归。 (这可能不是错误的原因,但很可疑。)
使用 deflate
参数而不是 z
的 redo()
调用的唯一区别是调用 deflate
时窗口大小为 -15
。这似乎与您映射的 inflateInit2_()
的 documentation 相反:
The windowBits parameter shall be a base 2 logarithm of the maximum window size to use, and shall be a value between 8 and 15.
由于您移植的原始 C 代码也使用了 -15,这可能是正确的,但很明显不同的窗口大小对输出有影响。
我建议保留 deflate
而不是 null
作为递归调用的最后一个参数,并添加更多的输出语句,以便在递归时更深入地了解参数的值。
另一个可能导致错误的变量是 outsize
值。这似乎意味着完整的 outsize
值是可以读取的,如果您已经到达分配的末尾,情况可能并非如此。有可能 outsize
第一次是最小大小(也许 windowsize = 15
导致这是真的),但是当递归时(windowsize = -15
情况)不能依赖,并且您应该在最后一次迭代中从输出中读取更少的字节(查看原始来源建议 z.total_out
。)
我正在尝试使用 JNA 从指针读取字节数组,但我不断收到:
Decompress with insz 11107, and outsize 65536
recieved 1
Decompression complete!
Decompress with insz 22112, and outsize 65536
recieved 1
Decompression complete!
Decompress with insz 22041, and outsize 65536
recieved 1
Decompression complete, final out size of 0!
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.read(Native Method)
at com.sun.jna.Pointer.read(Pointer.java:149)
at com.sun.jna.Pointer.getByteArray(Pointer.java:715)
at me.TTARCHExtract.redo(TTARCHExtract.java:330)
at me.TTARCHExtract.redo(TTARCHExtract.java:323)
at me.TTARCHExtract.z_decompress(TTARCHExtract.java:313)
当我执行下面的代码时:
public static final Pointer toPointer(byte[] array, int length){
Memory ret = new Memory(length);
ret.write(0, array, 0, length);
return ret;
}
//code starts here
private byte[] z_decompress(byte[] in,int insize,byte[] out,int outsize) {
if(in==null)return null;
System.out.println("Decompress with insz "+insize+", and outsize "+outsize);
Pointer inptr = toPointer(in, insize);
Pointer outptr = toPointer(out, outsize);
ZStream deflate = new ZStream();
ZStream z = new ZStream();
TTARCHHelper.load();
ZlibLibrary lib = TTARCHHelper.ZLIB_LIBRARY;
this.initz(lib, z, 15);
this.initz(lib, deflate, -15);
return this.redo(insize, outsize, z, lib, inptr, outptr, true, deflate);
}
private byte[] redo(int insize,int outsize,ZStream z,ZlibLibrary lib,Pointer inptr,Pointer outptr,boolean first,ZStream deflate) {
lib.inflateReset(z);
z.next_in=inptr;
z.next_out=outptr;
z.avail_in=insize;
z.avail_out=outsize;
int out = lib.inflate(z, ZlibLibrary.Z_FINISH);
if(!first)System.out.println("recieved "+out);
if(out != ZlibLibrary.Z_STREAM_END) {
if(first)return this.redo(insize, outsize, deflate, lib, inptr, outptr, false, null);
System.out.println("Compressed zlib/deflate input at offset "
+ ""+dgboff+" ("+insize+" > "+outsize+") is wrong or complete");
System.exit(-1);
return null;
}
System.out.println("Decompression complete!");
return z.next_out.getByteArray(0, outsize);
}
private void initz(ZlibLibrary lib,ZStream z, int w) {
lib.inflateInit2_(z, w, lib.zlibVersion(), z.size());
}
getByteArray 是发生错误的地方。可能是什么原因造成的?
这个错误有时会发生,而且并不是所有的 zlib 输入流都会发生,所以它与输出大小有关吗?
代码来自C写的项目ttarchext
JNA 中的 Invalid Memory Access
错误表明您正在尝试访问尚未分配的内存。在本例中,next_out
指针的全长为 outsize
。要对此进行调试,您需要查阅 API 以查看该函数是否希望您分配内存并将其传递给本机函数,或者本机函数本身是否会分配必要的内存。 (在后一种情况下,本机代码通常会告诉您如何在用完内存后释放内存。)对于这个 API,分配显然是在 inflateInit2()
调用中完成的,所以这是错误根本原因的提示。
输出具有指导意义,因为它表明使用较小的 insz
成功了一次,但使用较大的 insz
第二次失败了。崩溃的堆栈跟踪中的差异也很明显,表明递归调用发生在第二种情况(更大的输入)中,但可能没有出现在第一种情况中。 (要在调试中确认这一点,您应该添加更多输出。)
对于递归调用,唯一的变化是第三个参数从 ZStream z
改为 Zstream deflate
(其中 null
作为可能的下一个值传递给迭代。)虽然将 z
更改为 deflate
似乎是正确的,但我看不到原始代码中应该有 null
的位置。这似乎是为了在完成之前作为“下一个”类型的迭代进行递归。 (这可能不是错误的原因,但很可疑。)
使用 deflate
参数而不是 z
的 redo()
调用的唯一区别是调用 deflate
时窗口大小为 -15
。这似乎与您映射的 inflateInit2_()
的 documentation 相反:
The windowBits parameter shall be a base 2 logarithm of the maximum window size to use, and shall be a value between 8 and 15.
由于您移植的原始 C 代码也使用了 -15,这可能是正确的,但很明显不同的窗口大小对输出有影响。
我建议保留 deflate
而不是 null
作为递归调用的最后一个参数,并添加更多的输出语句,以便在递归时更深入地了解参数的值。
另一个可能导致错误的变量是 outsize
值。这似乎意味着完整的 outsize
值是可以读取的,如果您已经到达分配的末尾,情况可能并非如此。有可能 outsize
第一次是最小大小(也许 windowsize = 15
导致这是真的),但是当递归时(windowsize = -15
情况)不能依赖,并且您应该在最后一次迭代中从输出中读取更少的字节(查看原始来源建议 z.total_out
。)