Undefined behaviour ?

F

Francis Moreau

Hello,

Can someone confirm that the follow piece of code has a undefined
behaviour according to the C spec ?

#include <stdio.h>

int main(void)
{
int *p;

if (1) {
int i = 12;
p = &i;
}
printf("i = %d\n", *p);
return 0;
}

Compiling this with 'gcc -Wall' doesn't output any warnings which I
find strange but since it should be an undefined behaviour, then gcc
can do anything here...

thanks
 
E

Eric Sosman

Francis said:
Hello,

Can someone confirm that the follow piece of code has a undefined
behaviour according to the C spec ?

#include <stdio.h>

int main(void)
{
int *p;

if (1) {
int i = 12;
p = &i;
}
printf("i = %d\n", *p);
return 0;
}

The behavior is undefined because the object denoted
by `i' is used outside the object's lifetime. See 6.2.4p2
and 6.2.4p5.
Compiling this with 'gcc -Wall' doesn't output any warnings which I
find strange but since it should be an undefined behaviour, then gcc
can do anything here...

Right. Compilers are not obliged to catch every misteak.
 
F

Francis Moreau

Francis Moreau said:








Yes, that's undefined behaviour. The object created by the block
scope declaration and identified by i ceases to exist when the
block exits. Any pointers to it take on indeterminate values.
3.1.2.4 of C89 says "The value of a pointer that referred to an
object with automatic storage duration that is no longer guaranteed
to be reserved is indeterminate." And the behaviour on
dereferencing a pointer-type object with an indeterminate value is
undefined. (See the definition of undefined behaviour, which
specifically lists this case - i.e. using indeterminately-valued
objects.)


Yes. The implementation is not required to diagnose this problem.

Thanks for your confirmation.
 
F

Francis Moreau

     The behavior is undefined because the object denoted
by `i' is used outside the object's lifetime.  See 6.2.4p2
and 6.2.4p5.


     Right.  Compilers are not obliged to catch every misteak.

Thanks for your confirmation.
 
H

Hamiral

Francis Moreau a écrit :
Hello,

Can someone confirm that the follow piece of code has a undefined
behaviour according to the C spec ?

#include <stdio.h>

int main(void)
{
int *p;

if (1) {
int i = 12;
p = &i;
}
printf("i = %d\n", *p);
return 0;
}

Compiling this with 'gcc -Wall' doesn't output any warnings which I
find strange but since it should be an undefined behaviour, then gcc
can do anything here...

thanks

Well I guess that the space used by i in the loop can be, after the
loop, used by variable declared after it...

For example :

int main(void)
{
int *p;
if(1) {
int i = 12;
p = &i;
}
int j = 42;
printf("i = %d\n", *p);
return 0;
}

Here the space used by i in the loop could be recycled and used for j,
so the output could be i = 42

Ham
 
S

Spiros Bousbouras

Can someone confirm that the follow piece of code has a undefined
behaviour according to the C spec ?

#include <stdio.h>

int main(void)
{
int *p;

if (1) {
int i = 12;
p = &i;
}
printf("i = %d\n", *p);
return 0;

}

Compiling this with 'gcc -Wall' doesn't output any warnings which I
find strange but since it should be an undefined behaviour, then gcc
can do anything here...

As others have pointed out already it is indeed UB. When I try
the code at http://tinyurl.com/gimpel-testing one of the
warnings I get is
Info 733: Assigning address of auto variable 'i' to outer
scope symbol 'p'

So it doesn't unequivocally pick up the UB but does give a useful
warning.
 
F

Falcon Kirtaran

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Francis said:
Hello,

Can someone confirm that the follow piece of code has a undefined
behaviour according to the C spec ?

#include <stdio.h>

int main(void)
{
int *p;

if (1) {
int i = 12;
p = &i;
}
printf("i = %d\n", *p);
return 0;
}

Compiling this with 'gcc -Wall' doesn't output any warnings which I
find strange but since it should be an undefined behaviour, then gcc
can do anything here...

thanks

In my experience gcc pretty well never warns about memory bugs such as
this. Valgrind, however, will likely tell you all about it.

- --
- --Falcon Darkstar Christopher Momot
- --
- --OpenPGP: (7902:4457) 9282:A431

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iQIcBAEBAgAGBQJKAcFzAAoJEKmxP9YxEE4r1mEP/1axKJt1OXCcBopG3cnEQwAD
fco1vgmreGSBYdDXwMcixtt9wx1ytUky2Jekscs33GdAo4nYfwWifK8ruJqSYKLc
HsFECl4ijiPezVrD9zv6kXdqn2diqm97wcpilCMqE8pcU8tyFhd6qr0GwPMPClTu
3gtnuxCAfLmsFv3yWFa++/K1JxPOID1FbYWXnQxHI4zTlaVIuroDEohZjrwITy3P
hkGWCsc+ZWsB6m15CpDfngreXC9psIy/ESl8jGeA3TMtP9cSlqlVlJlsdwStzrER
IZwNg4sVhNAhv2PMEkaPuOESXYSGbYrfMMXmbVACj44swNk1QqzkHBC17/mONFbb
IGkM8rVCJxE7NlDba8Iw6qOACwyGaA9nVssjmg07zqoo4Zui9E9BzqJdufLQ7ITy
egg2ztzANJMqPveLBIMiepPn37nmD6gMtCd6Entz26m/HYH7WzDTFxHcbBr25h6k
8hRKpDPbx1zhYMsrKIZq0w6rok5fXN8TJRmplsOvURHkBODRh2/Jya/3MKZL8Pyq
TbK3pZEsiwv6QZxY9yvn2BruGWqWV6kTL7cRGrD4vUDNzHBOGJO5d3luB5wkkH7A
I5Rz0FVieRF8/oTKbjfBqXv6OeF62rwrlpbZ0f1h4mIFxRs/Eyzoex9qLjUD06dr
6/DVPJexzhf6nMazPvCL
=Uu+w
-----END PGP SIGNATURE-----
 
K

Keith Thompson

Hamiral said:
Well I guess that the space used by i in the loop can be, after the
loop, used by variable declared after it...

For example :

int main(void)
{
int *p;
if(1) {
int i = 12;
p = &i;
}
int j = 42;
printf("i = %d\n", *p);
return 0;
}

Here the space used by i in the loop could be recycled and used for j,
so the output could be i = 42

Well, yes and no (or perhaps I should say no and yes).

The lifetime of any object with automatic storage duration begins on
entry to the block with which it is associated, and ends when
execution of the block ends. So the lifetime of j actually begins at
the opening brace, even though it's not visible until the declaration
is reached. Since the lifetimes of i and j overlap, they can't share
the same storage. (It's actually possible to access j before its
declaration is reached by saving its address somewhere and jumping to
the top of the block with a goto statement.)

On the other hand, the program's behavior is undefined, so the
implementation is free to make i and j share storage (though I can't
think of any good reason to do so).

On the other other hand, two objects whose lifetimes overlap, but
whose effective lifetimes are disjoint, can share the same storage if
the compiler is clever enough to perform such an optimization.
"Effective lifetime" is a term I just made up. Here's an example:

{
int i = 42;
printf("i = %d\n", i);
/* i is not used after this */
/* j is not used before this */
int j = 43;
printf("j = %d\n", j);
}

i and j are two distinct objects, but the compiler can make them share
the same storage as long as it doesn't affect the behavior of the
program. Shuffle the statements around a bit, and the optimization
becomes invalid.
 
H

Hamiral

Keith Thompson a écrit :
The lifetime of any object with automatic storage duration begins on
entry to the block with which it is associated, and ends when
execution of the block ends. So the lifetime of j actually begins at
the opening brace, even though it's not visible until the declaration
is reached. Since the lifetimes of i and j overlap, they can't share
the same storage. (It's actually possible to access j before its
declaration is reached by saving its address somewhere and jumping to
the top of the block with a goto statement.)

Oh ok, thank you for this clarification. I thought that it was obvious,
but what you say is more logical.
And I didn't really have this knowledge, I just guessed ;)

Ham
 
C

CBFalconer

Francis said:
Can someone confirm that the follow piece of code has a undefined
behaviour according to the C spec ?

#include <stdio.h>
int main(void) {
int *p;

if (1) {
int i = 12;
p = &i;
}

When you get here p points to i, which no longer exists. It went
out of scope. Undefined behaviour.
 
R

Richard Tobin

In my experience gcc pretty well never warns about memory bugs such as
this. Valgrind, however, will likely tell you all about it.

I don't think so. Valgrind only deals with malloc()ed objects.
In any case, there may well be nothing in the compield code to
indicate an error - the code maybe exactly the same as if p had
been declared at the function's outermost scope.

Finding this kind of bug with any degree of reliability requires flow
analysis; the assignment itself (which some tools warn about) is quite
legal. And as with so many cases, it's impossible to diagnose (at
compile time) in all cases, because whether p still contains the
address of i at the end of the block may depend on an arbitrary
computation.

-- Richard
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,084
Latest member
HansGeorgi

Latest Threads

Top