Help. What is the error?

P

param

The following C program segfaults on 64 bit Arch., but works fine on 32
bit.

int main()
{
int* p;
p = (int*)malloc(sizeof(int));
*p = 10;
return 0;
}

Why does it happen so?
 
R

Ravi Uday

remove the 'cast' to malloc and
#include <stlib.h>

will work fine on all platforms

- Ravi
 
V

Vimal Aravindashan

param said:
The following C program segfaults on 64 bit Arch., but works fine on 32
bit.

int main()
it should really be int main(void)
{
int* p;
p = (int*)malloc(sizeof(int));
As Ravi noted, remove the cast. And make sure you have included stdlib.h.
Also, check if malloc has succeeded before using it.
 
J

jacob navia

param said:
The following C program segfaults on 64 bit Arch., but works fine on 32
bit.

int main()
{
int* p;
p = (int*)malloc(sizeof(int));
*p = 10;
return 0;
}

Why does it happen so?

This will crash because:

1) You did not include the proper header to malloc.
2) The compiler assumes it is an unknown function that returns
the default result: an integer.
3) The compiler generates code to read an integer result from malloc
(32 bit integer) and then casts it to a 64 bit pointer. Some
bits of the pointer are lost.
4) Since you did a cast to (int *) the compiler will not warn you
about casting an integer to a pointer since it is explicitely
asked for.
5) You store the wrong address in the pointer and when you use it it
crashes.

jacob
 
F

Flash Gordon

Vimal said:
it should really be int main(void)


As Ravi noted, remove the cast. And make sure you have included stdlib.h.
Also, check if malloc has succeeded before using it.

In addition, without the cast the compiler was *required* to complain at
you because int and pointers are not assignment compatible. If param put
in the cast to shut the compiler up then it just goes to show *why* you
should never put in a cast to shut the compiler up, you only put in
casts (or make any other change) when you understand *why* the compiler
complained and exactly what the effect will be.

The generally preferred form for calling malloc around here is
p = malloc(N * sizeof *p);
where N is the number of items you want space for. So when, as in this
case, you want space for one item you can simplify it to
p = malloc(sizeof *p);
Far less typing, the compiler is *required* to complain if you forget to
include stdlib.h (unless you have done something else really stupid) and
easier to maintain since it does not need changing if you have to change
p from int* to long* or anything else.

All the advice from Ravi and Vimal was correct, although they have not
explained why, so I'll add that information.

The ANSI standard for C that was release in 1989 specified that if the
compiler has not seen a declaration for a function (or if it saw a
declaration that did not specify a return type) that it should assume
that the function returned an int. It also specified that it was
undefined behaviour (i.e. *anything* can happen) if this assumption was
made but the function actually returned something else.

On your 32 bit platform int and void* are both 32 bits and the same
method is being used to return either type so it just happens to do what
you expect.

On your 64 bit platform you probably have int as 32 bits and void* as 64
bits. So malloc returns a 64 bit pointer, but when main was compiled the
compiler assumed it would be getting a 32 bit int, so it only grabs half
of the address and then converts that in to a pointer which obviously
produces a garbage value. E.g. malloc returns a pointer with the bit
pattern of 0x1122334455667788 but main only "sees" 0x11223344 and
converts that to address 0x0000000011223344 which you are not allowed to
access.

It can also fail for other reasons on platforms where int and void* are
the same size, for example if addresses are returned in an address
register and integers in a data register, which does happen on some systems.

The morals of the story are *always* include the correct headers to
provide prototypes for the functions you will be using otherwise
anything might happen and don't go adding casts just to shut the
compiler up.

PS, Ravi, please put your reply *under* the text you are replying to not
above. It makes it *far* easier for people to follow the thread and is
generally considered here (and in a lot of other places) to be the
polite way to post.
 
K

Kenneth Brody

param said:
The following C program segfaults on 64 bit Arch., but works fine on 32
bit.

int main()
{
int* p;
p = (int*)malloc(sizeof(int));
*p = 10;
return 0;
}

Why does it happen so?

Another perfect example of "don't cast the return from malloc".

You have hidden the fatal error (can't implicitly convert from "int" to
"int*") with a non-fatal warning (the explicit cast).

You need to include <stdlib.h> to get malloc's prototype.

Why does it fail on one system and work on another? Because that's how
"undocumented behavior" behaves.

As for specifics, my guess is that sizeof(int)==sizeof(void*) on the 32-bit
platform, and sizeof(int)!=sizeof(void*) on the 64-bit one.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
S

Skarmander

Flash said:
The generally preferred form for calling malloc around here is
p = malloc(N * sizeof *p);

I'd rather write

p = malloc(N * sizeof(*p));

Yes, the parentheses are redundant. But scanning "N * sizeof *p" always
makes me think of "N * sizeof * p", which isn't good.

Of course, diff'rent strokes, and there's not much ground to gain on the
microscopic level, but still.

S.
 
R

Richard Tobin

Kenneth Brody said:
Another perfect example of "don't cast the return from malloc".

Too perfect if you ask me! Is this some kind of reverse troll?

-- Richard
 
F

Flash Gordon

Kenneth said:
Another perfect example of "don't cast the return from malloc".

You have hidden the fatal error (can't implicitly convert from "int" to
"int*") with a non-fatal warning (the explicit cast).

The standard does not say the diagnostic has to be fatal without the
cast. With the cast no diagnostic is required for the conversion (and
not all compilers will give you a warning), although under C99 I think a
diagnostic is required due to the lack of a declaration the the removal
of implicit int from the language.
You need to include <stdlib.h> to get malloc's prototype.

Why does it fail on one system and work on another? Because that's how
"undocumented behavior" behaves.

You mean "undefined behaviour" not "undocumented behaviour".
As for specifics, my guess is that sizeof(int)==sizeof(void*) on the 32-bit
platform, and sizeof(int)!=sizeof(void*) on the 64-bit one.

Indeed. Although for it to "work" requires more than just the sizes
matching, it also requires the same return mechanism for pointers and
integers.
 
J

jacob navia

Kenneth Brody wrote:
You need to include said:
Why does it fail on one system and work on another? Because that's how
"undocumented behavior" behaves.

The code will work if the returned pointer lies in the first 4GB
virtual memory space, it will crash if it doesn't.
 
K

Keith Thompson

jacob navia said:
Kenneth Brody wrote:

As others have pointed out, this is probably a typo for "undefined
behavior".
The code will work if the returned pointer lies in the first 4GB
virtual memory space, it will crash if it doesn't.

Not necessarily. It could work on a 64-bit system if 32-bit and
64-bit types happen to be passed as arguments in the same way, or if
int, void*, and int* are all 64 bits. It could either succeed or fail
on a 64-bit system with a pointer in the first 4GB of the virtual
memory space depending on whether the system is big-endian or
little-endian. It could fail on either a 32-bit or a 64-bit system if
integer and pointer arguments are passed by different mechanisms, for
example in different registers. It could misbehave without actually
crashing on a 64-bit system if the truncated pointer value happens to
be a valid and accessible address. And so on.

The OP asked about 32-bit and 64-bit systems. He gave no clue about
which systems he was using, and it's unwise and unnecessary to assume
he meant, say, x86-32 and x86-64.

Undefined behavior is undefined behavior. It can certainly be useful
to discuss what the likely consequences are, particularly in
debugging, but all such discussions are system-specific and can only
be in terms of likelihoods unless you go down to a level of detail
that's inappropriate for this newsgroup.

You cannot correctly claim that the code "will work" in some
circumstances or "will creash" in other circumstances.
 
K

Kenneth Brody

jacob said:
Kenneth Brody wrote:

(Yes, that was a typo for "undefined behavior".)
The code will work if the returned pointer lies in the first 4GB
virtual memory space, it will crash if it doesn't.

Not necessarily. I have seen platforms where the return value from a
function will be in one register for pointers, and a diferent register
for non-pointers. If you haven't properly declared the function as
returning a pointer, then the return value you look at has nothing to
do with the actual return value.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
J

jacob navia

Keith said:
The OP asked about 32-bit and 64-bit systems. He gave no clue about
which systems he was using, and it's unwise and unnecessary to assume
he meant, say, x86-32 and x86-64.

You are right. It can fail in many other ways.

jacob
 
M

Michael Wojcik

Not necessarily. I have seen platforms where the return value from a
function will be in one register for pointers, and a diferent register
for non-pointers. If you haven't properly declared the function as
returning a pointer, then the return value you look at has nothing to
do with the actual return value.

The ever-lovin' AS/400 (EPM C/400, to be precise, though this should
apply to all the AS/400 C implementations) was one where malloc
without a prototype never "worked". There, int is 32 bits and void*
is 128 bits; and more importantly, the implementation validates every
pointer at runtime. You can coerce an integer value into a pointer
type with a cast, but try to do anything with it and you get a
friendly machine check in your job.

Of course, all this just boils down to "not everything is a PC".

--
Michael Wojcik (e-mail address removed)

An intense imaginative activity accompanied by a psychological and moral
passivity is bound eventually to result in a curbing of the growth to
maturity and in consequent artistic repetitiveness and stultification.
-- D. S. Savage
 

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
474,170
Messages
2,570,925
Members
47,464
Latest member
Bobbylenly

Latest Threads

Top