JNA尝试从指针读取字节数组时出现无效内存访问错误。

huangapple go评论105阅读模式
英文:

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;
}
// 代码从这里开始
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

英文:

Im trying to read a byte array from a Pointer using JNA and I keep getting:

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. 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?

Code is from C written project ttarchext

答案1

得分: 1

Invalid Memory Access 错误在 JNA 中表示您正在尝试访问未分配的内存。在这种情况下,是 next_out 指针,长度为 outsize。要调试此问题,您需要查阅 API,以确定函数是希望您分配内存并将其传递给本地函数,还是本地函数本身将分配所需的内存。在后一种情况下,本地代码通常会告诉您在使用完内存后如何释放它。对于这个 API,分配显然是在 inflateInit2() 调用中完成的,所以这是指向错误根本原因的线索。

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

对于递归调用,唯一的变化是第三个参数不再是 ZStream z,而是改为 Zstream deflate(在迭代时将 null 作为可能的下一个值传递)。虽然将 z 更改为 deflate 似乎是正确的,但我没有看到在原始代码中哪里应该有一个 null。这似乎旨在递归作为“下一个”类型的迭代进行,直到完成为止。(这可能不是错误的原因,但值得怀疑。)

redo() 调用中,将参数从 z 改为 deflate 的唯一差异是 deflate 使用了窗口大小 -15。这似乎与您所映射的 inflateInit2_()文档 相矛盾:

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

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

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


可能引起错误的另一个变量是 outsize 值。这似乎暗示可以读取完整的 outsize 值,但如果已经达到了分配的结尾,情况可能并非如此。可能的情况是 outsize 是一个最小值(也许 windowsize = 15 导致这种情况成立),第一次时是如此,但在递归时(windowsize = -15 的情况下)就不能依赖于这一点,您应该从输出中读取较少的字节,最后一次迭代时应该这样做(审查原始源代码建议使用 z.total_out)。

英文:

An Invalid Memory Access error in JNA is a sign that you are attempting to access memory which has not been allocated. In this case, the next_out pointer, with the full length of 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. (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.

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. 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. 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. This seems to be contrary to the documentation for inflateInit2_() which you have mapped:

> 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.

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.

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.

<hr>

The other variable which could cause the error is the outsize value. 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. 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.)

huangapple
  • 本文由 发表于 2020年8月28日 05:14:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/63624246.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定