JNA尝试从指针读取字节数组时,内存访问无效



我试图使用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输入流都会发生,所以这是因为out大小可能是错误的吗?

代码来自C编写的项目ttarchext

JNA中的Invalid Memory Access错误表示您试图访问尚未分配的内存。在这种情况下,next_out指针的全长为outsize。要调试它,您需要参考API,看看函数是否希望您分配内存并将其传递给本机函数,或者本机函数本身是否会分配必要的内存。(在后一种情况下,本机代码通常会告诉您在使用完内存后如何释放内存。(对于这个API,分配显然是在inflateInit2()调用中完成的,因此这是对bug根本原因的提示。

输出很有指导意义,因为它表明它在较小的insz下成功了一次,但在较大的insz下失败了第二次。这种差异在崩溃的堆栈跟踪中也很明显,表明递归调用发生在第二种(较大输入(情况下,但可能没有发生在第一种情况下。(为了在调试中确认这一点,您应该添加更多的输出。(

对于递归调用,唯一的变化是将第三个参数改为Zstream deflate,而不是ZStream z(其中null作为迭代中可能的下一个值传递。(虽然将z改为deflate似乎是正确的,但我看不出原始代码中应该有null。这似乎是为了重复出现";下一个";类型的迭代,直到完成为止。(这可能不是错误的原因,但很可疑。(

使用deflate参数而不是zredo()调用的唯一区别是使用-15的窗口大小调用deflate。这似乎与您映射的inflateInit2_()的文档相反:

windowBits参数应为要使用的最大窗口大小的以2为底的对数,并且应为8到15之间的值。

由于您移植的原始C代码也使用了-15,这可能是正确的,但很明显,不同的窗口大小会对输出产生影响。

我建议保留deflate作为递归调用的最后一个参数,而不是null,并添加更多的输出语句,以便在递归时更深入地了解参数的值。


可能导致错误的另一个变量是outsize值。这似乎意味着完整的outsize值是可供读取的,如果您已经到达分配的末尾,则情况可能并非如此。outsize可能是第一次的最小大小(也许windowsize = 15导致这是真的(,但当递归时(windowsize = -15的情况(,这是不可依赖的,并且您应该在最后一次迭代时从输出中读取更少的字节(查看原始源建议z.total_out。(

最新更新