Похоже, я нашел причину ошибки. Я пробовал другой пример со следующими исходными файлами:
Вот исходный код простого класса:
myclass.h
class MyClass
{
public:
MyClass();
~MyClass();
void Set();
void Show();
private:
int *pArray;
};
myclass.cpp
#include <stdio.h>
#include <stdlib.h>
#include "myclass.h"
MyClass::MyClass()
{
pArray = (int *)malloc(sizeof(int) * 5);
}
MyClass::~MyClass()
{
free(pArray);
pArray = NULL;
}
void MyClass::Set()
{
if (pArray != NULL)
{
pArray[0] = 0;
pArray[1] = 1;
pArray[2] = 2;
pArray[3] = 3;
pArray[4] = 4;
}
}
void MyClass::Show()
{
if (pArray != NULL)
{
for (int i = 0; i < 5; i++)
{
printf("pArray[%d] = %d\n", i, pArray[i]);
}
}
}
Как видно из кода, я не использовал ничего, связанного с STL.
Вот исходные файлы экспорта библиотеки функций.
func.h
#ifdef __cplusplus
extern "C" {
#endif
int SetBabe(int);
int ShowBabe(int);
#ifdef __cplusplus
}
#endif
func.cpp
#include <stdio.h>
#include "myclass.h"
#include "func.h"
MyClass cls;
__attribute__((constructor))
static void init()
{
}
__attribute__((destructor))
static void cleanup()
{
}
int SetBabe(int i)
{
cls.Set();
return i;
}
int ShowBabe(int i)
{
cls.Show();
return i;
}
И, наконец, это исходный код программы, которая использует библиотеку.
main.cpp
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include "../simple_lib/func.h"
int main()
{
void *handle;
typedef int (*func)(int);
func bbb;
printf("start...\n");
handle = dlopen("/data/testt/test.so", RTLD_LAZY);
if (!handle)
{
printf("%s\n", dlerror());
return 0;
}
bbb = (func)dlsym(handle, "SetBabe");
if (bbb == NULL)
{
printf("%s\n", dlerror());
return 0;
}
bbb(1);
bbb = (func)dlsym(handle, "ShowBabe");
if (bbb == NULL)
{
printf("%s\n", dlerror());
return 0;
}
bbb(1);
dlclose(handle);
printf("exit...\n");
return 0;
}
Опять же, как вы можете видеть, программа, использующая библиотеку, также не использует ничего, связанного с STL, но после запуска программы я получил ту же ошибку сегментации при выходе из функции main(...)
. Таким образом, проблема не связана с самой STL, и она скрыта в каком-то другом месте. Затем, после долгих исследований, я нашел ошибку.
Обычно destructors
статических переменных C ++ вызывается непосредственно перед выходом из функции main(...)
, если они определены в основной программе или если они определены в некоторой библиотеке, и вы используете ее, то деструкторы должны вызываться непосредственно перед dlclose(...)
.
В ОС Android все деструкторы (определенные в основной программе или в используемой вами библиотеке) статических переменных C ++ вызываются при выходе из функции main(...)
. Так что же происходит в нашем случае? У нас есть cls статическая переменная C ++, определенная в используемой нами библиотеке. Затем непосредственно перед выходом из функции main(...)
мы вызываем функцию dlclose(...)
, в результате библиотека результатов закрывается и cls становится недействительной. Но указатель cls хранится где-то, и его деструктор должен вызываться во время выхода из функции main(...)
, а поскольку во время вызова он уже недействителен, мы получаем ошибку сегментации. Поэтому решение состоит в том, чтобы не звонить dlclose(...)
, и все должно быть в порядке. К сожалению, с этим решением мы не можем использовать атрибут ((деструктор)) для деинициализации того, что мы хотим деинициализировать, потому что оно вызывается в результате вызова dlclose(...)
.