简体   繁体   English

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

[英]JNA Invalid memory access when trying to read byte array from pointer

Im trying to read a byte array from a Pointer using JNA and I keep getting:我尝试使用 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)

when I execute the code below:当我执行下面的代码时:

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());
    }

The getByteArray is where the error is happening. getByteArray 是发生错误的地方。 What could be causing this?什么可能导致这种情况?

This error happens sometimes and with not all zlib input streams so Is it to do with the out size maybe being wrong?有时会发生此错误,并非所有 zlib 输入流都会发生此错误,因此是否与输出大小可能错误有关?

Code is from C written project ttarchext代码来自 C 编写的项目ttarchext

An Invalid Memory Access error in JNA is a sign that you are attempting to access memory which has not been allocated. JNA 中的Invalid Memory Access错误表明您正在尝试访问尚未分配的内存。 In this case, the next_out pointer, with the full length of outsize .在这种情况下, next_out指针,具有的全长outsize To debug this, you need to consult the API to see whether the function expects you to allocate the memory and pass it to the native function, or whether the native function itself will allocate the necessary memory.要对此进行调试,您需要咨询 API 以查看函数是否希望您分配内存并将其传递给本机函数,或者本机函数本身是否会分配必要的内存。 (In the latter case, the native code usually tells you how to free the memory when you're done with it.) For this API, the allocation is apparently done in the inflateInit2() call, so that's a hint toward the bug's root cause. (在后一种情况下,本机代码通常会在完成后告诉您如何释放内存。)对于此 API,分配显然是在inflateInit2()调用中完成的,因此这是对错误根源的提示原因。

The output is instructive in that it shows that it succeeds once with a smaller insz but fails the second time with a larger insz .输出具有指导意义,因为它表明它使用较小的insz成功一次,但第二次使用较大的insz The difference is also evident in the stack trace for the crash, showing that the recursive call occurred in this second (larger input) case, but likely did not in the first case.崩溃的堆栈跟踪中的差异也很明显,表明递归调用发生在第二种(较大的输入)情况下,但可能没有发生在第一种情况下。 (To confirm this in debugging, you should add some more output.) (要在调试中确认这一点,您应该添加更多输出。)

For the recursive call, the only change is that instead of ZStream z , the third parameter is changed to Zstream deflate (where null is passed as the possible next value on the iteration.) While changing z to deflate seems right, I don't see where in the original code there should be a null .对于递归调用,唯一的变化是第三个参数不是ZStream z ,而是更改为Zstream deflate (其中null作为迭代中可能的下一个值传递。)虽然将z更改为deflate似乎是正确的,但我不查看原始代码中应该有一个null This seems to be intended to recurse as a "next" type of iteration until it's done.这似乎旨在作为“下一个”类型的迭代进行递归,直到完成为止。 (This may not be the cause of the error but is suspicious.) (这可能不是错误的原因,但很可疑。)

The only difference in the redo() call with the deflate argument instead of z is that deflate was called with a windowsize of -15 .使用deflate参数而不是zredo()调用的唯一区别是调用deflate时的窗口大小为-15 This seems to be contrary to the documentation for inflateInit2_() which you have mapped:这似乎与您映射的inflateInit2_() 文档相反:

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. windowBits 参数应该是要使用的最大窗口大小的以 2 为底的对数,并且应该是一个介于 8 和 15 之间的值。

Since the original C code you're porting also used -15, this may be correct, but it's clear the different windowsize has an impact on the output.由于您移植的原始 C 代码也使用 -15,这可能是正确的,但很明显不同的窗口大小对输出有影响。

I would suggest keeping deflate as the last argument of the recursive call instead of null , and adding more output statements to give you more insight on the values of the parameters as you recurse.我建议将deflate作为递归调用的最后一个参数而不是null ,并添加更多的输出语句,以便您在递归时更深入地了解参数的值。


The other variable which could cause the error is the outsize value.另一个可能导致错误的变量是outsize值。 This seems to imply the full outsize value is avialable to read, which may not be the case if you have reached the end of the allocation.这似乎意味着可以读取完整的outsize值,如果您已到达分配的末尾,则情况可能并非如此。 It is possible outsize is a minimum size (perhaps the windowsize = 15 causes this to be true) the first time, but when recursing (the windowsize = -15 case) that can not be relied upon, and you should read fewer bytes from the output on the final iteration (reviewing the original source suggests z.total_out .)第一次可能outsize是最小大小(也许windowsize = 15导致这是真的),但是当递归( windowsize = -15情况)不能依赖时,您应该从最后一次迭代的输出(查看原始来源建议z.total_out 。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM