Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Small C "Puzzle"

Reply
Thread Tools

Small C "Puzzle"

 
 
Keith Thompson
Guest
Posts: n/a
 
      08-28-2004
Jack Klein <> writes:
> On Fri, 27 Aug 2004 23:38:11 GMT, Keith Thompson <kst-> wrote
> in comp.lang.c:

[...]
> > In the absence of a visible prototype for malloc(), the compiler
> > assumes that it returns int. Since int is 32 bits, but the actual
> > void* value that malloc() *tries* to return is 64 bits, the result is
> > undefined behavior. In this case, the undefined behavior manifests
> > itself as returning the low-order (I think) 32 bits of the pointer
> > value.

>
> Doesn't make any difference what size int or pointers are. The code
> has undefined behavior because it calls ANY function with a return
> type other than int without a prototype in scope. Period. Size of
> anything irrelevant.


You're right, of course. (I did mention later that it's also
undefined behavior on the IA-32, where int and pointer types are the
same size, but in the quoted paragraph I inadvertently implied a
cause-and-effect relationship that doesn't exist.)

The difference in size does make a difference, in this case, in the
visible result of the undefined behavior.

--
Keith Thompson (The_Other_Keith) kst- <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.
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      08-28-2004
(Raju) writes:
[...]
> I am little confused about the explanation.
> I think size of "int" is size of processor register length.
> And malloc retuns 64 bit address and pointer is also 64 bit (whether
> int * or char *) , then where actually the size giving problem.


The size of "int" is whatever the compiler implementer decides it
should be. On the IA-64 (also known as Itanium), int is 32 bits, and
pointers are 64 bits. More precisely, these are the sizes chosen by
the compilers I'm familiar with on IA-64 systems (gcc and Intel's
compiler under Linux). Note that there's a strong motivation for
different compilers on the same system to be compatible with each
other.

Since the IA-64 is a 64-bit system, it's natural to assume that int
should be 64 bits, but that would actually cause some problems.
Currently, the types of the predefined integer types are:

char 8 bits
short 16 bits
int 32 bits
long 64 bits
long long 64 bits

If int were 64 bits, short would be either 16 or 32 bits, leaving a
gap in the type system. (C99 allows extended integer types, with
appropriate typedefs in <stdint.h>, but portable code can't yet depend
on this.)

> And can i know how the code below behaves on both platforms,
>
> int main()
> {
> char* p;
> p = (char*)malloc(sizeof(char));
> *p = 10;
> return 0;
> }


With the understanding that it's undefined behavior regardless
of the underlying system:

On IA-32: no ouput.
On IA-64: Segmentation fault.

Here's another program that shows more clearly what's going on:

#ifdef INCLUDE_STDLIB
#include <stdlib.h>
#endif
#include <stdio.h>
int main()
{
char* p;
p = (char*)malloc(sizeof(char));
printf("p = %p\n", p);
fflush(stdout);
*p = 10;
return 0;
}

On IA-32, this produces nearly the same output whether INCLUDE_STDLIB
is defined or not:

p = 0x8648008

(The specific address changes for some irrelevant reason.)

On IA-64, if INCLUDE_STDLIB is not defined, the output is:

p = 0xc80
Segmentation fault

If INCLUDE_STDLIB is defined, the output is:

p = 0x6000000000000c80

Of course none if this arises if you just write the code properly in
the first place: use a "#include <stdlib.h>" directive, and don't cast
the result of malloc().

--
Keith Thompson (The_Other_Keith) kst- <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.
 
Reply With Quote
 
 
 
 
Gordon Burditt
Guest
Posts: n/a
 
      08-28-2004
>If an int and a pointer are both 64 bits, then the undefined behaviour of
>calling malloc() without a protoype in scope should normally be the
>behaviour the programmer expects. In this case it appears that int was 32
>bits and pointers 64 bits, so the ujndefined beahviour instead manifested
>itself as a crash.


The unstated assumption here, which is false, is that the linkage
conventions for two types of the same size are the same. This is
often not true. Even on an Intel [3456]86 platform, integers and
floating point numbers are often (but not always) returned in a
different place.

For example, on a 680X0 processor it is quite possible (and logical)
to return pointers in the a0 register and integers in the d0 register
and floating point numbers in the top of the stack of the floating-point
unit. If the return type of the function is not known, the calling
code may retrieve the return value *FROM THE WRONG PLACE*. No amount
of casting the result will fix that.

>However there could be problems even if ints and pointers are the same
>width, for instance
>the act of loading an address into a data register could
>trigger a crash.

This I would think would be rather unusual. However, loading an
address register with uninitialized or otherwise arbitrary bit
patterns is much more likely to cause a crash.

>With undefined behaviour, you just don't know.


If you load data from the WRONG register, copying it to the "right"
register won't help, and the issue that loading crap into a register
might cause problems is a completely separate problem.

Gordon L. Burditt
 
Reply With Quote
 
Nudge
Guest
Posts: n/a
 
      08-29-2004
Mike Wahler wrote:

> I'm not familiar with the 'IA' machines, but apparently the
> puzzle is referring to the fact that trying to convert a pointer
> to an int and back to a pointer will *not* work correctly on
> those platforms.


AFAIK, IA stands for Intel Architecture.

Thus IA-32 is Intel's 32-bit ISA, i.e. x86, and IA-64 is Intel's
64-bit ISA, i.e. the Itanium Processor Family ISA.

--
Regards, Nudge

 
Reply With Quote
 
Minti
Guest
Posts: n/a
 
      08-29-2004

"Raju" <> wrote in message
news: om...
> > > The following C program segfaults of IA-64, but works fine on IA-32.
> > > int main()
> > > {
> > > int* p;
> > > p = (int*)malloc(sizeof(int));
> > > *p = 10;
> > > return 0;
> > > }
> > > Why does it happen so?
> > >
> > > Now I know that architecture dependant ...

> > The missing "#include <stdlib.h>" is exactly the problem.
> >
> > In the absence of a visible prototype for malloc(), the compiler
> > assumes that it returns int. Since int is 32 bits, but the actual
> > void* value that malloc() *tries* to return is 64 bits, the result is
> > undefined behavior. In this case, the undefined behavior manifests
> > itself as returning the low-order (I think) 32 bits of the pointer
> > value. Since the high-order bits include non-zero values, this loses
> > information. Casting to int* masks the error, and generates an
> > invalid pointer value (whose upper half happens to be all-bits-zero).
> > Dereferencing the pointer value on the next line causes more undefined
> > behavior, which manifests itself as a seg fault.
> >
> > It happens to work on IA-32 (more commonly known as x86) because int
> > and pointer types are both 32 bits. The phrase "happens to work"
> > means that the undefined behavior manifests itself as the program
> > doing what you expected it to do. (This is actually worse than what
> > happens on the IA-64, since it masks the error.)

>
> I am little confused about the explanation.
> I think size of "int" is size of processor register length.
> And malloc retuns 64 bit address and pointer is also 64 bit (whether
> int * or char *) , then where actually the size giving problem.




> And can i know how the code below behaves on both platforms,
>
> int main()
> {
> char* p;
> p = (char*)malloc(sizeof(char));
> *p = 10;
> return 0;
> }


Yup you are right. But you might note that even if a compiler is supporting
64 bit arch. It will in many cases keep int's to be 32 bit's { to keep
backward compatiblity for applications written assuming int to be 32 bits }
That said I think that is just a guess. For I really haven't used any 64 bit
compilers. Can anyone share the current trends in this 64 bit industry. gcc,
MS cl etc.



--
Imanpreet Singh Arora
If I would have only known, I would have been a locksmith.
-- Albert Einstein



 
Reply With Quote
 
Minti
Guest
Posts: n/a
 
      08-30-2004

"Jack Klein" <> wrote in message
news:...
> On Fri, 27 Aug 2004 23:38:11 GMT, Keith Thompson <kst-> wrote
> in comp.lang.c:
>
> > Robert Gamble <> writes:
> > > I was taking a look at some of the C puzzles at:
> > > http://purana.csa.iisc.ernet.in/~gkumar/cquestions.html and have not

had
> > > any trouble with any of them except for the first one which is

reproduced
> > > below:
> > >
> > > The following C program segfaults of IA-64, but works fine on IA-32.
> > > int main()
> > > {
> > > int* p;
> > > p = (int*)malloc(sizeof(int));
> > > *p = 10;
> > > return 0;
> > > }
> > > Why does it happen so?
> > >
> > > Now I know that architecture dependant behavior is off-topic, but I

don't
> > > really see anything wrong with the code (yes, stdlib.h is missing, int
> > > main(void), and malloc casted, but I don't think this has anything to

do
> > > with the point of the problem). Am I missing something here? I don't
> > > have access to an IA-64 machine, anyone who does have any insight?

> >
> > The missing "#include <stdlib.h>" is exactly the problem.
> >
> > In the absence of a visible prototype for malloc(), the compiler
> > assumes that it returns int. Since int is 32 bits, but the actual
> > void* value that malloc() *tries* to return is 64 bits, the result is
> > undefined behavior. In this case, the undefined behavior manifests
> > itself as returning the low-order (I think) 32 bits of the pointer
> > value.

>
> Doesn't make any difference what size int or pointers are. The code
> has undefined behavior because it calls ANY function with a return
> type other than int without a prototype in scope. Period. Size of
> anything irrelevant.



Yes, but the question is why it would work on IA-32 not IA-64. And IA-32 has
same size and representation specification for pointers and int's alike.


--
Imanpreet Singh Arora
If I would have only known, I would have been a locksmith.
-- Albert Einstein



 
Reply With Quote
 
Minti
Guest
Posts: n/a
 
      08-30-2004

"Keith Thompson" <kst-> wrote in message
news:...
> (Raju) writes:
> [...]
> > I am little confused about the explanation.
> > I think size of "int" is size of processor register length.
> > And malloc retuns 64 bit address and pointer is also 64 bit (whether
> > int * or char *) , then where actually the size giving problem.

>
> The size of "int" is whatever the compiler implementer decides it
> should be. On the IA-64 (also known as Itanium), int is 32 bits, and
> pointers are 64 bits. More precisely, these are the sizes chosen by
> the compilers I'm familiar with on IA-64 systems (gcc and Intel's
> compiler under Linux). Note that there's a strong motivation for
> different compilers on the same system to be compatible with each
> other.
>
> Since the IA-64 is a 64-bit system, it's natural to assume that int
> should be 64 bits, but that would actually cause some problems.
> Currently, the types of the predefined integer types are:
>
> char 8 bits
> short 16 bits
> int 32 bits
> long 64 bits
> long long 64 bits
>
> If int were 64 bits, short would be either 16 or 32 bits, leaving a
> gap in the type system. (C99 allows extended integer types, with
> appropriate typedefs in <stdint.h>, but portable code can't yet depend
> on this.)
>
> > And can i know how the code below behaves on both platforms,
> >
> > int main()
> > {
> > char* p;
> > p = (char*)malloc(sizeof(char));
> > *p = 10;
> > return 0;
> > }

>
> With the understanding that it's undefined behavior regardless
> of the underlying system:
>
> On IA-32: no ouput.
> On IA-64: Segmentation fault.
>
> Here's another program that shows more clearly what's going on:
>
> #ifdef INCLUDE_STDLIB
> #include <stdlib.h>
> #endif
> #include <stdio.h>
> int main()
> {
> char* p;
> p = (char*)malloc(sizeof(char));
> printf("p = %p\n", p);
> fflush(stdout);
> *p = 10;
> return 0;
> }
>
> On IA-32, this produces nearly the same output whether INCLUDE_STDLIB
> is defined or not:
>
> p = 0x8648008
>
> (The specific address changes for some irrelevant reason.)
>
> On IA-64, if INCLUDE_STDLIB is not defined, the output is:
>
> p = 0xc80
> Segmentation fault
>
> If INCLUDE_STDLIB is defined, the output is:
>
> p = 0x6000000000000c80
>
> Of course none if this arises if you just write the code properly in
> the first place: use a "#include <stdlib.h>" directive, and don't cast
> the result of malloc().



Why not cast? Are you saying this in context with the IA-64 thingy or just
as a general thingy? I probably have never understood the need to cast or
not to cast. I seem to consider it to be more of a matter of taste rather
than anything else now. I have seen lot of debate, Bjarne says use cast,
everyone here says no.



--
Imanpreet Singh Arora
If I would have only known, I would have been a locksmith.
-- Albert Einstein





 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      08-30-2004
Minti:

You e-mailed me a question in response to something I posted on this
thread. Please post any questions to the newsgroup. If you must send
me e-mail, don't use a spam-blocked return address. (If kissmyass.com
is meant to be a spam trap, you should pick a different one; it
happens to be a real domain, and you could be subjecting its owner to
spam that was meant for you.)

In answer to your question, it is never necessary to cast the result
of malloc() in C; it only masks errors. This is from the latest
version of the C FAQ (the web version hasn't yet been updated):

7.7: Why does some code carefully cast the values returned by malloc
to the pointer type being allocated?

A: Before ANSI/ISO Standard C introduced the void * generic pointer
type, these casts were typically required to silence warnings
(and perhaps induce conversions) when assigning between
incompatible pointer types.

Under ANSI/ISO Standard C, these casts are no longer necessary,
and in fact modern practice discourages them, since they can
camouflage important warnings which would otherwise be generated
if malloc() happened not to be declared correctly; see question
7.6 above. (However, the casts are typically seen in C code
which for one reason or another is intended to be compatible
with C++, where explicit casts from void * are required.)

References: H&S Sec. 16.1 pp. 386-7.

--
Keith Thompson (The_Other_Keith) kst- <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.
 
Reply With Quote
 
Minti
Guest
Posts: n/a
 
      08-30-2004

"Keith Thompson" <kst-> wrote in message
news:...
> Minti:
>
> You e-mailed me a question in response to something I posted on this
> thread. Please post any questions to the newsgroup. If you must send
> me e-mail, don't use a spam-blocked return address. (If kissmyass.com
> is meant to be a spam trap, you should pick a different one; it
> happens to be a real domain, and you could be subjecting its owner to
> spam that was meant for you.)




Thanks, my mail program is configured to send both mail and post it to the
newsgroup, however as a I later checked up after disconnecting that it had
failed to upload the message. Ooops.


Thanks. Again.

--
Imanpreet Singh Arora
Isingh A Acm Dot Org


 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      08-30-2004
Minti wrote:
> "Keith Thompson" <kst-> wrote in message
>

.... snip ...
>>
>> Of course none if this arises if you just write the code properly
>> in the first place: use a "#include <stdlib.h>" directive, and
>> don't cast the result of malloc().

>
> Why not cast? Are you saying this in context with the IA-64 thingy
> or just as a general thingy? I probably have never understood the
> need to cast or not to cast. I seem to consider it to be more of a
> matter of taste rather than anything else now. I have seen lot of
> debate, Bjarne says use cast, everyone here says no.


He is talking about C++. Here we talk about C. They are not the
same language.

--
"Churchill and Bush can both be considered wartime leaders, just
as Secretariat and Mr Ed were both horses." - James Rhodes.
"We have always known that heedless self-interest was bad
morals. We now know that it is bad economics" - FDR

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Small cameras getting too small? GRL Digital Photography 50 02-03-2006 03:12 AM
Small Square with small red X Peter Coddington Computer Support 4 01-03-2006 06:58 AM
Printer Sharing over a Small Network =?Utf-8?B?QS1yb24wNg==?= Wireless Networking 0 12-07-2004 10:59 PM
Problems sharing internet connection & files on small wireless net =?Utf-8?B?YmVuMjI=?= Wireless Networking 1 10-16-2004 12:09 PM
Best Small Wireless Equipment Bob La Londe Wireless Networking 1 08-21-2004 07:47 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57