Исключение освобождает память для std :: string (при попытке использовать YOLO / Dar knet внутри UE4) - PullRequest
0 голосов
/ 10 марта 2020

Я пытаюсь заставить YOLO / Dar knet работать внутри проекта UE4. Я построил YOLO как C ++ DLL и добавил все зависимости в проект. Он прекрасно работает, и некоторые части кода работают, но в определенный момент я получаю исключение, и после буквально нескольких дней попыток выяснить это, я в растерянности и нуждаюсь в некоторой помощи.

Вот код, который я вызываю для создания класса детектора YOLO из класса UE4:

YOLO_DataPath = FPaths::ProjectDir() + "Plugins/Stereolabs/Source/YOLO/Data/";
std::string YOLO_DataPathC(TCHAR_TO_UTF8(*YOLO_DataPath));

std::string  NamesFile = YOLO_DataPathC + "obj.names";
std::string  CFGFile = YOLO_DataPathC + "yolo-obj.cfg";
std::string  WeightsFile = YOLO_DataPathC + "yolo-obj.weights";

Detector YOLODetector(CFGFile, WeightsFile);

Вот вызываемый конструктор (из 'yolo_v2_class. cpp', строка 130 ):

LIB_API Detector::Detector(std::string cfg_filename, std::string weight_filename, int gpu_id) : cur_gpu_id(gpu_id)
{
    wait_stream = 0;
#ifdef GPU
    int old_gpu_index;
    check_cuda( cudaGetDevice(&old_gpu_index) );
#endif

    detector_gpu_ptr = std::make_shared<detector_gpu_t>();
    detector_gpu_t &detector_gpu = *static_cast<detector_gpu_t *>(detector_gpu_ptr.get());

#ifdef GPU
    //check_cuda( cudaSetDevice(cur_gpu_id) );
    cuda_set_device(cur_gpu_id);
    printf(" Used GPU %d \n", cur_gpu_id);
#endif
    network &net = detector_gpu.net;
    net.gpu_index = cur_gpu_id;
    //gpu_index = i;

    _cfg_filename = cfg_filename;
    _weight_filename = weight_filename;

    char *cfgfile = const_cast<char *>(_cfg_filename.c_str());
    char *weightfile = const_cast<char *>(_weight_filename.c_str());

    net = parse_network_cfg_custom(cfgfile, 1, 1);
    if (weightfile) {
        load_weights(&net, weightfile);
    }
    set_batch_network(&net, 1);
    net.gpu_index = cur_gpu_id;
    fuse_conv_batchnorm(net);

    layer l = net.layers[net.n - 1];
    int j;

    detector_gpu.avg = (float *)calloc(l.outputs, sizeof(float));
    for (j = 0; j < NFRAMES; ++j) detector_gpu.predictions[j] = (float*)calloc(l.outputs, sizeof(float));
    for (j = 0; j < NFRAMES; ++j) detector_gpu.images[j] = make_image(1, 1, 3);

    detector_gpu.track_id = (unsigned int *)calloc(l.classes, sizeof(unsigned int));
    for (j = 0; j < l.classes; ++j) detector_gpu.track_id[j] = 1;

#ifdef GPU
    check_cuda( cudaSetDevice(old_gpu_index) );
#endif
}

Кажется, что весь этот код работает нормально, но когда он достигает конца конструктора, он попадает в исключение, когда кажется, что он пытается удалить строку в этой строке (строка 132 из xmemory - c: \ Program Files (x86) \ Microsoft Visual Studio 14.0 \ VC \ include \ xmemory0):

::operator delete(_Ptr);

Полный стек вызовов выглядит следующим образом:

[Inline Frame] yolo_cpp_dll.dll!std::_Deallocate(void * _Ptr, unsigned __int64) Line 132
[Inline Frame] yolo_cpp_dll.dll!std::allocator<char>::deallocate(char *) Line 720
[Inline Frame] yolo_cpp_dll.dll!std::_Wrap_alloc<std::allocator<char> >::deallocate(char * _Count, unsigned __int64) Line 987
[Inline Frame] yolo_cpp_dll.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(bool) Line 2258
[Inline Frame] yolo_cpp_dll.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::{dtor}() Line 1017
yolo_cpp_dll.dll!Detector::Detector(std::basic_string<char,std::char_traits<char>,std::allocator<char> > cfg_filename, std::basic_string<char,std::char_traits<char>,std::allocator<char> > weight_filename, int gpu_id) Line 177

Из той ограниченной информации, которую я могу узнать об этой ошибке, может показаться, что это может быть проблема с DLL-библиотеками, компилируемыми с разными компиляторами. Я провел дни, пробуя разные версии компиляции всего с нуля - UE4 из исходного кода, проект UE4, YOLO cpp DLL. Я пробовал полностью чистые установки Visual Studio 2015 и 2017 для всех, и каждый раз сталкиваюсь с одной и той же проблемой.

Кто-нибудь точно знает, что здесь происходит? И как я мог бы это исправить или обойти это?

Ответы [ 2 ]

0 голосов
/ 12 марта 2020

Как уже отмечали другие, безотказный способ скрыть ваш код за C интерфейсом, но это сильно ограничивает ваш интерфейс, если вы используете C ++. Поэтому, если вы хотите go трудным путем, я знаю, по крайней мере, два проекта, которые успешно справились с этим, вы можете go в их код для получения полной информации

Как указывалось в большинстве комментариев, используйте тот же компилятор и конфигурацию, если вы открываете UE4 Проект в Visual Studio вы должны быть в состоянии проверить конфигурацию.

Тогда уловка статически связывает MSVCRT.lib. Если вы сами не скомпилировали UE4, он использует режим выпуска, поэтому мы используем /MD флаг компилятора (см. msv c ссылка ). Вот пример в скрипте сборки CARLA, BuildLibCarla.bat # L103-L111 , использует CMake для создания библиотеки stati c, позже эта библиотека связана с плагином UE4 (dll).

Linux

Для завершения я добавлю детали и для Linux, потому что я буду sh Я нашел это онлайн, когда мне пришлось это сделать!

Если вы опираетесь на Linux, все становится немного сложнее, ссылки UE4 на время выполнения LLVM libc++ вместо стандартного GNU libstdc++. В зависимости от версии UE4 они используют другую версию набора инструментов LLVM (они, как правило, обновляют его относительно часто). Они поставляются в комплекте с UE4, вы можете найти их в

  • Заголовки и библиотеки: Engine/Source/ThirdParty/Linux/LibCxx
  • SDK, двоичные файлы: Engine/Extras/ThirdPartyNotUE/SDKs/HostLinux/Linux_x64/<clang version>/x86_64-unknown-linux-gnu

Тогда либо скомпилируйте и создайте ссылку на связанную версию libc++.a и libc++abi.a, либо скомпилируйте свою собственную (это то, что CARLA делает Setup.sh # L37-L58 ). Обратите внимание, что использование libc ++ и libc ++ abi, которые вы получаете из apt install, не будет работать, потому что они не скомпилированы с позиционно-независимым кодом (-fPIC), который вам нужно будет связать с .so в UE4.

0 голосов
/ 12 марта 2020

Простой способ: никогда не передавать объекты std :: xxx между различными модулями. Используйте raw C типы. Память должна быть освобождена в модуле, который ее выделил.

Детектор (const char * cfg_filename, const char * weight_filename, int gpu_id)

Сложный способ: компилировать все модули с одинаковым компилятором / опциями (дополнительно тяжело в случае UE4).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...