Segfault on free()ing the malloc()ed memory

A

arnuld

Here is what I have made a small program to gain the understanding of
malloc() and free(). I malloc() some memory, assign some value to it and
then free() it but I got Segfault whne I try to free() the
malloc()ed memory:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(void)
{
int x = 3;

int* px = malloc( 1 * sizeof(*px));
int* p2 = malloc( 1 * sizeof(*p2));

if( (NULL == px) || (NULL == p2) )
{
printf("malloc() failed\n");
}


px = &x;
p2 = px;

printf("x = %d\n", x);
printf("*px = %d\n", *px);
printf("*p2 = %d\n", *p2);

printf("&x = %p\n", (void*)&x);
printf("px = %p\n", (void*)px);
printf("p2 = %p\n", (void*)p2);

free(p2);
p2 = NULL;

printf("-------------- p2 freed and set NULL ---------------------------\n\n");

printf("x = %d\n", x);
printf("*px = %d\n", *px);

printf("&x = %p\n", (void*)&x);
printf("px = %p\n", (void*)px);
printf("p2 = %p\n", (void*)p2);


free(px);
px = NULL;

return 0;
}

================ OUTPUT =======================
[arnuld@dune programs]$ gcc -std=c99 -pedantic -Wall -Wextra test.c
[arnuld@dune programs]$ ./a.out
x = 3
*px = 3
*p2 = 3
&x = 0xbfee8e04
px = 0xbfee8e04
p2 = 0xbfee8e04
Segmentation fault
[arnuld@dune programs]$
 
I

Ian Collins

arnuld said:
Here is what I have made a small program to gain the understanding of
malloc() and free(). I malloc() some memory, assign some value to it and
then free() it but I got Segfault whne I try to free() the
malloc()ed memory:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(void)
{
int x = 3;

int* px = malloc( 1 * sizeof(*px));
int* p2 = malloc( 1 * sizeof(*p2));

if( (NULL == px) || (NULL == p2) )
{
printf("malloc() failed\n");
}


px = &x;
p2 = px;

You have just bladdered to two pointers.
printf("x = %d\n", x);
printf("*px = %d\n", *px);
printf("*p2 = %d\n", *p2);

printf("&x = %p\n", (void*)&x);
printf("px = %p\n", (void*)px);
printf("p2 = %p\n", (void*)p2);

free(p2);

Boing! You are attempting to free &x.
 
C

Chris Dollin

arnuld said:
Here is what I have made a small program to gain the understanding of
malloc() and free(). I malloc() some memory, assign some value to it

No, you don't; you bin the pointers you got, but you don't
assign any values to the mallocated memory.
and then free() it but I got Segfault whne I try to free() the
malloc()ed memory:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
int x = 3;

int* px = malloc( 1 * sizeof(*px));
int* p2 = malloc( 1 * sizeof(*p2));

You set `px` and `p2` to point to some mallocated store ...

....
px = &x;
p2 = px;

.... and then you throw away those pointers and replace both
of them with un-mallocated pointers to `x`.

....
free(p2); ....
free(px);
....

Both of these will get you Undefined Behaviour as you free a non-null
pointer that was not the result of a `malloc`. In this case you're
dead lucky, since the UB manifests as a segfault at the right time
and place. One is not always so fortunate.
 
A

arnuld

.... SNIP...
... and then you throw away those pointers and replace both
of them with un-mallocated pointers to `x`.

So you mean &x returns a pointer to x but int* is not a pointer but only a
type. So & is the operator that returns a pointer.
 
M

mohangupta13

Here is what I have made a small program to gain the understanding of
malloc() and free(). I malloc() some memory, assign some value to it and
then free() it but I got Segfault whne I try to free() the
malloc()ed memory:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
int x = 3;

int* px = malloc( 1 * sizeof(*px));
int* p2 = malloc( 1 * sizeof(*p2));
px points to the area allocated by malloc upto here
if( (NULL == px) || (NULL == p2) )
{
printf("malloc() failed\n");
}

px = &x;

now px points to the address of the integer variable x (yes &x returns
the address of x and int* is a type (a pointer to int type)
note 'x' was not allocated by malloc and the address of 'x' which is
in px here cannot be freeEd.
p2 = px;

printf("x = %d\n", x);
printf("*px = %d\n", *px);
printf("*p2 = %d\n", *p2);

printf("&x = %p\n", (void*)&x);
printf("px = %p\n", (void*)px);
printf("p2 = %p\n", (void*)p2);

free(p2);
p2 = NULL;

printf("-------------- p2 freed and set NULL ---------------------------\n\n");

printf("x = %d\n", x);
printf("*px = %d\n", *px);

printf("&x = %p\n", (void*)&x);
printf("px = %p\n", (void*)px);
printf("p2 = %p\n", (void*)p2);

free(px);

this is attempting to free the space occupied by variable 'x' which
was never allocated by malloc() and it causes undefined behavior.
px = NULL;

return 0;

}

================ OUTPUT =======================
[arnuld@dune programs]$ gcc -std=c99 -pedantic -Wall -Wextra test.c
[arnuld@dune programs]$ ./a.out
x = 3
*px = 3
*p2 = 3
&x = 0xbfee8e04
px = 0xbfee8e04
p2 = 0xbfee8e04
Segmentation fault
[arnuld@dune programs]$

--www.lispmachine.wordpress.com
my email is @ the above blog.
 
C

Chris Dollin

arnuld said:
So you mean &x returns a pointer to x
Yes.

but int* is not a pointer but only a type.

It's a (notation for a) pointer type.
So & is the operator that returns a pointer.

It's the operator that returns a pointer to its (lvalue) operand. If
the operand has type T, then the pointer has type T*.
 
G

Guest

it would be better if you left more conext in.
So you mean

no. He meant "you have overwritten the values in px and p2
which held pointers to the memory you have just allocated.

&x returns a pointer to x

&x evaluates to the address of
OR
&x evaluates to a pointer to x

but int* is not a pointer but only a type.

int* is a type of ptr-to-int. I'm not sure what you mean
So & is the operator that returns a pointer.

er, yes. Though I'm not sure what you by "so".

Syntactically
px = &x;

is perfectly valid. But semantically you've just
created a memory leak by discarding the only reference to
the malloc()ed memory. You may be on the right track but
your reasoming is not transparent to me.



a modified (and simplified) version of your code
*****************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
int x = 3;

int* px = malloc (1 * sizeof(*px));

if(NULL == px)
{
printf("malloc() failed\n");
}

*px = x;

printf("x = %d\n", x);
printf(px = %p\n", (void*)px);
printf("*px = %d\n", *px);

free (px);

return 0;
}

******************************************************

--
Nick Keighley

"When you are having a bad day and it seems like everybody is trying
to piss you off, remember that it takes 42 muscles to produce a
frown, but only 4 muscles to work the trigger of a good sniper
rifle."
 
B

Ben Bacarisse

pete said:
ISO/IEC 9899:1999 (E)

6.5.3.2 Address and indirection operators

Semantics

3 The unary & operator returns the address of its operand.

For the record, this has been changed to "yields the address" in a
recent draft. Yes, one can't complain when someone usesthe language
of the standard, but even formal documents make mistakes and this has
been recognised as something the should be corrected.
 
S

Stefan Ram

arnuld said:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int x = 3;
int* px = malloc( 1 * sizeof(*px));
int* p2 = malloc( 1 * sizeof(*p2));
if( (NULL == px) || (NULL == p2) )
{
printf("malloc() failed\n");
}
printf("p2 = %p\n", (void*)p2);
free(p2);
free(px);
}

Let me rewrite this in my style:

#include <stdio.h>
#include <stdlib.h>

void dump( char const * const s, void const * const p )
{ printf( "%s = %p\n", s, p ); }

void use2( int * const px, int * const p2 )
{ dump( "px", px );
dump( "p2", p2 ); }

void use1( int * const px )
{ int * p2 = malloc( sizeof( *p2 ));
if( p2 ){ use2( px, p2 ); free( p2 ); }
else printf( "malloc() failed\n" ); }

void use0()
{ int * px = malloc( sizeof( *px ));
if( px ){ use1( px ); free( px ); }
else printf( "malloc() failed\n" ); }

int main( void ){ use0(); }

Observe how I am using functions to split the task:

Each of the functions »use0« and »use1« is dedicated to do
all the memory management of one buffer and nothing else.

Since both functions are small, one can easily confirm that
the resource they manage is used and released if and only if
it has been allocated successfully before.

Exercise (difficult): The functions »use0« and »use1« are
very similar. Can you extract what they share into a single
function and then use this function twice, so as to eliminate
this redundancy?
 
S

Stefan Ram

Ben Bacarisse said:
For the record, this has been changed to "yields the address" in a
recent draft. Yes, one can't complain when someone usesthe language
of the standard, but even formal documents make mistakes and this has
been recognised as something the should be corrected.

Thanks for this information! I am always annoyed when people
use wordings like: the expression »2 + 4« /returns/ 6.«
I would say: the expression »2 + 4« /has/ the value 6.«,
but »yields« also is much better than »returns«.

A /function/ might return a value indeed,
but already a function /call/ does not return anything anymore,
but /has/ a value. So, for example, after

int f(){ return 2; }

, I would say that:

- f /returns/ 2, but
- the expression »f()« /has/ the value 2, or
the evaluation of »f()« /yields/ the value 2.
 
G

Guest

  Let me rewrite this in my style:

style?! style?!! You call *that* a style? :)

#include <stdio.h>
#include <stdlib.h>

void dump( char const * const s, void const * const p )
{ printf( "%s = %p\n", s, p ); }

void use2( int * const px, int * const p2 )
{ dump( "px", px );
  dump( "p2", p2 ); }

void use1( int * const px )
{ int * p2 = malloc( sizeof( *p2 ));
  if( p2 ){ use2( px, p2 ); free( p2 ); }
  else printf( "malloc() failed\n" ); }

void use0()
{ int * px = malloc( sizeof( *px ));
  if( px ){ use1( px ); free( px ); }
  else printf( "malloc() failed\n" ); }

int main( void ){ use0(); }

  Observe how I am using functions to split the task:
good

  Each of the functions »use0« and »use1« is dedicated to do
  all the memory management of one buffer and nothing else.

yes, but.

Whilst this sounds like a good idea I don't think it is practical
in, er, practice. One of the reasons for using malloc() is because
the usage pattern is unpredictable. Nicely matched malloc()s and
free()s don't always occur. Yes, they *must* match at some level
but not necessarily lexically.
  Since both functions are small, one can easily confirm that
  the resource they manage is used and released if and only if
  it has been allocated successfully before.

  Exercise (difficult): The functions »use0« and »use1« are
  very similar. Can you extract what they share into a single
  function and then use this function twice, so as to eliminate
  this redundancy

I seem to need to call a function with two different types.
Not too hard with a language that supports currying. All I can
come up with is an array of pointers. Or something nasty with a global
variable.
 
S

Stefan Ram

In normal discussion, people understand things like "cold temperature",
even though it's wrong and needlessly verbose. But in programming, a
pointer to int is different from a pointer to the address of an int.

C is moving into the »people« direction:

#include <stdio.h>

void f( void )
{ printf( "f\n" ); }

int main( void )
{ f();
(&f)();
(*f)();
(**f)(); }

This prints »f« four times, here. (I have not checked it with
ISO/IEC 9899:1999 (E), but with gcc.)

IIRC, this would not have been legal in older versions of C.
 
K

Keith Thompson

#include <stdio.h>

void f( void )
{ printf( "f\n" ); }

int main( void )
{ f();
(&f)();
(*f)();
(**f)(); }

This prints »f« four times, here. (I have not checked it with
ISO/IEC 9899:1999 (E), but with gcc.)

IIRC, this would not have been legal in older versions of C.

I'm fairly sure that this did not change between C90 and C99.

It probably did change between K&R1 and ANSI, but that's going back at
least 20 years.
 
B

Ben Pfaff

#include <stdio.h>

void f( void )
{ printf( "f\n" ); }

int main( void )
{ f();
(&f)();
(*f)();
(**f)(); }

This prints »f« four times, here. (I have not checked it with
ISO/IEC 9899:1999 (E), but with gcc.)

IIRC, this would not have been legal in older versions of C.

This has the same semantics in C89 and C99, so by "older versions
of C" I guess you must mean "over 20 years old".
 

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,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top