I'm debugging a piece of code that is causing some crashes using Keil's compiler but not ARM-GCC. I'm not familiar with the history of the code but as I'm reading more I'm realizing that there is definitely at least a strict-aliasing violation in the code. However the error that drew me to the code in the first place was an unaligned access fault when running this snippet.
I'm embarassed to admit that I was not very aware of the issues with this kind of strict aliasing violation, and would like to convince myself that fixing that will solve the issue, and not just mask whatever is causing the unaligned fault.
Could someone help me understand why I'm seeing the unaligned access fault? Is this related to the strict-aliasing violation and if so, how does that manifest as such?
What would the best way to resolve this be? I have declared sampleStruct as __packed now which appears to be working but would using a union for sampleStruct be a better solution? Or going further would I need to copy individual members of the struct?
I'm still learning more about the strict-aliasing rules, but a push in the right direction would be much appreciated.
*Note: This is running on in an embedded system on a Cortex-M4 and will never run on another platform or hardware.
Disassembly:
0x00031DF0 9802 LDR r0,[sp,#0x08]
64: structA->SessionCount = params.SessionCount;
0x00031DF2 60A0 STR r0,[r4,#0x08]
65: structA->SessionValueAverage = params.ValueNum != 0 ? params.ValueTotal / params.ValueNum : 0.0f;
0x00031DF4 9806 LDR r0,[sp,#0x18]
65: structA->SessionValueAverage = params.ValueNum != 0 ? params.ValueTotal / params.ValueNum : 0.0f;
0x00031DF6 B140 CBZ r0,0x00031E0A
65: structA->SessionValueAverage = params.ValueNum != 0 ? params.ValueTotal / params.ValueNum : 0.0f;
0x00031DF8 EDDD0A05 VLDR s1,[sp,#0x14]
0x00031DFC ED9D0A06 VLDR s0,[sp,#0x18]
0x00031E00 EEB81A40 VCVT.F32.U32 s2,s0
0x00031E04 EE800A81 VDIV.F32 s0,s1,s2
0x00031E08 E001 B 0x00031E0E
65: structA->SessionValueAverage = params.ValueNum != 0 ? params.ValueTotal / params.ValueNum : 0.0f;
0x00031E0A ED9F0A1E VLDR s0,[pc,#0x78]
> 0x00031E0E ED840A03 VSTR s0,[r4,#0x0C]
66: structA->Value = params.ValueLast;
0x00031E12 ED9D0A04 VLDR s0,[sp,#0x10]
0x00031E16 ED840A04 VSTR s0,[r4,#0x10]
67: structA->SessionValueLow = params.ValueLow;
0x00031E1A ED9D0A07 VLDR s0,[sp,#0x1C]
0x00031E1E ED840A05 VSTR s0,[r4,#0x14]
68: structA->SessionValueHigh = params.ValueHigh;
0x00031E22 ED9D0A08 VLDR s0,[sp,#0x20]
58 case SESSION_INFO_HDL: {
59 AppParams_t params;
60 AppParamsRead(¶ms);
61 sampleStruct_t *structA = (sampleStruct_t *) &pData->pValue[offset];
62 structA->TotalCount = params.TotalCount;
63 structA->SessionId = params.SessionId;
64 structA->SessionCount = params.SessionCount;
65 structA->SessionValueAverage = params.ValueNum != 0 ? params.ValueTotal / params.ValueNum : 0.0f;
66 structA->Value = params.ValueLast;
67 structA->SessionValueLow = params.ValueLow;
68 structA->SessionValueHigh = params.ValueHigh;
69 structA->Reserved = 0;
70 AttsSetAttr(SESSION_INFO_HDL, sizeof(*structA), &pData->pValue[offset]);
71 break;
72 }
Code Snippet: https://godbolt.org/z/Djebj2
typedef struct
{
uint8_t *pValue; /*!< \brief Pointer to the data's value */
uint16_t *pLen; /*!< \brief Pointer to the length of the data's value */
} data_t;
typedef struct sampleStruct {
uint32_t TotalCount;
uint32_t SessionId;
uint32_t SessionCount;
float SessionValueAverage;
float Value;
float SessionValueLow;
float SessionValueHigh;
uint32_t Reserved;
} sampleStruct_t;
typedef struct AppParams {
uint32_t TotalCount;
uint32_t SessionId;
uint32_t SessionCount;
uint32_t CalibrationThreshold;
float ValueLast;
float ValueTotal;
uint32_t ValueNum;
float ValueLow;
float ValueHigh;
} AppParams_t;
void function ( uint16_t offset, data_t * pData )
{
AppParams_t params;
sampleStruct_t *structA = (sampleStruct_t *) &pData->pValue[offset];
structA->TotalCount = params.TotalCount;
structA->SessionId = params.SessionId;
structA->SessionCount = params.SessionCount;
structA->SessionValueAverage = params.ValueNum != 0 ? params.ValueTotal / params.ValueNum : 0.0f;
structA->Value = params.ValueLast;
structA->SessionValueLow = params.ValueLow;
structA->SessionValueHigh = params.ValueHigh;
structA->Reserved = 0;
AttsSetAttr(SESSION_INFO_HDL, sizeof(*structA), &pData->pValue[offset]);
send_data ( SESSION_INFO_HDL, &pData->pValue[offset], sizeof(*structA) );
}