Ответ 1
Похоже, я нашел причину ошибки. Я попробовал другой пример со следующими исходными файлами: Вот исходный код простого класса: 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
статических переменных С++ вызывается непосредственно перед выходом функции main(...)
, если они определены в основной программе или если они определены в некоторой библиотеке и вы используете ее, тогда деструкторы должны вызываться непосредственно перед dlclose(...)
.
В Android OS все деструкторы (определенные в основной программе или в какой-либо библиотеке, которую вы используете) статических переменных С++ вызывается во время выхода функции main(...)
. Так что же происходит в нашем случае? У нас есть статическая переменная С++, определенная в используемой библиотеке. Затем непосредственно перед выводом функции main(...)
вызывается функция dlclose(...)
, в результате библиотека закрывается, а cls становится недействительной. Но указатель cls хранится где-то, и его деструктор следует вызывать во время выхода функции main(...)
, а поскольку во время вызова он уже недействителен, мы получаем ошибку сегментации. Поэтому решение состоит в том, чтобы не называть dlclose(...)
, и все должно быть хорошо. К сожалению, с этим решением мы не можем использовать атрибут ((деструктор)) для деинициализации того, что мы хотим деинициализировать, потому что оно вызвано в результате вызова dlclose(...)
.