Passing structs by value

Discussion in 'C Programming' started by Christopher Benson-Manica, Dec 5, 2005.

  1. Does the following program exhibit undefined behavior? Specifically,
    does passing a struct by value cause undefined behavior if that struct
    has as a member a pointer that has been passed to free()?

    #include <stdlib.h>

    struct stype
    {
    int *foo;
    };

    void bar( struct stype foo )
    {
    }

    int main( void )
    {
    struct stype baz;
    baz.foo=malloc( sizeof *baz.foo );
    free( baz.foo );
    bar( baz ); /* UB or not? */
    return 0;
    }

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Dec 5, 2005
    #1
    1. Advertising

  2. Christopher Benson-Manica

    Jack Klein Guest

    On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
    <> wrote in comp.lang.c:

    >
    > Does the following program exhibit undefined behavior? Specifically,
    > does passing a struct by value cause undefined behavior if that struct
    > has as a member a pointer that has been passed to free()?


    I'm not sure why you make a distinction between a pointer in a
    structure passed by value, and a bare pointer passed by value. Also
    I'm not sure why you make a distinction between a pointer that has an
    indeterminate value because it is uninitialized, or because it points
    to previously allocated storage that has been freed.

    > #include <stdlib.h>
    >
    > struct stype
    > {
    > int *foo;
    > };
    >
    > void bar( struct stype foo )
    > {
    > }
    >
    > int main( void )
    > {
    > struct stype baz;
    > baz.foo=malloc( sizeof *baz.foo );
    > free( baz.foo );
    > bar( baz ); /* UB or not? */
    > return 0;
    > }


    In several places, the C standard refers to function call arguments
    being stored into the function's parameters by assignment. So passing
    anything to a function in C is essentially the same as assigning it to
    the function's local parameter value.

    Assignment in C is always based on value, so passing anything with
    indeterminate value, other than an unsigned char, to a function is
    undefined behavior, as is any other use of the value of such an
    object. It makes no difference whether the object with indeterminate
    value is part of a structure, nor does it make any difference how the
    value became indeterminate.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Dec 5, 2005
    #2
    1. Advertising

  3. Jack Klein <> writes:
    > On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
    > <> wrote in comp.lang.c:
    >> Does the following program exhibit undefined behavior? Specifically,
    >> does passing a struct by value cause undefined behavior if that struct
    >> has as a member a pointer that has been passed to free()?

    >
    > I'm not sure why you make a distinction between a pointer in a
    > structure passed by value, and a bare pointer passed by value. Also
    > I'm not sure why you make a distinction between a pointer that has an
    > indeterminate value because it is uninitialized, or because it points
    > to previously allocated storage that has been freed.
    >
    >> #include <stdlib.h>
    >>
    >> struct stype
    >> {
    >> int *foo;
    >> };
    >>
    >> void bar( struct stype foo )
    >> {
    >> }
    >>
    >> int main( void )
    >> {
    >> struct stype baz;
    >> baz.foo=malloc( sizeof *baz.foo );
    >> free( baz.foo );
    >> bar( baz ); /* UB or not? */
    >> return 0;
    >> }

    >
    > In several places, the C standard refers to function call arguments
    > being stored into the function's parameters by assignment. So passing
    > anything to a function in C is essentially the same as assigning it to
    > the function's local parameter value.
    >
    > Assignment in C is always based on value, so passing anything with
    > indeterminate value, other than an unsigned char, to a function is
    > undefined behavior, as is any other use of the value of such an
    > object. It makes no difference whether the object with indeterminate
    > value is part of a structure, nor does it make any difference how the
    > value became indeterminate.


    But DR #222 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_222.htm>
    says:

    The value of a struct or union object is never a trap
    representation, even though the value of a member of a struct or
    union object may be a trap representation.

    This was published in TC2 and in N1124.

    --
    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.
     
    Keith Thompson, Dec 5, 2005
    #3
  4. Christopher Benson-Manica

    pete Guest

    Keith Thompson wrote:
    >
    > Jack Klein <> writes:


    > > Assignment in C is always based on value, so passing anything with
    > > indeterminate value, other than an unsigned char, to a function is
    > > undefined behavior, as is any other use of the value of such an
    > > object.
    > > It makes no difference whether the object with indeterminate
    > > value is part of a structure,
    > > nor does it make any difference how the
    > > value became indeterminate.

    >
    > But DR #222 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_222.htm>
    > says:
    >
    > The value of a struct or union object is never a trap
    > representation, even though the value of a member of a struct or
    > union object may be a trap representation.
    >
    > This was published in TC2 and in N1124.


    I don't think that the undefined behavior
    associated with accessing freed pointer values
    has anything to do with traps.

    --
    pete
     
    pete, Dec 5, 2005
    #4
  5. pete <> writes:
    > Keith Thompson wrote:
    >> Jack Klein <> writes:
    >> > Assignment in C is always based on value, so passing anything with
    >> > indeterminate value, other than an unsigned char, to a function is
    >> > undefined behavior, as is any other use of the value of such an
    >> > object.
    >> > It makes no difference whether the object with indeterminate
    >> > value is part of a structure,
    >> > nor does it make any difference how the
    >> > value became indeterminate.

    >>
    >> But DR #222 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_222.htm>
    >> says:
    >>
    >> The value of a struct or union object is never a trap
    >> representation, even though the value of a member of a struct or
    >> union object may be a trap representation.
    >>
    >> This was published in TC2 and in N1124.

    >
    > I don't think that the undefined behavior
    > associated with accessing freed pointer values
    > has anything to do with traps.


    A freed pointer has an indeterminate value, defined as "either an
    unspecified value or a trap representation". (The term "trap
    representation" doesn't necessarily imply a trap.)

    --
    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.
     
    Keith Thompson, Dec 5, 2005
    #5
  6. Christopher Benson-Manica

    pete Guest

    Keith Thompson wrote:
    >
    > pete <> writes:


    > > I don't think that the undefined behavior
    > > associated with accessing freed pointer values
    > > has anything to do with traps.

    >
    > A freed pointer has an indeterminate value, defined as "either an
    > unspecified value or a trap representation". (The term "trap
    > representation" doesn't necessarily imply a trap.)


    I don't think trap representations
    have anything to do with freed pointers.

    I think we're dealing with the case of
    accessing a pointer with unspecified value,
    and that access being undefined.

    "An unspecified value cannot be a trap representation."

    "The value of a pointer becomes indeterminate when
    the object it points to reaches the end of its lifetime."

    5
    Certain object representations need not represent
    a value of the object type. If the stored
    value of an object has such a representation and is
    read by an lvalue expression that does not have character type,
    the behavior is undefined. If such a representation is produced
    by a side effect that modifies all or any part of the object by an
    lvalue expression that does not have character type, the behavior is
    undefined. Such a representation is called a trap representation.

    --
    pete
     
    pete, Dec 5, 2005
    #6
  7. Christopher Benson-Manica

    Richard Bos Guest

    Keith Thompson <> wrote:

    > Jack Klein <> writes:
    > > On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
    > > <> wrote in comp.lang.c:
    > >> Does the following program exhibit undefined behavior? Specifically,
    > >> does passing a struct by value cause undefined behavior if that struct
    > >> has as a member a pointer that has been passed to free()?

    > >
    > > I'm not sure why you make a distinction between a pointer in a
    > > structure passed by value, and a bare pointer passed by value. Also
    > > I'm not sure why you make a distinction between a pointer that has an
    > > indeterminate value because it is uninitialized, or because it points
    > > to previously allocated storage that has been freed.
    > >
    > >> #include <stdlib.h>
    > >>
    > >> struct stype
    > >> {
    > >> int *foo;
    > >> };
    > >>
    > >> void bar( struct stype foo )
    > >> {
    > >> }
    > >>
    > >> int main( void )
    > >> {
    > >> struct stype baz;
    > >> baz.foo=malloc( sizeof *baz.foo );
    > >> free( baz.foo );
    > >> bar( baz ); /* UB or not? */
    > >> return 0;
    > >> }

    > >
    > > In several places, the C standard refers to function call arguments
    > > being stored into the function's parameters by assignment. So passing
    > > anything to a function in C is essentially the same as assigning it to
    > > the function's local parameter value.
    > >
    > > Assignment in C is always based on value, so passing anything with
    > > indeterminate value, other than an unsigned char, to a function is
    > > undefined behavior, as is any other use of the value of such an
    > > object. It makes no difference whether the object with indeterminate
    > > value is part of a structure, nor does it make any difference how the
    > > value became indeterminate.

    >
    > But DR #222 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_222.htm>
    > says:
    >
    > The value of a struct or union object is never a trap
    > representation, even though the value of a member of a struct or
    > union object may be a trap representation.


    That's weird. I would've thought this would only make sense for unions,
    not structs.
    In a union, you can easily have the situation that a non-trap value in
    one member means that another member does have a trap value (e.g., with
    an int and a float: bytes that represent a valid int can be a non-valid
    float). This would make passing a union safely impossible in the general
    case; one could not guarantee that any non-trap value assigned to any
    member of a union would leave the whole union in a passable, non-trap
    state.
    For a struct, this is much simpler: all members must be valid for it to
    be a valid object. Assigning a non-trap value to a single struct member
    is already guaranteed not to assign a trap value to any other member of
    the struct, unlike in unions.

    Richard
     
    Richard Bos, Dec 5, 2005
    #7
  8. pete <> writes:
    > Keith Thompson wrote:
    >>
    >> pete <> writes:

    >
    >> > I don't think that the undefined behavior
    >> > associated with accessing freed pointer values
    >> > has anything to do with traps.

    >>
    >> A freed pointer has an indeterminate value, defined as "either an
    >> unspecified value or a trap representation". (The term "trap
    >> representation" doesn't necessarily imply a trap.)

    >
    > I don't think trap representations
    > have anything to do with freed pointers.
    >
    > I think we're dealing with the case of
    > accessing a pointer with unspecified value,
    > and that access being undefined.


    The standard doesn't say the value is unspecified; it says it's
    indeterminate.

    > "An unspecified value cannot be a trap representation."


    Right, so the two cases are mutually exclusive (presumably at the whim
    of the implementation).

    > "The value of a pointer becomes indeterminate when
    > the object it points to reaches the end of its lifetime."


    Right, meaning it's *either* unspecified *or* a trap representation.
    The standard could have been more specific, requiring it to be a trap
    representation, but the same bit pattern (address) could later be
    returned by another call to malloc(), and a program could detect this
    using memcmp().

    So:

    int *ptr = malloc(sizeof *ptr); /* assume ptr != NULL */
    free(ptr);
    /*
    * ptr now has an indeterminate value, possibly a trap representation
    */
    ptr; /* undefined behavior */

    The tricky thing is that the value can be unspecified rather than a
    trap representation. For example, this program *might* examine the
    indeterminate value of ptr1 without invoking undefined behavior:

    #include <stdlib.h>
    #include <stdio.h>
    #include <assert.h>
    int main(void)
    {
    void *ptr1;
    void *ptr2;

    ptr1 = malloc(32);
    assert(ptr1 != NULL);
    free(ptr1);

    ptr2 = malloc(32);
    assert(ptr2 != NULL);

    if (memcmp(&ptr1, &ptr2, sizeof ptr1) == 0) {
    printf("The same address was re-used\n");
    printf("ptr1 = %p\n", ptr1);
    }
    else {
    printf("The address was not re-used\n");
    printf("Examining ptr1 may invoke undefined behavior\n");
    }

    return 0;
    }

    But if we drop the second malloc() call, after free(ptr1) the object
    ptr1 *could* hold a trap representation. (The set of representations
    that are trap representations can vary over time during the execution
    of the program.)

    --
    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.
     
    Keith Thompson, Dec 5, 2005
    #8
  9. Christopher Benson-Manica

    pete Guest

    Keith Thompson wrote:

    > (The set of representations
    > that are trap representations can vary over time during the execution
    > of the program.)


    How do you know that?

    --
    pete
     
    pete, Dec 5, 2005
    #9
  10. Christopher Benson-Manica

    Jordan Abel Guest

    On 2005-12-05, pete <> wrote:
    > Keith Thompson wrote:
    >
    >> (The set of representations
    >> that are trap representations can vary over time during the execution
    >> of the program.)

    >
    > How do you know that?


    Yeah - that is one of the more controversial of the "DS9K claims" - IMO
    up there with the "padding bits of DOOM" one elsethread.
     
    Jordan Abel, Dec 5, 2005
    #10
  11. pete <> writes:
    > Keith Thompson wrote:
    >
    >> (The set of representations
    >> that are trap representations can vary over time during the execution
    >> of the program.)

    >
    > How do you know that?


    Because an implementation on which they can vary can be conforming.
    (I'm not claiming that they'll do so on every implementation.)

    For example:

    void *ptr = malloc(32);
    assert(ptr != NULL);
    /*
    * ptr has a valid value.
    */
    free(ptr);
    /*
    * ptr may now contain a trap representation, even though the bits
    * haven't changed.
    */

    How does this violate the standard? If the standard intends that ptr
    can't have a trap representation, why does it say the value is
    indeterminate rather than unspecified? (The only difference between
    indeterminate and unspecified is that the former includes trap
    representations.)

    --
    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.
     
    Keith Thompson, Dec 5, 2005
    #11
  12. Christopher Benson-Manica

    pete Guest

    Jordan Abel wrote:
    >
    > On 2005-12-05, pete <> wrote:
    > > Keith Thompson wrote:
    > >
    > >> (The set of representations
    > >> that are trap representations
    > >> can vary over time during the execution
    > >> of the program.)

    > >
    > > How do you know that?

    >
    > Yeah -
    > that is one of the more controversial of the "DS9K claims" - IMO
    > up there with the "padding bits of DOOM" one elsethread.


    I can find a reference for that one.

    "Some combinations of padding bits might generate trap
    representations, for example, if one padding bit is a parity bit."

    But I don't see anything in the standard about trap representations,
    which even suggests that trap representations
    can change during the execution of a program.

    The only reference to trap representations
    connected with pointers is"

    5 An integer may be converted to any pointer type.
    Except as previously specified,
    the result is implementation-defined,
    might not be correctly aligned,
    might not point to an entity of the referenced type,
    and might be a trap representation.

    I read the commas and the "and" of
    "this, that, and the other"
    as
    "this, and that, and the other"
    rather than as
    "this, or (that, and the other)"

    --
    pete
     
    pete, Dec 5, 2005
    #12
  13. Christopher Benson-Manica

    pete Guest

    Keith Thompson wrote:

    > free(ptr);
    > /*
    > * ptr may now contain a trap representation, even though the bits
    > * haven't changed.
    > */
    >
    > How does this violate the standard? If the standard intends that ptr
    > can't have a trap representation, why does it say the value is
    > indeterminate rather than unspecified?


    I don't know.

    > (The only difference between
    > indeterminate and unspecified is that the former includes trap
    > representations.)


    You might be right.
    I believe they (the comp.std.c crowd and others here)
    also say that a machine can trap on a pointer
    over running an array,
    which could be an example of a trap representation
    that can change during the execution of a program.

    --
    pete
     
    pete, Dec 5, 2005
    #13
  14. Christopher Benson-Manica

    Jordan Abel Guest

    On 2005-12-05, pete <> wrote:
    > Jordan Abel wrote:
    >>
    >> On 2005-12-05, pete <> wrote:
    >> > Keith Thompson wrote:
    >> >
    >> >> (The set of representations
    >> >> that are trap representations
    >> >> can vary over time during the execution
    >> >> of the program.)
    >> >
    >> > How do you know that?

    >>
    >> Yeah -
    >> that is one of the more controversial of the "DS9K claims" - IMO
    >> up there with the "padding bits of DOOM" one elsethread.

    >
    > I can find a reference for that one.
    >
    > "Some combinations of padding bits might generate trap
    > representations, for example, if one padding bit is a parity bit."


    the "padding bits of doom" claim was that if you read out the
    representation as unsigned chars, then copy it into another variable at
    a later date, those padding bits might be valid anymore - i.e. the DS9K
    might suddenly flip all padding bits to 1 and places with 0s would
    suddenly become trap representations.

    > But I don't see anything in the standard about trap representations,
    > which even suggests that trap representations can change during the
    > execution of a program.
     
    Jordan Abel, Dec 6, 2005
    #14
  15. On Mon, 05 Dec 2005 23:35:11 GMT, in comp.lang.c , pete
    <> wrote:

    >
    >But I don't see anything in the standard about trap representations,
    >which even suggests that trap representations
    >can change during the execution of a program.


    Absence of a mention merely means that the standard places no
    requirements on it.
    In this case, the definition of trap representation (6.2.6.1p5)
    doesn't say that it may /not/ change during execution, so you can't
    assume it remains constant.

    >The only reference to trap representations
    >connected with pointers is"
    >
    >5 An integer may be converted to any pointer type.
    >Except as previously specified,
    >the result is implementation-defined,
    >might not be correctly aligned,
    >might not point to an entity of the referenced type,
    >and might be a trap representation.
    >
    >I read the commas and the "and" of
    > "this, that, and the other"
    >as
    > "this, and that, and the other"


    I believe it means that at least zero of the conditions might apply to
    any instance of such a conversion.

    ----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
    http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
    ----= East and West-Coast Server Farms - Total Privacy via Encryption =----
     
    Mark McIntyre, Dec 6, 2005
    #15
  16. Christopher Benson-Manica

    Alex Fraser Guest

    "pete" <> wrote in message
    news:...
    [snip]
    > 5 An integer may be converted to any pointer type.
    > Except as previously specified,
    > the result is implementation-defined,
    > might not be correctly aligned,
    > might not point to an entity of the referenced type,
    > and might be a trap representation.
    >
    > I read the commas and the "and" of
    > "this, that, and the other"
    > as
    > "this, and that, and the other"
    > rather than as
    > "this, or (that, and the other)"


    I read the above as:

    Except as previously specified,
    the result is implementation defined,
    [the result] might not be correctly aligned,
    [the result] might not point to an entity of the referenced type, and
    [the result] might be a trap representation.

    Alex
     
    Alex Fraser, Dec 6, 2005
    #16
  17. Christopher Benson-Manica

    pete Guest

    Jordan Abel wrote:

    > the "padding bits of doom" claim was that if you read out the
    > representation as unsigned chars,
    > then copy it into another variable at
    > a later date, those padding bits might be valid anymore - i.e.
    > the DS9K
    > might suddenly flip all padding bits to 1 and places with 0s would
    > suddenly become trap representations.


    The value of the padding bits wouldn't change.
    The problem would be if the trap representation changed.

    --
    pete
     
    pete, Dec 6, 2005
    #17
  18. Christopher Benson-Manica

    Tim Rentsch Guest

    (Richard Bos) writes:

    > Keith Thompson <> wrote:
    >
    > > Jack Klein <> writes:
    > > > On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
    > > > <> wrote in comp.lang.c:
    > > >> Does the following program exhibit undefined behavior? Specifically,
    > > >> does passing a struct by value cause undefined behavior if that struct
    > > >> has as a member a pointer that has been passed to free()?
    > > >
    > > > I'm not sure why you make a distinction between a pointer in a
    > > > structure passed by value, and a bare pointer passed by value. Also
    > > > I'm not sure why you make a distinction between a pointer that has an
    > > > indeterminate value because it is uninitialized, or because it points
    > > > to previously allocated storage that has been freed.
    > > >
    > > >> #include <stdlib.h>
    > > >>
    > > >> struct stype
    > > >> {
    > > >> int *foo;
    > > >> };
    > > >>
    > > >> void bar( struct stype foo )
    > > >> {
    > > >> }
    > > >>
    > > >> int main( void )
    > > >> {
    > > >> struct stype baz;
    > > >> baz.foo=malloc( sizeof *baz.foo );
    > > >> free( baz.foo );
    > > >> bar( baz ); /* UB or not? */
    > > >> return 0;
    > > >> }
    > > >
    > > > In several places, the C standard refers to function call arguments
    > > > being stored into the function's parameters by assignment. So passing
    > > > anything to a function in C is essentially the same as assigning it to
    > > > the function's local parameter value.
    > > >
    > > > Assignment in C is always based on value, so passing anything with
    > > > indeterminate value, other than an unsigned char, to a function is
    > > > undefined behavior, as is any other use of the value of such an
    > > > object. It makes no difference whether the object with indeterminate
    > > > value is part of a structure, nor does it make any difference how the
    > > > value became indeterminate.

    > >
    > > But DR #222 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_222.htm>
    > > says:
    > >
    > > The value of a struct or union object is never a trap
    > > representation, even though the value of a member of a struct or
    > > union object may be a trap representation.

    >
    > That's weird. I would've thought this would only make sense for unions,
    > not structs. [...stuff about unions...]
    >
    > For a struct, this is much simpler: all members must be valid for it to
    > be a valid object. Assigning a non-trap value to a single struct member
    > is already guaranteed not to assign a trap value to any other member of
    > the struct, unlike in unions.


    Pshaw. Do you mean to say that for

    struct small_stack_of_int {
    int values[100];
    int first_empty_slot;
    };

    that all elements of the 'values' array must have been assigned, even
    if the relation 'first_empty_slot == 0' is true?

    It makes perfect sense for struct objects to be partially valid, with
    one field (or sometimes more) indicating which other fields may be
    accessed. The pattern is quite common, showing up in various kinds
    of buffers all the time.

    The rule in the DR, and now in n1124, is IMO the most sensible
    expression for how non-completely-valid structs should be
    expected to behave.
     
    Tim Rentsch, Dec 8, 2005
    #18
    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. Patricia  Van Hise

    structs with fields that are structs

    Patricia Van Hise, Apr 5, 2004, in forum: C Programming
    Replies:
    5
    Views:
    651
    Al Bowers
    Apr 5, 2004
  2. Chris Hauxwell

    const structs in other structs

    Chris Hauxwell, Apr 23, 2004, in forum: C Programming
    Replies:
    6
    Views:
    565
    Chris Hauxwell
    Apr 27, 2004
  3. Paminu
    Replies:
    5
    Views:
    651
    Eric Sosman
    Oct 11, 2005
  4. Daniel Rudy
    Replies:
    15
    Views:
    1,422
    Keith Thompson
    Apr 10, 2006
  5. Tuan  Bui
    Replies:
    14
    Views:
    494
    it_says_BALLS_on_your forehead
    Jul 29, 2005
Loading...

Share This Page