使用JNA和JUnit测试本地库:退出库后测试意外终止
JNA调用自定义本地库后程序意外终止问题
我开发了一个测试JNA集成Linux和Windows本地库的小型应用,用JUnit测试验证结果时遇到问题:第一个测试调用库方法后程序会意外终止,控制台能看到库方法输出的"welcome",但Java代码finally块里的"EXIT"从未打印,程序直接停止。
替换测试用系统库(比如libc.so的cosh方法)时,JUnit测试完全正常,多次调用也没问题,所以问题肯定出在我自己的本地库中。
Java相关代码
interface NativeLibraryInterface extends Library { static final String LIB_NAME_WINDOWS = "mylibW"; static final String LIB_NAME_LINUX = "mylibL"; NativeLibraryInterface INSTANCE = Native.load(Platform.isWindows() ? LIB_NAME_WINDOWS : LIB_NAME_LINUX, NativeLibraryInterface.class); int func1(int argc, String[] argv) throws LastErrorException; } public interface INativeLibraryApi { int myFunc1(String... args) throws LastErrorException; } public class NativeLibraryApi implements INativeLibraryApi { @Override public int myFunc1(String... args) throws LastErrorException { try { return NativeLibraryInterface.INSTANCE.func1(args.length, args); } catch (LastErrorException e) { System.out.println(e.getLocalizedMessage()); return -1; } finally { System.out.println("EXIT"); } } } final class NativeLibraryTest { static INativeLibraryApi nativeApi; @BeforeAll static void setup() { nativeApi = new NativeLibraryApi(); } @Test void test1() throws Exception { int result = nativeApi.myFunc1("myArgA", "myArgB"); assertEquals(0, result); } @Test void test2() throws Exception { int result = nativeApi.myFunc1("myArgC", "myArgD", "myArgE"); assertEquals(0, result); } }
自定义本地库代码
编译选项:-g -ansi -pedantic -Wall -Wextra -m64 -O0
链接选项:-shared
myLibrary.hpp
class MyLibrary { public: MyLibrary (); ~MyLibrary (); int myFunc1 ( int argc, char* argv[] ); }; extern "C" int func1 (int argc, char* argv[]);
myLibrary.cpp
#include "myLibrary.hpp" MyLibrary::MyLibrary () { } MyLibrary::~MyLibrary () { } int MyLibrary::myFunc1 (int argc, char* argv[]) { std::cout << "welcome" << std::endl; exit (EXIT_SUCCESS); } extern "C" int func1(int argc, char* argv[]) { MyLibrary library; return library.myFunc1(argc, argv); }
问题原因与解决方法
问题根源在本地库的myFunc1方法里调用了exit(EXIT_SUCCESS);——这个C标准库函数会直接终止整个进程,而不是返回给调用者。Java进程被这个exit调用直接杀死,导致Java代码的finally块根本没机会执行,程序直接终止。
解决方法很简单:把exit(EXIT_SUCCESS);替换成返回值,让函数正常返回给JNA:
int MyLibrary::myFunc1 (int argc, char* argv[]) { std::cout << "welcome" << std::endl; return EXIT_SUCCESS; }
这样修改后,本地库函数执行完成后会正常返回,Java代码能继续执行finally块的逻辑,后续的JUnit测试也能正常运行。
内容的提问来源于stack exchange,提问作者raoul volfoni
相关产品推荐
相关产品推荐

