Dereferencing type-punned pointer

Discussion in 'C Programming' started by John May, Jul 18, 2012.

  1. John May

    John May Guest

    I keep getting this warning in GCC with the code segment below.

    file.c:256 "warning: dereferencing type-punned pointer will break
    strict-aliasing rules"

    /*****************************************/
    char buffer[SIZE];
    int length, type;

    /* Code to fill buffer */

    length = ntohs( *((unsigned short *)buffer) );
    type = ntohs( *((unsigned short *)buffer + 1) );

    /*****************************************/


    I'm trying to take the first two bytes (in network byte order) off the
    buffer and put them in the length, followed by the next two bytes into
    the type. GCC complains about the length conversion, but not the type.

    What does this warning mean, and should I bother with it?

    I don't want to keep checking this forum, so answers by email required.
    Quick responses appreciated.

    John
    John May, Jul 18, 2012
    #1
    1. Advertising

  2. John May <> writes:
    > I keep getting this warning in GCC with the code segment below.
    >
    > file.c:256 "warning: dereferencing type-punned pointer will break
    > strict-aliasing rules"
    >
    > /*****************************************/
    > char buffer[SIZE];
    > int length, type;
    >
    > /* Code to fill buffer */
    >
    > length = ntohs( *((unsigned short *)buffer) );
    > type = ntohs( *((unsigned short *)buffer + 1) );
    >
    > /*****************************************/
    >
    >
    > I'm trying to take the first two bytes (in network byte order) off the
    > buffer and put them in the length, followed by the next two bytes into
    > the type. GCC complains about the length conversion, but not the type.
    >
    > What does this warning mean, and should I bother with it?


    Assuming buffer is aligned at an even address, buffer + 1 is at an odd
    address; attempting to read a short object from an odd address can
    easily crash your program. (x86 systems, I think, don't impose strict
    alignment requirements.)

    If you want to copy bytes from an array of char into a larger integer,
    either do so explicitly or use memcpy().

    You also appear to be making some assumptions about the sizes of short
    and int. You should at least document those assumptions.

    > I don't want to keep checking this forum, so answers by email required.
    > Quick responses appreciated.


    Answers posted here are not just for your benefit; they're for everyone
    who reads this newsgroup. Feel free to explain why you should get
    special treatment, but don't expect to convince anyone. Post here, get
    your answers here.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 18, 2012
    #2
    1. Advertising

  3. John May <> writes:
    [...]
    > I don't want to keep checking this forum, so answers by email required.
    > Quick responses appreciated.


    Unless <> is your real e-mail address, how do you
    expect to get answers by e-mail?

    And if it isn't, you shouldn't use a real domain name as a fake address
    (yes, there really is a nospam.com); it can result in the owners of that
    domain receiving spam meant for you. "example.com" is guaranteed not to
    exist.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 18, 2012
    #3
  4. Keith Thompson <> writes:

    > John May <> writes:

    <snip>
    >> char buffer[SIZE];
    >> int length, type;
    >>
    >> /* Code to fill buffer */
    >>
    >> length = ntohs( *((unsigned short *)buffer) );
    >> type = ntohs( *((unsigned short *)buffer + 1) );

    <snip>
    >> I'm trying to take the first two bytes (in network byte order) off the
    >> buffer and put them in the length, followed by the next two bytes into
    >> the type. GCC complains about the length conversion, but not the type.
    >>
    >> What does this warning mean, and should I bother with it?

    >
    > Assuming buffer is aligned at an even address, buffer + 1 is at an odd
    > address; attempting to read a short object from an odd address can
    > easily crash your program.


    The cast has higher precedence so unless the size of short is odd, the
    second access uses an address with the same parity as the first.

    I've phrased it like this because there's nothing actually wrong with
    what you said -- it just isn't relevant to the code in question!

    <snip>
    --
    Ben.
    Ben Bacarisse, Jul 19, 2012
    #4
  5. John May <> writes:

    > I keep getting this warning in GCC with the code segment below.
    >
    > file.c:256 "warning: dereferencing type-punned pointer will break
    > strict-aliasing rules"
    >
    > /*****************************************/
    > char buffer[SIZE];
    > int length, type;
    >
    > /* Code to fill buffer */
    >
    > length = ntohs( *((unsigned short *)buffer) );
    > type = ntohs( *((unsigned short *)buffer + 1) );
    >
    > /*****************************************/
    >
    >
    > I'm trying to take the first two bytes (in network byte order) off the
    > buffer and put them in the length, followed by the next two bytes into
    > the type. GCC complains about the length conversion, but not the type.
    >
    > What does this warning mean, and should I bother with it?


    gcc assumes (as it is permitted to do) that an object is only accessed
    via an expression of "the right type" -- usually just the declared type
    of the object. The objects in 'buffer' are declared to be chars, but
    the pointer cast and dereference causes them to be accessed using an
    expression of type short. Because the breaks gcc's assumptions it warns
    you. It's generally a bad way to do this kind of thing.

    (The phrase "the right type" is in quotes because the actual rules are
    rather complex so my explanation is very much a simplification.)

    An alternative is to use a union:

    union {
    uint8_t bytes[SIZE];
    uint16_t words[SIZE/2];
    } buf_type;

    but_type buffer;
    ...
    length = ntohs(buffer.words[0]);
    type = ntohs(buffer.words[1]);

    (The uintN_t types are standard C types from stdint.h.)

    Alternatively you can construct the two values from the individual
    bytes:

    length = ((unsigned)buffer[0] << 8) + buffer[1];

    but this is fiddly -- you should make the buffer an array of unsigned
    char and you still need the cast before the shift for the code to be
    properly portable.

    > I don't want to keep checking this forum, so answers by email required.
    > Quick responses appreciated.


    Sorry -- impossible for reasons already explained.

    --
    Ben.
    Ben Bacarisse, Jul 19, 2012
    #5
  6. John May

    Ike Naar Guest

    On 2012-07-18, Keith Thompson <> wrote:
    > Unless <> is your real e-mail address, how do you
    > expect to get answers by e-mail?
    >
    > And if it isn't, you shouldn't use a real domain name as a fake address
    > (yes, there really is a nospam.com); it can result in the owners of that
    > domain receiving spam meant for you. "example.com" is guaranteed not to
    > exist.


    Are you sure about that? "example" does not exist as a top-level
    domain, but is it also a reserved name for subdomains? (I thought
    not).
    Perhaps better choices would be "nospam.example" or "nospam.invalid".
    Ike Naar, Jul 19, 2012
    #6
  7. Ike Naar <> writes:
    > On 2012-07-18, Keith Thompson <> wrote:
    >> Unless <> is your real e-mail address, how do you
    >> expect to get answers by e-mail?
    >>
    >> And if it isn't, you shouldn't use a real domain name as a fake address
    >> (yes, there really is a nospam.com); it can result in the owners of that
    >> domain receiving spam meant for you. "example.com" is guaranteed not to
    >> exist.

    >
    > Are you sure about that? "example" does not exist as a top-level
    > domain, but is it also a reserved name for subdomains? (I thought
    > not).
    > Perhaps better choices would be "nospam.example" or "nospam.invalid".


    Yes, I'm sure. See <http://www.iana.org/domains/example/>
    (<http://example.com> forwards to it).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Jul 19, 2012
    #7
  8. John May

    Ike Naar Guest

    On 2012-07-19, Keith Thompson <> wrote:
    > Ike Naar <> writes:
    >> On 2012-07-18, Keith Thompson <> wrote:
    >>> Unless <> is your real e-mail address, how do you
    >>> expect to get answers by e-mail?
    >>>
    >>> And if it isn't, you shouldn't use a real domain name as a fake address
    >>> (yes, there really is a nospam.com); it can result in the owners of that
    >>> domain receiving spam meant for you. "example.com" is guaranteed not to
    >>> exist.

    >>
    >> Are you sure about that? "example" does not exist as a top-level
    >> domain, but is it also a reserved name for subdomains? (I thought
    >> not).
    >> Perhaps better choices would be "nospam.example" or "nospam.invalid".

    >
    > Yes, I'm sure. See <http://www.iana.org/domains/example/>
    > (<http://example.com> forwards to it).


    Thanks. I was only aware of the reserved toplevel domains "example",
    "invalid", "test" and "localhost", and didn't know about "example.com",
    "example.org" and "example.net".
    Ike Naar, Jul 19, 2012
    #8
  9. John May

    Nobody Guest

    On Thu, 19 Jul 2012 01:56:03 +0100, Ben Bacarisse wrote:

    > length = ntohs(buffer.words[0]);
    > type = ntohs(buffer.words[1]);
    >
    > (The uintN_t types are standard C types from stdint.h.)


    Also, the type of ntohs() as specified by POSIX is:

    uint16_t ntohs(uint16_t);
    Nobody, Jul 20, 2012
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David Ford

    help with type-punned warning please

    David Ford, Feb 26, 2004, in forum: C Programming
    Replies:
    16
    Views:
    662
    Chris Torek
    Feb 28, 2004
  2. David Mathog
    Replies:
    3
    Views:
    692
    Chris Torek
    Jul 5, 2007
  3. David Mathog

    dereferencing type-punned pointer, redux

    David Mathog, Jul 10, 2007, in forum: C Programming
    Replies:
    1
    Views:
    661
    Eric Sosman
    Jul 10, 2007
  4. SG
    Replies:
    0
    Views:
    486
  5. Billy Mays

    dereferencing type-punned pointer

    Billy Mays, Jun 21, 2010, in forum: C Programming
    Replies:
    16
    Views:
    1,619
Loading...

Share This Page