Passing structs by value

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Christopher Benson-Manica

    #1

    Passing structs by value


    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)cybers pace.org | don't, I need to know. Flames welcome.
  • Jack Klein

    #2
    Re: Passing structs by value

    On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
    <ataru@nospam.c yberspace.org> wrote in comp.lang.c:
    [color=blue]
    >
    > 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()?[/color]

    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.
    [color=blue]
    > #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;
    > }[/color]

    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.l earn.c-c++

    Comment

    • Keith Thompson

      #3
      Re: Passing structs by value

      Jack Klein <jackklein@spam cop.net> writes:[color=blue]
      > On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
      > <ataru@nospam.c yberspace.org> wrote in comp.lang.c:[color=green]
      >> 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()?[/color]
      >
      > 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.
      >[color=green]
      >> #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;
      >> }[/color]
      >
      > 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.[/color]

      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_Keit h) kst-u@mib.org <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.

      Comment

      • pete

        #4
        Re: Passing structs by value

        Keith Thompson wrote:[color=blue]
        >
        > Jack Klein <jackklein@spam cop.net> writes:[/color]
        [color=blue][color=green]
        > > 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.[/color]
        >
        > 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.[/color]

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

        --
        pete

        Comment

        • Keith Thompson

          #5
          Re: Passing structs by value

          pete <pfiland@mindsp ring.com> writes:[color=blue]
          > Keith Thompson wrote:[color=green]
          >> Jack Klein <jackklein@spam cop.net> writes:[color=darkred]
          >> > 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.[/color]
          >>
          >> 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.[/color]
          >
          > I don't think that the undefined behavior
          > associated with accessing freed pointer values
          > has anything to do with traps.[/color]

          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_Keit h) kst-u@mib.org <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.

          Comment

          • pete

            #6
            Re: Passing structs by value

            Keith Thompson wrote:[color=blue]
            >
            > pete <pfiland@mindsp ring.com> writes:[/color]
            [color=blue][color=green]
            > > I don't think that the undefined behavior
            > > associated with accessing freed pointer values
            > > has anything to do with traps.[/color]
            >
            > 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.)[/color]

            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

            Comment

            • Richard Bos

              #7
              Re: Passing structs by value

              Keith Thompson <kst-u@mib.org> wrote:
              [color=blue]
              > Jack Klein <jackklein@spam cop.net> writes:[color=green]
              > > On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
              > > <ataru@nospam.c yberspace.org> wrote in comp.lang.c:[color=darkred]
              > >> 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()?[/color]
              > >
              > > 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.
              > >[color=darkred]
              > >> #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;
              > >> }[/color]
              > >
              > > 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.[/color]
              >
              > 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.[/color]

              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

              Comment

              • Keith Thompson

                #8
                Re: Passing structs by value

                pete <pfiland@mindsp ring.com> writes:[color=blue]
                > Keith Thompson wrote:[color=green]
                >>
                >> pete <pfiland@mindsp ring.com> writes:[/color]
                >[color=green][color=darkred]
                >> > I don't think that the undefined behavior
                >> > associated with accessing freed pointer values
                >> > has anything to do with traps.[/color]
                >>
                >> 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.)[/color]
                >
                > 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.[/color]

                The standard doesn't say the value is unspecified; it says it's
                indeterminate.
                [color=blue]
                > "An unspecified value cannot be a trap representation. "[/color]

                Right, so the two cases are mutually exclusive (presumably at the whim
                of the implementation) .
                [color=blue]
                > "The value of a pointer becomes indeterminate when
                > the object it points to reaches the end of its lifetime."[/color]

                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("Examini ng 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_Keit h) kst-u@mib.org <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.

                Comment

                • pete

                  #9
                  Re: Passing structs by value

                  Keith Thompson wrote:
                  [color=blue]
                  > (The set of representations
                  > that are trap representations can vary over time during the execution
                  > of the program.)[/color]

                  How do you know that?

                  --
                  pete

                  Comment

                  • Jordan Abel

                    #10
                    Re: Passing structs by value

                    On 2005-12-05, pete <pfiland@mindsp ring.com> wrote:[color=blue]
                    > Keith Thompson wrote:
                    >[color=green]
                    >> (The set of representations
                    >> that are trap representations can vary over time during the execution
                    >> of the program.)[/color]
                    >
                    > How do you know that?[/color]

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

                    Comment

                    • Keith Thompson

                      #11
                      Re: Passing structs by value

                      pete <pfiland@mindsp ring.com> writes:[color=blue]
                      > Keith Thompson wrote:
                      >[color=green]
                      >> (The set of representations
                      >> that are trap representations can vary over time during the execution
                      >> of the program.)[/color]
                      >
                      > How do you know that?[/color]

                      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_Keit h) kst-u@mib.org <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.

                      Comment

                      • pete

                        #12
                        Re: Passing structs by value

                        Jordan Abel wrote:[color=blue]
                        >
                        > On 2005-12-05, pete <pfiland@mindsp ring.com> wrote:[color=green]
                        > > Keith Thompson wrote:
                        > >[color=darkred]
                        > >> (The set of representations
                        > >> that are trap representations
                        > >> can vary over time during the execution
                        > >> of the program.)[/color]
                        > >
                        > > How do you know that?[/color]
                        >
                        > Yeah -
                        > that is one of the more controversial of the "DS9K claims" - IMO
                        > up there with the "padding bits of DOOM" one elsethread.[/color]

                        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

                        Comment

                        • pete

                          #13
                          Re: Passing structs by value

                          Keith Thompson wrote:
                          [color=blue]
                          > 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?[/color]

                          I don't know.
                          [color=blue]
                          > (The only difference between
                          > indeterminate and unspecified is that the former includes trap
                          > representations .)[/color]

                          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

                          Comment

                          • Jordan Abel

                            #14
                            Re: Passing structs by value

                            On 2005-12-05, pete <pfiland@mindsp ring.com> wrote:[color=blue]
                            > Jordan Abel wrote:[color=green]
                            >>
                            >> On 2005-12-05, pete <pfiland@mindsp ring.com> wrote:[color=darkred]
                            >> > 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?[/color]
                            >>
                            >> Yeah -
                            >> that is one of the more controversial of the "DS9K claims" - IMO
                            >> up there with the "padding bits of DOOM" one elsethread.[/color]
                            >
                            > 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."[/color]

                            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 .
                            [color=blue]
                            > 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.[/color]

                            Comment

                            • Mark McIntyre

                              #15
                              Re: Passing structs by value

                              On Mon, 05 Dec 2005 23:35:11 GMT, in comp.lang.c , pete
                              <pfiland@mindsp ring.com> wrote:
                              [color=blue]
                              >
                              >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.[/color]

                              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.
                              [color=blue]
                              >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"[/color]

                              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 =----

                              Comment

                              Working...