Android编译器优化导致的奇怪问题

来源:互联网 发布:ps3模拟器og数据损坏 编辑:程序博客网 时间:2024/06/15 07:01

最近在调试一个协程库的时候遇到奇怪的问题:在Ubuntu 10.04上调试协程一直正常,但是将协程库编译成.so文件后放入Android设备中,在应用程序中调用此库却出现强制退出的问题,刚开始遇到十分不解。
因为该协程库是利用单个线程来实现协程的,协程的栈空间其实直接分配在线程的栈空间上,于是对于这个问题我的第一直觉是可能是因为Android中Bionic库与glibc的不同而导致的。
我把这个现象与猜想与其他开发人员交流过后,讨论得出更加有可能是缺页中断而导致的,这种问题在消费电子上出现也可以理解,于是我在设备上做了这么一个实验:

void stack_test(){    int i;    char _a[4096];    for(i = 0; i < 4096; i++){        _a[i] = 'A';        LOGD("_a[%d] is %c",i,_a[i]);    }    char _s = 's';    LOGD("_s is %c",_s);    void *p = malloc(getpagesize());    memcpy(p+getpagesize(),'A',sizeof('A'));    LOGD("malloc & memcpy done");}

将这个函数编译成为.so库中,在Android设备上调用pthread_create新建一个线程,将线程栈长度设置为足够大之后运行此函数,结果发现一切正常。
如此一来这个程序强制退出的问题是由于缺页中断引起的便站不住脚了。
失去了线索后我继续在库里面加打印尝试寻找新的方向,结果发现是在尝试访问协程栈的内存是出现程序强制退出,再一查看协程栈的内存地址,发现协程栈的地址范围已经超出了线程栈地址范围,这样问题就清晰多了,原来是因为内存访问错误,本来协程栈的内存应该被包括在进程栈里,现在由于不知名的问题导致了协程栈的内存分配错误,所以导致程序强制退出。
继续往下查找发现是库里面使用的检查机器栈增长方向的函数出现了错误,函数如下:

static int check_stack_dir(char *p){    char q;    return (int)(p - &q);}static int stack_mp(){    char x;    int dir = check_stack_dir(&x);}

正常情况下在Linux下函数check_stack_dir计算出来的结果应该为负值(因为栈的增长方向是由高地址到低地址的),但在Android设备上的计算结果却是正值,既然代码是没问题的,系统也应该没有问题,那么很有可能是编译出问题了。有可能是因为编译器优化将函数check_stack_dir里的变量q放在了stack_mp函数中变量char x前面去了。
根据这个猜测我修改了代码,将函数int check_stack_dir声明为:

int check_stack_dir(char *p)

这样编译器就无法做出刚才的优化了,好,上机调试,一切正常,完毕!

0 0