Hra*_*yan 11 c++ linux android android-ndk
(我使用动态加载API时存在一些问题<dlfcn.h>:dlopen(),dlclose()等),在Android上.我正在使用NDK独立工具链(版本8)来编译应用程序和库.Android版本是2.2.1 Froyo.
这是简单共享库的源代码.
#include <stdio.h>
int iii = 0;
int *ptr = NULL;
__attribute__((constructor))
static void init()
{
iii = 653;
}
__attribute__((destructor))
static void cleanup()
{
}
int aaa(int i)
{
printf("aaa %d\n", iii);
}
Run Code Online (Sandbox Code Playgroud)
这是使用上述库的程序源代码.
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
void *handle;
typedef int (*func)(int);
func bbb;
printf("start...\n");
handle = dlopen("/data/testt/test.so", RTLD_LAZY);
if (!handle)
{
return 0;
}
bbb = (func)dlsym(handle, "aaa");
if (bbb == NULL)
{
return 0;
}
bbb(1);
dlclose(handle);
printf("exit...\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有了这些来源,一切都运行正常,但是当我尝试使用一些STL函数或类时,程序会在main()函数退出时崩溃并出现分段错误,例如在使用共享库的源代码时.
#include <iostream>
using namespace std;
int iii = 0;
int *ptr = NULL;
__attribute__((constructor))
static void init()
{
iii = 653;
}
__attribute__((destructor))
static void cleanup()
{
}
int aaa(int i)
{
cout << iii << endl;
}
Run Code Online (Sandbox Code Playgroud)
使用此代码,程序在main()函数退出后或在函数退出期间崩溃并出现分段错误.我尝试了几个测试,发现了以下结果.
dlclose()最后没有调用时,一切正常.-fno-use-cxa-atexit或者-fuse-cxa-atexit,结果是一样的.我的代码使用STL有什么问题?
看起来我找到了这个bug的原因.我尝试了以下源文件的另一个例子:这是简单类的源代码:myclass.h
class MyClass
{
public:
MyClass();
~MyClass();
void Set();
void Show();
private:
int *pArray;
};
Run Code Online (Sandbox Code Playgroud)
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]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
从代码中可以看出,我没有使用任何与STL相关的东西.这是函数库导出的源文件.func.h
#ifdef __cplusplus
extern "C" {
#endif
int SetBabe(int);
int ShowBabe(int);
#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
最后这是使用该库的程序的源代码.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;
}
Run Code Online (Sandbox Code Playgroud)
再次,你可以看到使用该库的程序也没有使用任何STL相关的东西,但在程序运行后,我在main(...)函数退出期间得到了相同的分段错误.所以这个问题与STL本身无关,而且它隐藏在其他地方.经过一番长时间的研究,我发现了这个bug.通常,destructors在main(...)函数退出之前立即调用静态C++变量,如果它们在主程序中定义,或者如果它们在某个库中定义并且您正在使用它,那么应该在之前立即调用析构函数dlclose(...).在Android OS上,在函数退出期间调用静态C++变量的所有析构函数(在主程序中或在您正在使用的某些库中定义)main(...).那么我们的情况会发生什么?我们在我们使用的库中定义了cls静态C++变量.然后在main(...)函数退出之前,我们调用dlclose(...)function,结果库关闭,cls变为无效.但cls的指针存储在某个地方,它的析构函数应该在main(...)函数退出时调用,因为在调用时它已经无效,我们得到了分段错误.因此解决方案是不要打电话dlclose(...),一切都应该没问题.不幸的是,使用这个解决方案,我们不能使用属性((析构函数))来取消初始化我们想要取消初始化的东西,因为它是作为dlclose(...)调用的结果而调用的.
| 归档时间: |
|
| 查看次数: |
5797 次 |
| 最近记录: |