如何调试JNI堆栈破坏问题?

5
我有一个Java应用程序,通过JNI调用遗留应用程序的许多不同本地方法。但是JVM在任何JNI调用之外的随机位置出现堆栈转储的崩溃。有时它会在GC期间崩溃,有时会在类加载和其他位置崩溃。我怀疑一个或多个本地方法正在破坏JVM堆或一些其他数据结构。我需要知道是哪个调用导致了这个问题,这样我就可以修复本地实现。
这个遗留应用程序是第三方DLL,我没有源代码和符号信息。为了使其可从Java调用,我构建了一个使用JNI调用约定的包装器DLL。
完美的解决方案是扩展JVM选项,强制JVM在每次JNI调用后自动检查堆及其其他数据结构的完整性。
你知道有什么可以帮助的吗?
P.S. 请不要告诉我要在JVM和遗留应用程序之间构建套接字或管道层,因为我们的要求不允许这样做。这是关于错误检测,而不是架构设计。

我假设你知道“-Xcheck:jni”吗? - Erik
我有同样的问题,如果这有帮助的话 :/ 我有很多数据通过JNI传输,偶尔会出现损坏的地址和数据包。它会破坏整个模拟过程,真的很烦人。 - Chris Dennett
1个回答

5
因为我已经没有答案,也找不到现成的解决方案,所以我最终使用纯C++构建了一个沙盒进程来识别问题。我的Java应用程序使用ProcessBuilder实例化沙盒进程,然后使用stdin和stdout与其通信。与JVM不同,实际上是沙盒加载并调用遗留的DLL。然后我使用Microsoft的Application Verifier监视沙盒进程,发现了内存损坏问题——有一个调用传递了比预期更小的缓冲区。在确定了这个问题之后,我只需要增加Java应用程序中用作缓冲区的byte[]的长度,现在JVM可以直接调用DLL而无需使用沙盒。

总的来说,我浪费了将近10天的时间,仅仅因为JVM没有在每次JNI调用之后验证堆的选项。但至少现在,如果有人发现崩溃,我们可以快速使用沙盒进行调试。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接