Android NDK: C++ struct member access, causes SIGB

2019-07-28 11:04发布

I'm porting a C++ library on Android (Android Studio 2.3.1/NDK 25); the library works flawlessly on UWP (VS2017 VC 1.41 - ARM & Win32) a custom ARM7 board (GCC 4.8).

When debugging on Android Studio, I get a "SIGBUS (signal SIGBUS: illegal alignment)" during an assignment to a struct member. Here is the struct (I need it to be 64-bit aligned):

typedef unsigned int        _t_u32;         // 32-bit unsigned
typedef unsigned long long  _t_u64;         // 64-bit unsigned

typedef struct __attribute__((aligned(8)))
{
    _t_u32      crc32;
    _t_u64      counter;

} t_security;

Now, here is the code snippet:

void prepareBuffer(_t_u8 cmd, _t_u8 *buffer, _t_u32 buffferLen)
{
    t_security *secPtr = ((t_security *)(buffer + sizeof(_t_u8)));

    secPtr->crc32 = 0;
    secPtr->counter= 0; << when this is being executed, on Android Studio-only, I get *"SIGBUS (signal SIGBUS: illegal alignment)"*
    ...
    ...
}

From Android Studio debugger watches:

sizeof(t_security) = {unsigned int} 16
&secPtr = {t_security * | 0xdc98eb41} 0xdc98eb41
&secPtr->crc32 = {_t_u32 * | 0xdc98eb41} 0xdc98eb41
&secPtr->counter = {_t_u64 * | 0xdc98eb49} 0xdc98eb49

From Visual Studio debugger watches (ARM platform):

sizeof(t_security)  16  unsigned int
secPtr  0x00afe2e5 {crc32=3435973836 ...}   t_security *
&secPtr->crc32  0x00afe2e5 {3435973836} unsigned int *
&secPtr->counter    0x00afe2ed {14757395258967641292}   unsigned __int64 *

I suppose it has to due to packing/member alignment... but as you can notice, the packaging seems consistent on the two platforms... just on Android Studio-only, I get "SIGBUS (signal SIGBUS: illegal alignment)".

Can someone please help me understand what's going on? May be a compiler switch I'm missing? Here's the ndk's gradle config:

android.ndk {
    moduleName = "NativeLib"

    // add compilation flags
    cppFlags.add("-DANDROID")
    cppFlags.add("-frtti")
    cppFlags.add("-std=c++14")
    cppFlags.add("-fexceptions")

    // include headers
    cppFlags.add("-I${file("native-src")}".toString())

    ldLibs.addAll("android", "dl", "log", "z", "atomic")

    stl = "c++_static"  // LLVM compiler
}
android.buildTypes {
    all {
        // To solve struct packing issues, setting abiFilters to package only 32-bit architectures:
        ndk.with {
            abiFilters.add("armeabi")
            abiFilters.add("armeabi-v7a")
            abiFilters.add("mips")
            abiFilters.add("x86")
        }
    }
    debug {
        ndk.with {
            cppFlags.add("-DDEBUG")
            CFlags.add("-DDEBUG")
        }
    }
}

Many thanks!

1条回答
趁早两清
2楼-- · 2019-07-28 11:46

I had exactly the same issue.

In your code snippet, secPtr is not aligned because it points to buffer offseted by 1(sizeof(_t_u8)) byte. (assuming that buffer is aligned address)

All 4-byte ailgned memory addresses should end in '0', '4', '8' or 'C'. Since secPtr ends in '5', it is not aligned.

ARM processors support some of unaligned memory access. That is why secPtr->crc32 = 0; is legal, but secPtr->counter= 0; is not.

Try removing 1-byte offset in secPtr somehow and see if the problem goes away.

Also check out this page for detailed information: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html

查看更多
登录 后发表回答