I read a file, put the data into a buffer, say char array. After that I copy part of the data to a struct and increment an offset to read the next data part. The struct is like a header, whose member int dataSize can indicate the variable size of the data load following it.
The buffer could be visualized like this:
| headerA |
| dataLoad |
| dataLoad |
| dataLoad |
| headerB |
| dataLoad |
| dataLoad |
Something happens, possibly due to misaligned data, and SIGBUS occurs. Is it common to use align to realign data before accessing header?
Here is my simple program to illustrate the situation:
#include <iostream>
#include <cstring>
#include <cstdint>
#include <memory>
using namespace std;
typedef struct HeaderA {
int dataSize;
char y;
int z;
} HeaderA; // 12 bytes after padding by compiler
typedef struct HeaderB{
char x;
int dataSize;
char z;
} HeaderB; // 12 bytes after padding by compiler
void copyHeaderA(HeaderA& dest, const char* src) {
memcpy(&dest, src, sizeof(HeaderA));
}
void copyHeaderB(HeaderB& dest, const char* src) {
memcpy(&dest, src, sizeof(HeaderB));
}
int main() {
char data[100]; // 100 bytes
HeaderA headerA;
int offset = 1; // intentionally put offset = 1 to cause mis-alignment when reading dataSize at HeaderA
if (offset + sizeof(HeaderA) <= sizeof(data)) {
copyHeaderA(headerA, &data[offset]);
offset += (sizeof(HeaderA) + headerA.dataSize);
}
HeaderB headerB;
if (offset + sizeof(HeaderB) <= sizeof(data)) {
copyHeaderB(headerB, &data[offset]);
offset += (sizeof(HeaderB) + headerB.dataSize);
}
return 0;
}
My fix is to call std::align to "re-align" the dataSrc. What do you think of this fix? I am also interested to learn how to debug and show the memory address.
#include <iostream>
#include <cstring>
#include <cstdint>
#include <memory>
using namespace std;
typedef struct HeaderA {
int dataSize;
char y;
int z;
} HeaderA; // 12 bytes after padding
typedef struct HeaderB{
char x;
int dataSize;
char z;
} HeaderB; // 12 bytes after padding
void copyHeaderA(HeaderA& dest, const char* src) {
memcpy(&dest, src, sizeof(HeaderA));
}
void copyHeaderB(HeaderB& dest, const char* src) {
memcpy(&dest, src, sizeof(HeaderB));
}
int main() {
char data[100]; // 100 bytes, suppose that this is read from a file and is valid.
HeaderA headerA;
int offset = 1;
if (offset + sizeof(HeaderA) <= sizeof(data)) {
const char* alignedPtrA = &data[offset];
std::size_t spaceA = sizeof(data) - offset;
if (std::align(alignof(HeaderA), sizeof(HeaderA), (void*&)alignedPtrA, spaceA)) {
copyHeaderA(headerA, alignedPtrA); // Ensure alignment before copying
offset += sizeof(HeaderA);
} else {
std::cerr << "Alignment failed for HeaderA" << std::endl;
}
}
HeaderB headerB;
if (offset + sizeof(HeaderB) <= sizeof(data)) {
const char* alignedPtrB = data + offset;
std::size_t spaceB = sizeof(data) - offset;
if (std::align(alignof(HeaderB), sizeof(HeaderB), (void*&)alignedPtrB, spaceB)) {
copyHeaderB(headerB, alignedPtrB); // Ensure alignment before copying
offset += sizeof(HeaderB);
} else {
std::cout << "Alignment failed for HeaderB" << std::endl;
}
}
return 0;
}
HeaderAand then using theHeaderA::dataSizefield: that's undefined behaviour.