I've run into a EXC_BAD_ACCESS
with a piece of code that deals with data serialization. The code only fails on device (iPhone) and not on simulator. It also fails only on certain data types.
Here is a test code that reproduces the problem:
template <typename T>
void test_alignment() {
// allocate memory and record the original address
unsigned char *origin;
unsigned char *tmp = (unsigned char*)malloc(sizeof(unsigned short) + sizeof(T));
origin = tmp;
// push data with size of 2 bytes
*((unsigned short*)tmp) = 1;
tmp += sizeof(unsigned short);
// attempt to push data of type T
*((T*)tmp) = (T)1;
// free the memory
free(origin);
}
static void test_alignments() {
test_alignment<bool>();
test_alignment<wchar_t>();
test_alignment<short>();
test_alignment<int>();
test_alignment<long>();
test_alignment<long long>(); // fails on iPhone device
test_alignment<float>();
test_alignment<double>(); // fails on iPhone device
test_alignment<long double>(); // fails on iPhone device
test_alignment<void*>();
}
Guessing that it must be a memory alignment issue, I decided I want to understand the problem thoroughly. From my (limited) understanding of memory alignment, when tmp
gets advanced by 2 bytes, it becomes misaligned for data types whose alignment is greater than 2 bytes:
tmp += sizeof(unsigned short);
But the test code is executed alright for int
and others! It only fails for long long
, double
and long double
.
Examining the size and alignment of each data type revealed that the failing data types are the ones that have different sizeof
and __alignof
values:
iPhone 4:
bool sizeof = 1 alignof = 1
wchar_t sizeof = 4 alignof = 4
short int sizeof = 2 alignof = 2
int sizeof = 4 alignof = 4
long int sizeof = 4 alignof = 4
long long int sizeof = 8 alignof = 4 // 8 <> 4
float sizeof = 4 alignof = 4
double sizeof = 8 alignof = 4 // 8 <> 4
long double sizeof = 8 alignof = 4 // 8 <> 4
void* sizeof = 4 alignof = 4
iPhone Simulator on Mac OS X 10.6:
bool sizeof = 1 alignof = 1
wchar_t sizeof = 4 alignof = 4
short int sizeof = 2 alignof = 2
int sizeof = 4 alignof = 4
long int sizeof = 4 alignof = 4
long long int sizeof = 8 alignof = 8
float sizeof = 4 alignof = 4
double sizeof = 8 alignof = 8
long double sizeof = 16 alignof = 16
void* sizeof = 4 alignof = 4
(These are the result of running the print function from "C++ data alignment and portability")
Can someone enlighten me what's causing the error? Is the difference really the cause of EXC_BAD_ACCESS
? If so, by what mechanics?