当使用dlclose(...)Android平台分段故障 [英] Segmentation fault when using dlclose(...) on android platform

查看:478
本文介绍了当使用dlclose(...)Android平台分段故障的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了动态加载API时存在一些问题(< dlfcn.h中> 的dlopen() dlclose()在Android等)。 我使用NDK独立的工具链(第8版)编译应用程序和库。 而Android的版本是2.2.1升级Froyo。

I have some problems when using the dynamic loading API (<dlfcn.h>: dlopen(), dlclose(), etc) on Android. I'm using NDK standalone toolchain (version 8) to compile the applications and libraries. The Android version is 2.2.1 Froyo.

下面是一个简单的共享库的源$ C ​​$ C。

Here is the source code of the simple shared library.

#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);
}

下面是节目源$ C ​​$ C,它使用提到的库。

Here is the program source code which uses the mentioned library.

#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;
}

使用这些资源一切工作正常,但当我尝试使用一些STL函数或类,程序段故障崩溃的<$ C时,使用这种光源$ C ​​$ C共享库时,$ C>的main()函数退出,例如。

With these sources everything is working fine, but when I try to use some STL functions or classes, the program crashes with a segmentation fault, when the main() function exits, for example when using this source code for the shared library.

#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;
}

通过这个code,程序崩溃与分段故障后或在的main()函数退出。 我曾尝试一些测试,发现了以下结果。

With this code, the program crashes with segmentation fault after or the during main() function exit. I have tried couple of tests and found the following results.

  1. 在不使用STL的一切工作正常。
  2. 当使用STL和不叫 dlclose()结尾,一切工作正常。
  3. 我试图编译像 -fno使用-CXA-atexit对 - 保险丝-CXA-atexit对,结果是一样的。
  1. Without using of STL everything is working fine.
  2. When use STL and do not call dlclose() at the end, everything is working fine.
  3. I tried to compile with various compilation flags like -fno-use-cxa-atexit or -fuse-cxa-atexit, the result is the same.

什么是错误的,我认为使用STL code?

What is wrong in my code that uses the STL?

推荐答案

看起来像我找到了错误的原因。我曾尝试另一个例子用下面的源文件: 下面是简单的类的源$ C ​​$ C: myclass.h

Looks like I found the reason of the bug. I have tried another example with the following source files: Here is the source code of the simple class: myclass.h

class MyClass
{
public:
    MyClass();
    ~MyClass();
    void Set();
    void Show();
private:
    int *pArray;
};

myclass.cpp

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]);
        }
    }
}

正如你可以从code我没有使用任何STL相关的东西看看。 这里是函数库出口的源文件。 func.h

As you can see from the code I did not used any STL related stuff. Here is the source files of the functions library exports. func.h

#ifdef __cplusplus
extern "C" {
#endif

int SetBabe(int);
int ShowBabe(int);

#ifdef __cplusplus
}
#endif

func.cpp

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;
}

最后,这是使用该库的PROGRAMM源$ C ​​$ C。 的main.cpp

And finally this is the source code of the programm that uses the library. 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相关的东西看的程序,但程序的运行后,我在主(...)函数退出。所以,问题是没有连接到STL本身,它隐藏在其他一些地方。再经过一些长期研究,我发现的bug。 通常情况下,析构函数静态C ++变量之前立即召集主(...)函数退出,如果他们被定义在主程序中,或者如果他们在一些库中定义的,您正在使用它,那么析构函数应该立即之前称为dlclose(...)。 在Android OS 所有析构函数中主(...)函数退出。那么,在我们的情况下,会发生什么?我们的 CLS 的库定义的静态C ++变量,我们正在使用。于是马上主(...)函数退出我们称之为 dlclose(...)的功能,因此前库关闭的 CLS 的变成不合法。但指针的 CLS 的存储的地方,它的析构函数应该在被称为主(...)函数退出,因为在时间调用它已经无效,我们得到段错误。所以,解决的办法就是不叫 dlclose(...),一切都应该罚款。不幸的是这个解决方案,我们不能使用的 属性((析构函数))的对,我们要取消初始化,因为它被称为的结果是什么deinitializing dlclose(...)通话。

Again as you can see the program using the library also does not using any STL related stuff, but after run of the program I got the same segmentation fault during main(...) function exit. So the issue is not connected to STL itself, and it is hidden in some other place. Then after some long research I found the bug. Normally the destructors of static C++ variables are called immediately before main(...) function exit, if they are defined in main program, or if they are defined in some library and you are using it, then the destructors should be called immediately before dlclose(...). On Android OS all destructors(defined in main program or in some library you are using) of static C++ variables are called during main(...) function exit. So what happens in our case? We have cls static C++ variable defined in library we are using. Then immediately before main(...) function exit we call dlclose(...) function, as a result library closed and cls becomes non valid. But the pointer of cls is stored somewhere and it's destructor should be called during main(...) function exit, and because at the time of call it is already invalid, we get segmentation fault. So the solution is to not call dlclose(...) and everything should be fine. Unfortunately with this solution we cannot use attribute((destructor)) for deinitializing of something we want to deinitialize, because it is called as a result of dlclose(...) call.

这篇关于当使用dlclose(...)Android平台分段故障的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆