Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > C++

Ответ
 
Опции темы
Старый 16.08.2017, 01:50   #1
Samodelkin
Мастер
 
Регистрация: 12.01.2009
Сообщений: 978
Написано 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
Samodelkin
Мастер
 
Регистрация: 12.01.2009
Сообщений: 978
Написано 388 полезных сообщений
(для 631 пользователей)
Ответ: Вызов нативного кода через JNI

gdb backtrace:
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)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
St_AnGer (16.08.2017)
Старый 16.08.2017, 19:02   #3
Samodelkin
Мастер
 
Регистрация: 12.01.2009
Сообщений: 978
Написано 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)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
St_AnGer (17.08.2017)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 12:05.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com