I was using a TCP library that has an incoming data handler with the following signature:
static void handleData(void *arg, AsyncClient *client, void *data, size_t len)
When I tried to cast the data
like the following the access the field values of the structure, the board crashed.
MyStructure* m = (MyStructure*)data;
In an example of an unrelated communication library, I had seen it using memcpy
like the following, so I changed the casting code above to memcpy
then it worked. But why is the example using memcpy
instead of casting?
// Callback when data is received
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
incomingTemp = incomingReadings.temp;
incomingHum = incomingReadings.hum;
}
The incomingReadings
is declared as a global variable, but that variable is only used inside of that function, and only the fields which are copied to other global variables incomingTemp
and incomingHum
are used elsewhere. What if the example function were like the following, would it crash?
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
struct_message* incoming = (struct_message*)incomingData;
incomingTemp = incoming->temp;
incomingHum = incoming->hum;
}
PS: About the crashing above, I have tested more things to reproduce it with simpler code. It seems that the board does not crash at casting, but at accessing the cast variable.
The structure is as simple as
typedef struct TEST_TYPE
{
unsigned long a;
} TEST_TYPE;
and in the client, I sent a
in
TEST_TYPE *a = new TEST_TYPE();
a->a = 1;
. In the server's handleData
, I modified the code like below
static void handleData(void *arg, AsyncClient *client, void *data, size_t len)
{
Serial.printf("Data length = %i\n", len);
uint8_t* x = (uint8_t*)data;
for(int i =0; i<len; i++)
{
Serial.printf("%X, ", x[i]);
}
Serial.println("Casting.");
TEST_TYPE* a = (TEST_TYPE*)data;
Serial.println("Printing.");
Serial.printf("\nType = %i\n", a->a);
, and the output was
Data length = 4
1, 0, 0, 0, Casting.
Printing.
--------------- CUT HERE FOR EXCEPTION DECODER ---------------
Exception (9):
epc1=0x40201117 epc2=0x00000000 epc3=0x00000000 excvaddr=0x3fff3992 depc=0x00000000
>>>stack>>>
ctx: sys
sp: 3fffec30 end: 3fffffb0 offset: 0190
PS2: Seems like it indeed is an alignment issue. The exception code is 9 above, and according to this page, 9 means:
LoadStoreAlignmentCause Load or store to an unaligned address
I have found an old answer for a similar case. The author suggested some possible solutions
adding
__attribute__((aligned(4)))
to the buffer: I think this is not applicable in my case, because I did not create thedata
parameter.adding
__attribute__((packed))
to the structure: I have modified my structure like the following, and it did not crash this time.typedef struct TEST_TYPE { unsigned long a; } __attribute__((packed)) TEST_TYPE;
Read it by each one byte and construct the fields manually: This seems too much work.