Método virtual puro chamado - compilação cruzada
-
20-12-2019 - |
Pergunta
Estou escrevendo uma biblioteca de programação baseada em eventos para uso no BeagleBone Black e encontrei um erro estranho.
Quando compilo exatamente o mesmo código com os mesmos sinalizadores, recebo os seguintes erros no processador baseado em ARM, mas não quando executo o código compilado para meu computador x86.
$ ./missionControl
pure virtual method called
pure virtual method called
pure virtual method called
terminate called recursively
terminate called recursively
Aborted
Quando compilo e executo no meu laptop, o programa é executado corretamente.
Este é o comando que estou usando para compilar (estou usando um Makefile, mas ambos os métodos de compilação exibem exatamente o mesmo comportamento):
g++ -std=gnu++11 -pthread -O3 -D_GLIBCXX_USE_NANOSLEEP -o missionControl `find . -name *.cpp`
Não importa se eu compilei com o Ubuntu arm-linux-gnueabi-g++
ou compatível com ARM g++
no BeagleBone real, ainda recebo erros no ARM.
Minha pergunta é esta:O que poderia estar causando esse erro e o que posso fazer para tentar encontrar a fonte?Por que isso aconteceria em uma arquitetura de processador, mas não em outra, para a mesma versão do G++?
Obrigado!
Aqui está um backtrace do GDB do processador ARM:
#0 0xb6d4adf8 in raise () from /lib/libc.so.6
#1 0xb6d4e870 in abort () from /lib/libc.so.6
#2 0xb6f50ab4 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/libstdc++.so.6
#3 0xb6f4ea4c in ?? () from /usr/lib/libstdc++.so.6
#4 0xb6f4ea4c in ?? () from /usr/lib/libstdc++.so.6
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
Solução
O problema acabou sendo devido a um bug na versão ARM do libstdc++ que roda no BeagleBone.Um pequeno programa de brinquedo que não possui nenhuma função virtual causa o mesmo erro ("função virtual pura chamada") quando std::thread é criado.
Vou tentar compilar uma versão customizada do gcc/libstdc++ 4.8 no próprio BeagleBone - mesmo que demore muito.
Outras dicas
O método virtual puro chamado O erro ocorre quando você tenta usar o despacho dinâmico para chamar uma função que é puramente virtual em uma base antes que o tipo derivado que a implementa tenha sido construído ou depois de já ter sido destruído.
A causa mais comum para isso é se a classe base tenta chamar uma função virtual que é pura nesse nível por meio do construtor ou destruidor.Fora isso, como foi apontado em alguns comentários, se você tentar acessar um objeto morto, também poderá se deparar com o mesmo problema.
Basta anexar um depurador ao programa e ver qual função virtual é chamada e de onde.
Ver: https://groups.google.com/forum/#!topic/automatak-dnp3/Jisp_zGhd5I
E: Por que este exemplo simples de threading do c++ 11 falha quando compilado com o clang 3.2?
Agora, não tenho ideia de por que isso funciona, mas pelo menos para mim funciona.Adicione as seguintes quatro definições de pré-processador à linha de comando do compilador:
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
Não experimentei para ver se todos eles são necessários ou se você pode ou não usar apenas alguns.Mas isso resolveu o problema para mim.Obrigado a todos aqueles que escreveram as respostas acima e ao meu colega por me superar no Google :)