void pointer cast segfaults

  • Thread starter Andreas Schmidt
  • Start date
A

Andreas Schmidt

I am trying to understand the behavior of void pointers. Can someone
explain to me why I get a segfault for the following program?

#include <stdio.h>

void* plusone(void* i){
int* arg = (int*)i;
int result = (*arg + 1);
return (void*)result;
}
int main(){
void* w1 = (void*)10;
void* result = plusone(w1);
printf("%d", *(int*)result);
}

According to gdb, the cast in the first line of plusone gives the segfault.
Why??

Markus

P.S.: I compiled with gcc 3.2.2
 
P

Peter Nilsson

Andreas said:
I am trying to understand the behavior of void pointers.

You're really trying to explain why accessing random addresses
causes your machine to segfault.
Can someone explain to me why I get a segfault for the
following program?

#include <stdio.h>

void* plusone(void* i){
int* arg = (int*)i;

The (int *) cast is unnecessary. But the conversion may fail if the
resulting pointer is not suitably aligned for an int.
int result = (*arg + 1);

You're trying to get an int value from memory you probably don't own.
return (void*)result;

The conversion of an int to a void * is implementation defined.
}
int main(){
void* w1 = (void*)10;

Again the conversion is implementation defined. It is utterly useless
in portable programming because you have _no idea_ what 10 will
represent when converted to a pointer.
void* result = plusone(w1);
printf("%d", *(int*)result);

Again you try and grab an int value from memory you don't own.

Also, without a trailing \n, you have no guarantee of output anyway.
}

According to gdb, the cast in the first line of plusone gives
the segfault.
Why??

What are you actually trying to do? If it is implementation specific,
then ask in an implementation specific newsgroup.

If you're just trying things, then realise that C is probably the
_worst_ language to learn through pure experimentation.
 
O

Old Wolf

Andreas said:
Can someone explain to me why I get a segfault for the
following program?

According to gdb, the cast in the first line of plusone
gives the segfault. Why??
#include <stdio.h>

int main(){
void* w1 = (void*)10;

In general, this is illegal: you cannot cast an int to a pointer.
In your case, you will probably end up with a pointer to address
number 10 on your PC.
void* result = plusone(w1);

Now let's look at plusone() (I have rearranged your post a little):
void* plusone(void* i){
int* arg = (int*)i;

You are casting the address 10 to be a pointer to int. This
may also be illegal (for example, on some systems, ints can
only reside at addresses that are a multiple of 4).
int result = (*arg + 1);

This is definitely a problem: you are retrieving an int from
address 10. On a system like Windows XP or Unix or Linux,
you will get a segmentation fault because your program
is not allowed to access address 10 (it can only access
addresses in its own address space).
return (void*)result;

Casting an int to a pointer -- illegal, as I mentioned before.

Now we're back to main():
printf("%d", *(int*)result);

Again, dereferencing a pointer to an address you probably
don't own, this will probably give you a segmentation fault.
}


I am trying to understand the behavior of void pointers.

Your code really has nothing to do with void pointers as such,
you could have used int pointers or char pointers and
got the same problems. Generally, you cannot convert between
ints and pointers in this way.

A "void pointer" (or more accurately, a pointer-to-void) is
a pointer where you don't know the type of what it's pointing
to. You can convert other POINTERS into void pointers, and
convert them back again. You can't convert ints etc. into
void pointers.

Here's an example of what you can do:

void plusone(void *ptr)
{
*(int *)ptr += 1;
}

int main()
{
int x = 5;
void *ptr = &x;
plusone(ptr);
printf("%d\n", x);
}
 
A

Andreas Schmidt

The conversion of an int to a void * is implementation defined.


Again the conversion is implementation defined. It is utterly useless
in portable programming because you have _no idea_ what 10 will
represent when converted to a pointer.

I don't think it's utterly useless. The following program works fine:

#include <stdio.h>
int main(){
void* i = (void*)10;
printf("%d\n", (int*)i);
return 0;
}

What do you mean by "implementation specific"? Are you saying I'm just
lucky that it compiles and runs, but it depends on the implementation of
the compiler?
 
A

Andreas Schmidt

Andreas said:
The following program works fine:

#include <stdio.h>
int main(){
void* i = (void*)10;
printf("%d\n", (int*)i);
return 0;
}

OK, now I understand I am really just printing the pointer address here...

A.
 
K

Keith Thompson

Andreas Schmidt said:
OK, now I understand I am really just printing the pointer address here...

You *might* be printing the address. By using an int* argument with a
"%d" format, you're invoking undefind behavior. (In particular, it's
not uncommon for int and int* to have different sizes.)
 
E

Emmanuel Delahaye

Andreas Schmidt wrote on 05/05/05 :
#include <stdio.h>

void *plusone (void *i)
{
/* -ed- the value of i is unspecified */

int *arg = (int *) i;
/* -ed- the value of arg is unspecified */

int result = (*arg + 1);
/* -ed- the value of *arg is undefined */

return (void *) result;
/* -ed-
* I'm lost.
* Why in the world are you frankensteining your code like that ?
* Cast is evil, didn't your mom told you that before ?
*/
}

int main (void)
{
/* -ed-
* the result of the conversion of an integer to a pointer constant
* is implementation defined. On my platform, the result is
unspecified.
*
* Using the value of w1 invokes an undefined behaviour.
*/
void *w1 = (void *) 10;

void *result = plusone (w1);
printf ("%d", *(int *) result);
}

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

..sig under repair
 
C

Cian

Andreas Schmidt said:
I am trying to understand the behavior of void pointers. Can someone
explain to me why I get a segfault for the following program?

#include <stdio.h>

void* plusone(void* i){
int* arg = (int*)i;
int result = (*arg + 1);
return (void*)result;
change this to: return (void*)&result;
return the address of result (cast to a void *) [or a pointer to result]
}
int main(){
void* w1 = (void*)10;
change this to: void* w1 = (void*)&10;

w1 is assigned the address of 10 (cast to a void *) [or a pointer to
address]
void* result = plusone(w1);
printf("%d", *(int*)result);
}


Cian
 
L

Lawrence Kirby

Andreas Schmidt said:
I am trying to understand the behavior of void pointers. Can someone
explain to me why I get a segfault for the following program?

#include <stdio.h>

void* plusone(void* i){
int* arg = (int*)i;
int result = (*arg + 1);
return (void*)result;
change this to: return (void*)&result;
return the address of result (cast to a void *) [or a pointer to result]
}
int main(){
void* w1 = (void*)10;
change this to: void* w1 = (void*)&10;

10 isn't an lvalue, it is not a valid operand for &. You could change it
to

int value = 10;
void *w1 = &value;
w1 is assigned the address of 10 (cast to a void *) [or a pointer to
address]

Since 10 is not an object or function it has no address.

Lawrence
 
J

Jim Hunter

Cian said:
void* plusone(void* i){
int* arg = (int*)i;
int result = (*arg + 1);
return (void*)result;
change this to: return (void*)&result;
return the address of result (cast to a void *) [or a pointer to result]

Not a good idea to return a pointer to a local variable.

Jim
 
K

Keith Thompson

Old Wolf said:
In general, this is illegal: you cannot cast an int to a pointer.

Not quite. C99 6.3.2.3p5 says:

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.

(The "previously specified" refers to null pointer constants.)
In your case, you will probably end up with a pointer to address
number 10 on your PC.

Probably. A footnote says:

The mapping functions for converting a pointer to an integer or an
integer to a pointer are intended to be consistent with the
addressing structure of the execution environment.

Of course, the result is vanishingly unlikely to be useful.
 
B

Barry Schwarz

You *might* be printing the address. By using an int* argument with a
"%d" format, you're invoking undefind behavior. (In particular, it's
not uncommon for int and int* to have different sizes.)

It also invokes undefined behavior in those cases where the value 10
does not represent the suitably aligned value for the address of an
int.


<<Remove the del for email>>
 
C

Christian Bau

Andreas Schmidt said:
I don't think it's utterly useless. The following program works fine:

#include <stdio.h>
int main(){
void* i = (void*)10;
printf("%d\n", (int*)i);
return 0;
}

What do you mean by "implementation specific"? Are you saying I'm just
lucky that it compiles and runs, but it depends on the implementation of
the compiler?

No, you are extremely unlucky.

Luck is when a crappy program crashes on you, giving you the chance the
fix it and may be to learn something.
 

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

Similar Threads

void * 10
pointer addresses 15
void * and explicit cast 22
cast function pointer to void* 10
Array of structs function pointer 10
int** to void** 39
arithmetic on a void * pointer 140
help a beginner with void function 9

Members online

No members online now.

Forum statistics

Threads
474,164
Messages
2,570,901
Members
47,439
Latest member
elif2sghost

Latest Threads

Top