从一个EXC_ARM_DA_ALIGN的crash来看ios3.2以后内存对齐问题

来源:互联网 发布:java map转json字符串 编辑:程序博客网 时间:2024/06/03 04:45

今天在Iphone4调试的时候,遇到一个EXC_ARM_DA_ALIGN。用Iphone 3G(IOS3.1.2)调试之则不出现。因为出问题的代码乃一个库文件里面的,函数大致如下:

 

void f(const char * pBuffer, uint64_t * pDesLLong)

{

   (*(uint64_t *)pDesLLong) = (*(uint64_t *)pBuffer);

   ...

}


查看crash log文件,发现是由于产生了一个EXC_ARM_DA_ALIGN 的 Exception。google之,找到一位老外兄弟言:IOS3.2以及之后的版本,开发者需要考虑内存对齐的问题。http://byteclub.com/blog/44-development/85-memory-alignment-errors-on-iphone-os-3-2

 

那么,它是几字节对齐呢?根据上面这位牛哥提供的资源,查到了这样一篇比较系统的文档,知道它是4字节对齐得(word)(https://brewx.qualcomm.com/bws/content/gi/common/appseng/en/knowledgebase/docs/kb95.html)

 

那么问题就很明显了:如果上面那两个指针pBuffer和pDestLong所指的地址不是4的倍数,就会触发一个对齐的异常EXC_ARM_DA_ALIGN。那么这个问题怎么解决呢?前面的文档中言,使用memcpy来代替type casting来做赋值。于是我将代码改为:

 

memcpy((char*)pDestLong, (char*)pBuffer, sizeof(uing64_t));

 

在Debug版本下运行之,果然有效。可是当我编出一个Release版本的时候,问题又出现了。为何?

 

第一印象一定是memcpy是否被优化掉了。于是google “memcpy optimize”,发现以下这个优化代码:

 

void * memcpy(void * dst, void const * src, size_t len)
{
    long * plDst = (long *) dst;
    long const * plSrc = (long const *) src;

    if (!(src & 0xFFFFFFFC) && !(dst & 0xFFFFFFFC))
    {
        while (len >= 4)
    {
            *plDst++ = *plSrc++;
            len -= 4;
        }
    }

    char * pcDst = (char *) plDst;
    char const * pcDst = (char const *) plSrc;

    while (len--)
    {
        *pcDst++ = *pcSrc++;
    }

    return (dst);
}

 

第一句话这个赋值,如果传入的指针不是一个四字节对齐的指针,即所指地址不是4的倍数,那么就会引发一个EXC_ARM_DA_ALIGN。如果真是这样的话,解决方案就必须自己写一个老版本的memcpy函数了:

 

void * memcpy(void * dst, void const * src, size_t len)
{
    char * pDst = (char *) dst;
    char const * pSrc = (char const *) src;

    while (len--)
    {
        *pDst++ = *pSrc++;
    }

    return (dst);
}

 

使用之,问题解决。