1

I have some c++ code that defines a struct:

struct IcmpHdr
{
    uint8_t m_type;
    uint8_t m_code;
    uint16_t m_chksum;
    uint16_t m_id;
    uint16_t m_seq;
} __attribute__((packed, aligned(2)))

I understand that this struct will always be aligned on an address divisible by 2 when allocated because a padding byte ahead of the struct will be added if necessary.

This struct gets cast to a byte array before going over the wire to be unpacked on the the receiving end. Now what happens on the receiving end if I store the bytes in an array char byte_array[8];

And then ultimately cast this as a pointer to my type?

IcmpHdr* header = (IcmpHdr*)byte_array;

Will the struct have a 50/50 chance of being misaligned? Could this cause undefined behavior when dereferencing the members? Other issues?

I know I could just align the array on a 2 byte boundary to avoid even having to think about this. Curiosity is my main reason for asking.

6
  • 2
    You'd have some chance of being misaligned and a 100% chance of a strict aliasing violation and therefore undefined behavior. Commented Dec 3, 2021 at 16:08
  • 2
    Don’t, just don’t. There is no reason to attempt to make bad code work when there is a supported way to write good code. When receiving a buffer like this, define an IcmpHdr object and read the data into it (pass it as the buffer to the network call that writes the received data into a buffer). In cases where you are reading a packet and do not know which type it is until after starting to inspect it, you can use a union of the various packet types. Another option is to read into a character buffer and then memcpy into a proper IcmpHdr object. Commented Dec 3, 2021 at 16:13
  • 1
    The aliasing rule Andrew Henle aludes to is basically: Do not lie to the compiler about what type an object is. Modern compilers make a variety of assumptions about code based on object types. Even if the pointer is aligned as needed for an IcmpHdr, accessing an array of char using an lvalue of type IcmpHdr can result in the compiler generating code that does not do what you want. Commented Dec 3, 2021 at 16:16
  • 1
    Have a look at std::bit_cast and this link : stackoverflow.com/questions/58320316/stdbit-cast-with-stdarray. ("C" style casts for "reinterpreting" data are UB anyway) Commented Dec 3, 2021 at 16:23
  • Do not tag both C and C++ except when asking about differences or interactions between the two languages. The aliasing rules are different in the two languages, and answers for one will not serve people who are looking for information about the other language. Commented Dec 3, 2021 at 16:24

1 Answer 1

0
  1. Avoid pointer punning as it almost always breaks strict aliasing rules.
  2. Alignment of your structure does not matter as your byte array does not have to be 2 bytes aligned.

Use memcpy

IcmpHdr header;
memcpy(&header, byte_array, sizeof(header));

If you use modern optimizing compiler it is very unlikely memcpy to be called.

https://godbolt.org/z/6P5M333dv

Sign up to request clarification or add additional context in comments.

2 Comments

@ColonelThirtyTwo no, you can access other types via char, but not char via other types. It is not fine. You did not understand the link
@PepijnKramer where do you see any casts in my code? What is this comment about?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.