6

I have the following structure and "getter" function that returns a cast to an unsigned integer:

struct s {
    uint32_t a;
};

void get_a(struct s *st, unsigned *ret)
{
    *ret = (unsigned)st->a;
}

The following code is run:

struct s st;
uint16_t x;

st.a = 1;
get_a(&st, (unsigned *)&x);

And for x86_64, i686, armv7hl, ppc64le and other architectures x == 1, but for ppc64 x == 0. Why is this? Little- vs. big-endian?

MC93
  • 791
  • 6
  • 14
  • Set a to 0x12345678. Little-endian machines will return 0x5678, big-endian 0x1234. To maintain same behavior on all machines use htonl/htons/ntohl/ntohs functions. – nsilent22 Jul 24 '15 at 10:13

1 Answers1

5

The problem is that you have:

uint16_t x;

but then you try to write to that memory location as if it were the location of unsigned.

If you were on a system where unsigned and uint16_t are the same type, this is fine. But on other systems, such as the one you used for your code sample, you are in trouble.

First of all, this causes undefined behaviour by violating the strict aliasing rule. Variables of type uint16_t may only be written to through lvalues of type uint16_t, or a character type.

But even if it did not violate strict aliasing, you would still cause UB by writing outside the bounds of x. Probably, you are writing 4 or 8 bytes into a 2-byte memory location, so it will overflow the buffer.

There could also be UB if x is not correctly aligned for unsigned.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • I think it's also worth mentioning that endianness has nothing to do in this case. – edmz Jul 24 '15 at 10:12
  • 1
    @black it sort of does: *if* all of the UB in the code doesn't produce nasal demons this time, we might expect that the `1` bit being written appears either inside `x` or outside `x` depending on the system endianness – M.M Jul 24 '15 at 10:15
  • 1
    Lesson learned: Do not cast pointers, or at least be very careful with what you are doing. There mostly ever is a different solution. Here a temporary `unsigned` typed variable would have wiped away all uncertainties. – alk Jul 24 '15 at 12:05