Undefined behaviour ?

  • Follow


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
0
Reply francis.moro (129) 5/6/2009 12:34:32 PM

Francis Moreau wrote:
> 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.

-- 
Eric Sosman
esosman@ieee-dot-org.invalid
0
Reply esosman2 (2945) 5/6/2009 12:47:16 PM


Francis Moreau 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;
> }

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.)

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

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

-- 
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
0
Reply rjh (10789) 5/6/2009 12:51:19 PM

On May 6, 2:51=A0pm, Richard Heathfield <r...@see.sig.invalid> wrote:
> Francis Moreau 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)
> > {
> > =A0int *p;
>
> > =A0 =A0 =A0 =A0 if (1) {
> > int i =3D 12;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 p =3D &i;
> > =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0 printf("i =3D %d\n", *p);
> > =A0 =A0 =A0 =A0 return 0;
> > }
>
> 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.)
>
> > 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...
>
> Yes. The implementation is not required to diagnose this problem.
>

Thanks for your confirmation.
0
Reply francis.moro (129) 5/6/2009 12:54:15 PM

On May 6, 2:47=A0pm, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
> Francis Moreau wrote:
> > 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)
> > {
> > =A0 =A0int *p;
>
> > =A0 =A0 =A0 =A0 if (1) {
> > =A0 =A0 =A0 =A0 =A0 =A0int i =3D 12;
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 p =3D &i;
> > =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0 printf("i =3D %d\n", *p);
> > =A0 =A0 =A0 =A0 return 0;
> > }
>
> =A0 =A0 =A0The behavior is undefined because the object denoted
> by `i' is used outside the object's lifetime. =A0See 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...
>
> =A0 =A0 =A0Right. =A0Compilers are not obliged to catch every misteak.
>

Thanks for your confirmation.
0
Reply francis.moro (129) 5/6/2009 12:54:30 PM

Francis Moreau a =E9crit :
> Hello,
>=20
> Can someone confirm that the follow piece of code has a undefined
> behaviour according to the C spec ?
>=20
> #include <stdio.h>
>=20
> int main(void)
> {
>  	int *p;
>=20
>         if (1) {
> 	        int i =3D 12;
>                 p =3D &i;
>         }
>         printf("i =3D %d\n", *p);
>         return 0;
> }
>=20
> 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...
>=20
> thanks

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

For example :

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

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

Ham
0
Reply hamiral (22) 5/6/2009 1:39:20 PM

Eric Sosman wrote:

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

Every missed steak :-)
0
Reply Boon 5/6/2009 2:10:39 PM

On 6 May, 13:34, Francis Moreau <francis.m...@gmail.com> wrote:
>
> 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.
0
Reply spibou (1037) 5/6/2009 4:54:28 PM

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

Francis Moreau wrote:
> 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-----
0
Reply falconnews1 (78) 5/6/2009 4:57:23 PM

Hamiral <hamiral@hamham.com> writes:
[...]
> 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.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
Reply kst-u (21474) 5/6/2009 5:56:06 PM

Keith Thompson a =E9crit :
> 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,=20
but what you say is more logical.
And I didn't really have this knowledge, I just guessed ;)

Ham
0
Reply hamiral (22) 5/6/2009 10:02:59 PM

Francis Moreau wrote:
> 
> 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.

>         printf("i = %d\n", *p);
>         return 0;
> }


-- 
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: <http://cbfalconer.home.att.net>
            Try the download section.


0
Reply cbfalconer (19183) 5/6/2009 10:31:00 PM

In article <gtsfhi$va2$2@akira.iridiumlinux.org>,

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

>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
-- 
Please remember to mention me / in tapes you leave behind.
0
Reply richard91 (3683) 5/7/2009 9:08:18 AM

12 Replies
25 Views

(page loaded in 0.136 seconds)


Reply: