![](images/chestnut/misc/left.gif) |
16.08.2017, 01:50
|
#1
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Вызов нативного кода через JNI
Несколько дней назад решил Java освоить.
Вот есть такой вопрос:
Вот есть либа с нативным кодом (С++), я хочу вызывать функции от туда. Сделал java класс с native методами и через javah получил хедер для С/С++ и реализовал его в коде. Функции вызываются нормально. Проблема появляется когда я добавил глобальную переменную в С++ код.
smd::sgz::err_c err; // Вот эту.
JNIEXPORT void JNICALL Java_sgz_SysgzrCalls_testOne( JNIEnv*, jclass ) {
cout << "Test One !!!" << endl;
}
Приложение начинает крошиться вместе с машиной. Машина говорит что виноват вызываемый код. Я запустил под gdb вместе с машиной и посмотрел backtrace - ошибка внутри libstdc++.so в аллокаторе std::string'а, которая линкуется к моему коду и по стеку выше видно что вызов происходит из конструктора err_c. Тем не менее ещё не значит что виноват мой код - возможно java как-то не так загружает либу? Самое интересное что если изменить имя на errEx например - приложение работает, а вот err и error крошатся. Изменение содержимого класса err_c не влияет на результат, даже если сделать пустой класс. Короче как-то однозначно воспроизвести баг и понять причины не удаётся. Саму С++ либу я много раз линковал к другим проектам с нативным кодом - она работает без ошибок, к тому же я специально создал тестовую пустую либу где есть только функция и один объект (как в приведённом коде) - результат тот же.
|
(Offline)
|
|
16.08.2017, 16:53
|
#2
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: Вызов нативного кода через JNI
gdb backtrace:
![](images/chestnut/misc/code_html.gif)
Thread 2 "java" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff7fcf700 (LWP 5848)]
0x00007ffff6020614 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0 0x00007ffff6020614 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00007fffd1e59a88 in smd::sgz::err_c::err_c() () from /home/sam0delk1n/Documents/smdct/bin/libtest.so
#2 0x00007fffd1e59b37 in __static_initialization_and_destruction_0(int, int) () from /home/sam0delk1n/Documents/smdct/bin/libtest.so
#3 0x00007fffd1e59b69 in _GLOBAL__sub_I_test.cpp () from /home/sam0delk1n/Documents/smdct/bin/libtest.so
#4 0x00007ffff7de76ba in call_init (l=<optimized out>, argc=argc@entry=3, argv=argv@entry=0x7fffffffde08, env=env@entry=0x7fffffffde28) at dl-init.c:72
#5 0x00007ffff7de77cb in call_init (env=0x7fffffffde28, argv=0x7fffffffde08, argc=3, l=<optimized out>) at dl-init.c:30
#6 _dl_init (main_map=main_map@entry=0x7ffff0300310, argc=3, argv=0x7fffffffde08, env=0x7fffffffde28) at dl-init.c:120
#7 0x00007ffff7dec8e2 in dl_open_worker (a=a@entry=0x7ffff7fcd920) at dl-open.c:575
#8 0x00007ffff7de7564 in _dl_catch_error (objname=objname@entry=0x7ffff7fcd910, errstring=errstring@entry=0x7ffff7fcd918, mallocedp=mallocedp@entry=0x7ffff7fcd90f,
operate=operate@entry=0x7ffff7dec4d0 <dl_open_worker>, args=args@entry=0x7ffff7fcd920) at dl-error.c:187
#9 0x00007ffff7debda9 in _dl_open (file=0x7ffff03002d0 "/home/sam0delk1n/Documents/smdct/bin/libtest.so", mode=-2147483647, caller_dlopen=0x7ffff6b39dc2, nsid=-2, argc=<optimized out>, argv=<optimized out>,
env=0x7fffffffde28) at dl-open.c:660
#10 0x00007ffff73e0f09 in dlopen_doit (a=a@entry=0x7ffff7fcdb50) at dlopen.c:66
#11 0x00007ffff7de7564 in _dl_catch_error (objname=0x7ffff0000950, errstring=0x7ffff0000958, mallocedp=0x7ffff0000948, operate=0x7ffff73e0eb0 <dlopen_doit>, args=0x7ffff7fcdb50) at dl-error.c:187
#12 0x00007ffff73e1571 in _dlerror_run (operate=operate@entry=0x7ffff73e0eb0 <dlopen_doit>, args=args@entry=0x7ffff7fcdb50) at dlerror.c:163
#13 0x00007ffff73e0fa1 in __dlopen (file=<optimized out>, mode=<optimized out>) at dlopen.c:87
#14 0x00007ffff6b39dc2 in ?? () from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so
#15 0x00007ffff6931f72 in JVM_LoadLibrary () from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so
#16 0x00007ffff53a9188 in Java_java_lang_ClassLoader_00024NativeLibrary_load () from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/libjava.so
#17 0x00007fffe1015574 in ?? ()
#18 0x00007fffdb8c4058 in ?? ()
#19 0x0000000000000000 in ?? ()
Вот видно JVM вызывает dlopen, внутри неё происходят инициализации статических переменных static_initialization_and_desctruction_0 и затем внутри конструктора std::string (я так предполагаю что аллокация) происходит sigsegv. Было бы интересно посмотреть что происходит в dl-init.c, dl-open.c, dl-error.c, dlopen.c и dlerror.c но в системе их нет, в инете что-то тоже, видимо нужно качать коды библиотек, там где dlopen реализован.
Вот что ещё удалось выяснить:
* Падения происходят как с конструкторами по умолчанию, так и с параметрами (для std:string).
* std::vector тоже падает (видимо падает всё что находится внутри объекта с именем err или error).
* Если создать string или vector вне класса а сразу как переменные - работает.
* Если поставить static перед объектом (что ограничит зону видимости одним cpp файлом) - работает во всех случаях.
* В либе которую я пытался изначально подключить есть много других глобальных переменных, и они инициализируются нормально. То есть либа работает если обойти проблему с err (изменив имя или сделав её static).
В общем предположение что название глобальной переменной err или error в некоторых случаях приводит к конфликту имен или проблеме с аллокацией и в качестве частичного решения я сделал её static.
Ещё пробовал менять флаги ggdb и flto при сборке либы но на результат это не влияет.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
16.08.2017, 19:02
|
#3
|
Мастер
Регистрация: 12.01.2009
Сообщений: 979
Написано 388 полезных сообщений (для 631 пользователей)
|
Ответ: Вызов нативного кода через JNI
предположение что название глобальной переменной err или error в некоторых случаях приводит к конфликту имен
|
Запускаем в варианте "static smd::sgz::err_c err;" и смотрим что говорит gdb:
Thread 2 "java" hit Breakpoint 1, __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at src/test/test.cpp:8
8 static smd::sgz::err_c err;
(gdb) print err
$1 = {mLast = ""}
(gdb) explore err
The value of 'err' is a struct/class of type 'smd::sgz::err_c' with the following fields:
mLast = <Enter 0 to explore this field of type 'std::__cxx11::string'>
Enter the field number of choice:
Вполне ожидаемо.
Теперь запускаем в варианте "smd::sgz::err_c err;":
Thread 2 "java" hit Breakpoint 1, __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at src/test/test.cpp:8
8 smd::sgz::err_c err;
(gdb) print err
$1 = {void (int, const char *, ...)} 0x7ffff7902fe0 <err>
(gdb) explore err
Explorer for type 'void (int, const char *, ...)' not yet available.
Внезапно под идентификатором err подразумевается какая-то функция.
Видимо источник бага в этом.
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 02:32.
|