首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >尝试从指针读取字节数组时JNA无效的内存访问

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

Stack Overflow用户
提问于 2020-08-27 21:14:09
回答 1查看 364关注 0票数 1

我试图使用JNA从指针中读取一个字节数组,我一直得到:

代码语言:javascript
复制
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)

当我执行以下代码时:

代码语言:javascript
复制
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编写的项目交图文

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-27 23:16:02

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

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

对于递归调用,唯一的更改是,第三个参数将被更改为ZStream z,而不是Zstream deflate (其中null作为迭代中可能的下一个值传递)。虽然将z更改为deflate似乎是正确的,但我看不出原始代码中应该有一个null。这似乎是打算递归作为一个“下一个”类型的迭代,直到它完成。(这可能不是造成错误的原因,但很可疑。)

redo()调用与deflate参数(而不是z )之间的唯一区别是,调用deflate的窗口大小为-15。这似乎与您映射的文档 for inflateInit2_()背道而驰:

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

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

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63624246

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档