An example of unions not being type safe?

Discussion in 'C Programming' started by Chad, Aug 15, 2007.

  1. Chad

    Chad Guest

    Okay, so like recently the whole idea of using a Union in C finally
    sunk into my skull. Seriously, I think it probably took me 2 years to
    catch on what a Union really is. Belated, I mentioned this too my
    ultra smart friend who just quit working as a CTO of a wireless
    company so he go complete his PhD in particle physics. Anyhow he
    mentioned that Unions in C are not typesafe.

    Now, how is it possible to violate type safety in Unions?

    Chad
    Chad, Aug 15, 2007
    #1
    1. Advertising

  2. "Chad" <> wrote in message
    news:...
    > Okay, so like recently the whole idea of using a Union in C finally
    > sunk into my skull. Seriously, I think it probably took me 2 years to
    > catch on what a Union really is. Belated, I mentioned this too my
    > ultra smart friend who just quit working as a CTO of a wireless
    > company so he go complete his PhD in particle physics. Anyhow he
    > mentioned that Unions in C are not typesafe.
    >
    > Now, how is it possible to violate type safety in Unions?


    #include <stdio.h>

    int main(void) {
    union {
    int i;
    double d;
    } z;

    z.d = 42.7;
    printf( "%d\n", z.i ); /* Oops */
    return 0;
    }

    --
    poncho
    Scott Fluhrer, Aug 15, 2007
    #2
    1. Advertising

  3. Chad

    Old Wolf Guest

    On Aug 15, 1:17 pm, "Scott Fluhrer" <> wrote:
    > "Chad" <> wrote in message
    >
    > > Now, how is it possible to violate type safety in Unions?

    >
    > z.d = 42.7;
    > printf( "%d\n", z.i ); /* Oops */


    Well, you aren't allowed to do that. Would you
    also say that an int is not typesafe because
    you can write:

    int x = 10;
    printf("%f", *(double *)&x); /* oops */

    ? If you follow the rules as to what you are
    permitted to do with unions, then I don't see
    any violation of type safety.
    Old Wolf, Aug 16, 2007
    #3
  4. Old Wolf <> writes:
    > On Aug 15, 1:17 pm, "Scott Fluhrer" <> wrote:
    >> "Chad" <> wrote in message
    >>
    >> > Now, how is it possible to violate type safety in Unions?

    >>
    >> z.d = 42.7;
    >> printf( "%d\n", z.i ); /* Oops */

    >
    > Well, you aren't allowed to do that. Would you
    > also say that an int is not typesafe because
    > you can write:
    >
    > int x = 10;
    > printf("%f", *(double *)&x); /* oops */
    >
    > ? If you follow the rules as to what you are
    > permitted to do with unions, then I don't see
    > any violation of type safety.


    You aren't allowed to do it, but the prohibition is not enforced; it
    invokes undefined behavior.

    You can play similar games with pointer conversions, but storing a
    value in one union member and then reading the value of another is an
    easier mistake to make (or an easier thing to do deliberately if you
    don't mind undefined behavior). Some programmers have the attitude
    that that's just what unions are for (and I'm not convinced that
    they're entirely wrong).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2007
    #4
  5. Old Wolf said:

    > On Aug 15, 1:17 pm, "Scott Fluhrer" <> wrote:
    >> "Chad" <> wrote in message
    >>
    >> > Now, how is it possible to violate type safety in Unions?

    >>
    >> z.d = 42.7;
    >> printf( "%d\n", z.i ); /* Oops */

    >
    > Well, you aren't allowed to do that.


    False. The behaviour is implementation-defined in C90, and undefined in
    C99. Taking advantage of either behaviour is *not* forbidden, although
    it does render your program non-portable. I'm not condoning the above
    by any means, but it is not true that "you aren't allowed to do that",
    any more than it is true that you are not allowed to define an array
    with 1 << CHAR_BIT elements (implementation-defined behaviour) or
    dereference a pointer to video memory under MS-DOS (undefined
    behaviour).

    > Would you
    > also say that an int is not typesafe because
    > you can write:
    >
    > int x = 10;
    > printf("%f", *(double *)&x); /* oops */


    Yes. What makes it possible to break the type system is the existence of
    multiple types and the ability to convert between them.

    <snip>

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Aug 16, 2007
    #5
  6. Richard Heathfield <> writes:
    > Old Wolf said:

    [...]
    >> Would you
    >> also say that an int is not typesafe because
    >> you can write:
    >>
    >> int x = 10;
    >> printf("%f", *(double *)&x); /* oops */

    >
    > Yes. What makes it possible to break the type system is the existence of
    > multiple types and the ability to convert between them.


    Not quite. Being able to convert between types doesn't necessarily
    break the type system. For example, a hypothetical 100% typesafe
    language might freely allow conversions among different numeric types.
    This:
    int x = 10;
    printf("%f", (double)x);
    doesn't break type safety.

    What does break type safety in C is the ability to treat an object of
    one type as if it were an object of a different type, *without*
    coverting the value of the object (i.e., type-punning). Unions and
    pointer conversions make this possible.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2007
    #6
  7. Chad

    Old Wolf Guest

    On Aug 16, 12:35 pm, Richard Heathfield <> wrote:
    > Old Wolf said:
    > >> "Chad" <> wrote:
    > >> z.d = 42.7;
    > >> printf( "%d\n", z.i ); /* Oops */

    >
    > > Well, you aren't allowed to do that.

    >
    > False. The behaviour is implementation-defined in C90, and undefined in
    > C99.


    C90 does not have aliasing rules? (Notwithstanding
    clauses specific to unions).
    Old Wolf, Aug 16, 2007
    #7
  8. Keith Thompson said:

    > Richard Heathfield <> writes:
    >> Old Wolf said:

    > [...]
    >>> Would you
    >>> also say that an int is not typesafe because
    >>> you can write:
    >>>
    >>> int x = 10;
    >>> printf("%f", *(double *)&x); /* oops */

    >>
    >> Yes. What makes it possible to break the type system is the existence
    >> of multiple types and the ability to convert between them.

    >
    > Not quite. Being able to convert between types doesn't necessarily
    > break the type system.


    I didn't say it did. I said that it was what makes it *possible* to
    break the type system. Now, I will accept that it may not be
    sufficient, but it is certainly a prerequisite. Without the ability to
    convert between types, there is no mechanism for breaking the type
    system; and without multiple types, there isn't a type system to break.

    The existence of a mechanism for breaking the type system does not imply
    that that mechanism must be used. Therefore, the ability to convert
    between types doesn't of itself break the type system. Such a mechanism
    does, however, remove a significant barrier to such breakage.

    > For example, a hypothetical 100% typesafe
    > language might freely allow conversions among different numeric types.
    > This:
    > int x = 10;
    > printf("%f", (double)x);
    > doesn't break type safety.
    >
    > What does break type safety in C is the ability to treat an object of
    > one type as if it were an object of a different type, *without*
    > coverting the value of the object (i.e., type-punning). Unions and
    > pointer conversions make this possible.


    You're making the same mistake again. That ability does not break type
    safety. It merely opens the door to such breakage. Nor are unions and
    pointer conversions *necessary* for breaking type safety, since C
    thoughtfully provides at least one other type-safety-breaking
    mechanism: the ability to write values to, and subsequently read those
    values from, a file.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Aug 16, 2007
    #8
  9. Old Wolf said:

    > On Aug 16, 12:35 pm, Richard Heathfield <> wrote:
    >> Old Wolf said:
    >> >> "Chad" <> wrote:
    >> >> z.d = 42.7;
    >> >> printf( "%d\n", z.i ); /* Oops */

    >>
    >> > Well, you aren't allowed to do that.

    >>
    >> False. The behaviour is implementation-defined in C90, and undefined
    >> in C99.

    >
    > C90 does not have aliasing rules?


    It's hard to prove a negative. Can you show that C90 /does/ have
    aliasing rules that disallow the specific code given?

    For "disallow", I will on this occasion accept the following meanings:

    * the code violates a constraint
    * the code contains a syntax error
    * the behaviour of the code is undefined [1]

    Note that 3.3.2.3 of C89 renders the behaviour implementation-defined,
    so any answer has to be able to trump that rendering. C90 will have
    different numbering - possibly 6.3.2.3 - but it is well-known that C89
    and C90 have basically the same text, except for the insertion of three
    "noise" sections.

    > (Notwithstanding
    > clauses specific to unions).


    The *code* is specific to unions!


    [1] In fact, there is no prohibition on taking advantage of undefined
    behaviour, but I want to give you every chance to back up your claim
    that "you aren't allowed to do that". What I won't do is agree that
    implementation-defined behaviour is not allowed.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Aug 16, 2007
    #9
  10. Chad

    Old Wolf Guest

    Richard Heathfield wrote:
    > Old Wolf said:
    > > Richard Heathfield wrote:
    > >> >> "Chad" <> wrote:
    > >> >> z.d = 42.7;
    > >> >> printf( "%d\n", z.i ); /* Oops */

    >
    > >> False. The behaviour is implementation-defined in C90,

    >
    > > C90 does not have aliasing rules?

    >
    > It's hard to prove a negative. Can you show that C90 /does/ have
    > aliasing rules that disallow the specific code given?


    I don't have a copy of C90, hence why I'm asking you.

    > Note that 3.3.2.3 of C89 renders the behaviour implementation-defined,
    > so any answer has to be able to trump that rendering.


    Yes. For example, in C99 the behaviour is undefined
    because it is explicitly undefined to alias a float
    as an int (regardless of whether a union is involved).
    It seems a reasonable assumption that C90 has similar
    aliasing rules, although I'm unable to look it up.
    Old Wolf, Aug 16, 2007
    #10
  11. On Aug 15, 8:35 pm, Richard Heathfield <> wrote:
    > Old Wolf said:
    >
    > > On Aug 15, 1:17 pm, "Scott Fluhrer" <> wrote:
    > >> "Chad" <> wrote in message

    >
    > >> > Now, how is it possible to violate type safety in Unions?

    >
    > >> z.d = 42.7;
    > >> printf( "%d\n", z.i ); /* Oops */

    >
    > > Well, you aren't allowed to do that.

    >
    > False. The behaviour is implementation-defined in C90, and undefined in
    > C99.


    It is actually undefined in C90 (the fact that the Standard states it
    is implementation-defined is a defect). In C99 it is only undefined
    behavior if the result is a trap representation.

    Robert Gamble
    Robert Gamble, Aug 16, 2007
    #11
  12. Robert Gamble said:

    > On Aug 15, 8:35 pm, Richard Heathfield <> wrote:


    [Context: union type-punning]

    >> The behaviour is implementation-defined in C90, and undefined
    >> in C99.

    >
    > It is actually undefined in C90 (the fact that the Standard states it
    > is implementation-defined is a defect).


    No, it is actually implementation-defined in C90. The fact that the C90
    Standard states it is implementation-defined means that it is
    implementation-defined in the C90 Standard. If the ISO C Committee
    decide that it constitutes a defect in that Standard, they can issue a
    TC - and presumably they did. But that doesn't affect the C90 Standard.
    It only affects a Standard that we might reasonably call "C90 + TCs 1
    to n", where n is the number of the TC in which the correction was
    made.

    Not even the ISO C Committee can change the past.

    <snip>

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Aug 16, 2007
    #12
  13. Richard Heathfield <> writes:
    > Keith Thompson said:
    >> Richard Heathfield <> writes:
    >>> Old Wolf said:

    >> [...]
    >>>> Would you
    >>>> also say that an int is not typesafe because
    >>>> you can write:
    >>>>
    >>>> int x = 10;
    >>>> printf("%f", *(double *)&x); /* oops */
    >>>
    >>> Yes. What makes it possible to break the type system is the existence
    >>> of multiple types and the ability to convert between them.

    >>
    >> Not quite. Being able to convert between types doesn't necessarily
    >> break the type system.

    >
    > I didn't say it did. I said that it was what makes it *possible* to
    > break the type system. Now, I will accept that it may not be
    > sufficient, but it is certainly a prerequisite. Without the ability to
    > convert between types, there is no mechanism for breaking the type
    > system; and without multiple types, there isn't a type system to break.
    >
    > The existence of a mechanism for breaking the type system does not imply
    > that that mechanism must be used. Therefore, the ability to convert
    > between types doesn't of itself break the type system. Such a mechanism
    > does, however, remove a significant barrier to such breakage.

    [...]

    I think we're saying the same thing in different words.

    I'm thinking of "breaks the type system" and "makes it possible to
    break the type system" as being essentially synonymous. Being able to
    convert between types is not sufficient to make it possible to break
    the type system (if, for example, only conversions among numeric types
    are allowed).

    I think the difference is that I'm talking about language features
    breaking the type system, and you're talking about programs actually
    *using* those features to break the type system. A language that
    allows arbitary assignments between distinct types has a broken type
    system, even if it's possible to write programs in that language that
    don't take advantage of that brokenness.

    Note that "broken" isn't necessarily a bad thing. Sometimes you want
    to bypass type checking.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2007
    #13
  14. Keith Thompson said:

    <snip>

    > I think we're saying the same thing in different words.


    No, we *are*!

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Aug 16, 2007
    #14
  15. Richard Heathfield <> writes:
    > Robert Gamble said:
    >> On Aug 15, 8:35 pm, Richard Heathfield <> wrote:

    >
    > [Context: union type-punning]
    >
    >>> The behaviour is implementation-defined in C90, and undefined
    >>> in C99.

    >>
    >> It is actually undefined in C90 (the fact that the Standard states it
    >> is implementation-defined is a defect).

    >
    > No, it is actually implementation-defined in C90. The fact that the C90
    > Standard states it is implementation-defined means that it is
    > implementation-defined in the C90 Standard. If the ISO C Committee
    > decide that it constitutes a defect in that Standard, they can issue a
    > TC - and presumably they did. But that doesn't affect the C90 Standard.
    > It only affects a Standard that we might reasonably call "C90 + TCs 1
    > to n", where n is the number of the TC in which the correction was
    > made.
    >
    > Not even the ISO C Committee can change the past.


    Strictly speaking, the committee corrected the C90 standard by issuing
    the C99 standard. They're not going to issue corrections to a
    standard that's officially obsolete. (I know that C90 is still a de
    facto current standard, but the committee isn't going to act on that
    basis.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2007
    #15
  16. Keith Thompson said:

    > Richard Heathfield <> writes:


    <snip>

    >> Not even the ISO C Committee can change the past.

    >
    > Strictly speaking, the committee corrected the C90 standard by issuing
    > the C99 standard. They're not going to issue corrections to a
    > standard that's officially obsolete. (I know that C90 is still a de
    > facto current standard, but the committee isn't going to act on that
    > basis.)


    All absolutely true, of course. Nevertheless, C90 remains topical here,
    and in C90 (sans TCs) the behaviour in question is, and will always
    remain, implementation-defined.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Aug 16, 2007
    #16
  17. Richard Heathfield <> writes:
    > Keith Thompson said:
    >> Richard Heathfield <> writes:

    >
    > <snip>
    >
    >>> Not even the ISO C Committee can change the past.

    >>
    >> Strictly speaking, the committee corrected the C90 standard by issuing
    >> the C99 standard. They're not going to issue corrections to a
    >> standard that's officially obsolete. (I know that C90 is still a de
    >> facto current standard, but the committee isn't going to act on that
    >> basis.)

    >
    > All absolutely true, of course. Nevertheless, C90 remains topical here,
    > and in C90 (sans TCs) the behaviour in question is, and will always
    > remain, implementation-defined.


    True, but the flaw is that there are implementations on which the
    behavior cannot reasonably be defined (unless the definition says
    "This can yield arbitrary results that can blow up in your face").

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Aug 16, 2007
    #17
  18. In article <>,
    Old Wolf <> wrote:

    >> > Now, how is it possible to violate type safety in Unions?

    >>
    >> z.d = 42.7;
    >> printf( "%d\n", z.i ); /* Oops */


    >Well, you aren't allowed to do that. Would you
    >also say that an int is not typesafe because
    >you can write:
    >
    > int x = 10;
    > printf("%f", *(double *)&x); /* oops */


    No, I would say that casts aren't type-safe. Casts and unions are two
    of the ways to have objects treated as the wrong type.

    -- Richard
    --
    "Consideration shall be given to the need for as many as 32 characters
    in some alphabets" - X3.4, 1963.
    Richard Tobin, Aug 16, 2007
    #18
  19. Chad

    CBFalconer Guest

    Richard Tobin wrote:
    > Old Wolf <> wrote:
    >
    >>>> Now, how is it possible to violate type safety in Unions?
    >>>
    >>> z.d = 42.7;
    >>> printf( "%d\n", z.i ); /* Oops */

    >
    >> Well, you aren't allowed to do that. Would you> also say that
    >> an int is not typesafe because you can write:
    >>
    >> int x = 10;
    >> printf("%f", *(double *)&x); /* oops */

    >
    > No, I would say that casts aren't type-safe. Casts and unions
    > are two of the ways to have objects treated as the wrong type.


    Apart from variadic function parameters, such as printf, most casts
    are errors. I include unnecessary as an error.

    --
    Chuck F (cbfalconer at maineline dot net)
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net>



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Aug 16, 2007
    #19
  20. On Thu, 16 Aug 2007 00:35:19 +0000, in comp.lang.c , Richard
    Heathfield <> wrote:

    >Old Wolf said:
    >
    >> On Aug 15, 1:17 pm, "Scott Fluhrer" <> wrote:
    >>> "Chad" <> wrote in message
    >>>
    >>> > Now, how is it possible to violate type safety in Unions?
    >>>
    >>> z.d = 42.7;
    >>> printf( "%d\n", z.i ); /* Oops */

    >>
    >> Well, you aren't allowed to do that.

    >
    >False.


    Too strong.

    >The behaviour is implementation-defined in C90, and undefined in
    >C99. Taking advantage of either behaviour is *not* forbidden,


    In C99, its forbidden in the same sense that much of what we discuss
    here as 'forbidden' or 'illegal' is.
    --
    Mark McIntyre

    "Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are,
    by definition, not smart enough to debug it."
    --Brian Kernighan
    Mark McIntyre, Aug 16, 2007
    #20
    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. Safe use of unions

    , Jun 30, 2006, in forum: C Programming
    Replies:
    4
    Views:
    277
    Robert Gamble
    Jul 9, 2006
  2. Gabriel Rossetti
    Replies:
    0
    Views:
    1,294
    Gabriel Rossetti
    Aug 29, 2008
  3. Replies:
    1
    Views:
    325
    Brian Candler
    Aug 12, 2003
  4. Aredridel

    Not just $SAFE, but damn $SAFE

    Aredridel, Sep 2, 2004, in forum: Ruby
    Replies:
    19
    Views:
    225
  5. John Nagle
    Replies:
    5
    Views:
    451
    John Nagle
    Mar 12, 2012
Loading...

Share This Page