472,958 Members | 2,271 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,958 software developers and data experts.

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)cyberspace.org | don't, I need to know. Flames welcome.
Dec 5 '05 #1
17 2744
On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
<at***@nospam.cyberspace.org> 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/~a...FAQ-acllc.html
Dec 5 '05 #2
Jack Klein <ja*******@spamcop.net> writes:
On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
<at***@nospam.cyberspace.org> 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) ks***@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.
Dec 5 '05 #3
Keith Thompson wrote:

Jack Klein <ja*******@spamcop.net> 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
Dec 5 '05 #4
pete <pf*****@mindspring.com> writes:
Keith Thompson wrote:
Jack Klein <ja*******@spamcop.net> 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) ks***@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.
Dec 5 '05 #5
Keith Thompson wrote:

pete <pf*****@mindspring.com> 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
Dec 5 '05 #6
Keith Thompson <ks***@mib.org> wrote:
Jack Klein <ja*******@spamcop.net> writes:
On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
<at***@nospam.cyberspace.org> 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
Dec 5 '05 #7
pete <pf*****@mindspring.com> writes:
Keith Thompson wrote:

pete <pf*****@mindspring.com> 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) ks***@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.
Dec 5 '05 #8
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
Dec 5 '05 #9
On 2005-12-05, pete <pf*****@mindspring.com> 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.
Dec 5 '05 #10
pete <pf*****@mindspring.com> 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) ks***@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.
Dec 5 '05 #11
Jordan Abel wrote:

On 2005-12-05, pete <pf*****@mindspring.com> 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
Dec 5 '05 #12
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
Dec 6 '05 #13
On 2005-12-05, pete <pf*****@mindspring.com> wrote:
Jordan Abel wrote:

On 2005-12-05, pete <pf*****@mindspring.com> 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.

Dec 6 '05 #14
On Mon, 05 Dec 2005 23:35:11 GMT, in comp.lang.c , pete
<pf*****@mindspring.com> 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 =----
Dec 6 '05 #15
"pete" <pf*****@mindspring.com> wrote in message
news:43***********@mindspring.com...
[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
Dec 6 '05 #16
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
Dec 6 '05 #17
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Keith Thompson <ks***@mib.org> wrote:
Jack Klein <ja*******@spamcop.net> writes:
On Mon, 5 Dec 2005 05:20:20 +0000 (UTC), Christopher Benson-Manica
<at***@nospam.cyberspace.org> 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.
Dec 9 '05 #18

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Seung-Uk Oh | last post by:
Hi, everyone! We are developing an application using both C and C++. We have defined a structure in a C program as follows: typedef struct node { struct node *next; int value; }List;
19
by: Method Man | last post by:
I understand that arrays and structs can't be passed by value into and out of functions since they can be arbitrarily big. My question is: Why are types allowed to be passed by value? Couldn't my...
8
by: kalinga1234 | last post by:
there is a problem regarding passing array of characters to another function(without using structures,pointer etc,).can anybody help me to solve the problem.
9
by: Just Me | last post by:
PARAFORMAT2 is a structure that SendMessage will return stuff in. Is the "ref" correct or since only a pointer is being passed should it be by value? Suppose I was passing data rather then...
5
by: Chris Ashley | last post by:
I'm getting a little confused at the behaviour of C# with one of my class constructors. A code example will probably help: public class RawBitmap { internal BITMAPFILEHEADER fileHdr; internal...
3
by: iu2 | last post by:
Hi all, I need your professional opinion about this. It is more a general programming dilemma rather then a C++ one, but since the project I write is in C++... We handle big structs of data....
8
by: S. | last post by:
Hi all, Can someone please help me with this? I have the following struct: typedef struct { char *name; int age; } Student;
2
by: jonpb | last post by:
Using .NET 3.5, I need to pass an array of structs as parameter to a C++ unmanaged function. The C++ dll stores some data in an unmanaged cache, the function writes the values into the array of...
0
by: mjaaland | last post by:
Hi! I've been working with DLLimports passing structs and various other parameters to unmanaged code. I had problems earlier sending pointer to structs to the unmanaged code, and this forum solved...
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
0
tracyyun
by: tracyyun | last post by:
Hello everyone, I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
2
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.