freeing memory....partially

F

f.oppedisano

Hi,
i would like to allocate two structures making only one malloc call.
So i do prt=malloc(sizeof(struct1)+sizeof(struct2));
After this operation i make two pointers one to the first struct (ptr1=ptr),
the other to second struct(ptr2=ptr+sizeof(struct2)).
These two pointer are later used by two threads in mutual exclusion so
thread1 can't access ptr2 and thread2 can't access ptr1.
At some time thread2 wants to free his part of memory but a
free(ptr2) or free((struct struct2 *)ptr) or something similar leads to
a SEGV. This happens, i think, because i must pass to free() a pointer
returned by a previous malloc call. But why this limitation?
Is it possible, in some way, to free only a part of the memory allocated
by malloc?
Remember that i cannot use realloc beacause thread2 cannot access ptr1.

Thank u very much
Francesco Oppedisano
 
R

rihad

Hi,
i would like to allocate two structures making only one malloc call.
So i do prt=malloc(sizeof(struct1)+sizeof(struct2));
After this operation i make two pointers one to the first struct (ptr1=ptr),
the other to second struct(ptr2=ptr+sizeof(struct2)).

If ptr is of type (struct1 *), then
struct2 *ptr2 = (void *) (ptr+1);
will suffice.
These two pointer are later used by two threads in mutual exclusion so
thread1 can't access ptr2 and thread2 can't access ptr1.
At some time thread2 wants to free his part of memory but a
free(ptr2) or free((struct struct2 *)ptr) or something similar leads to
a SEGV. This happens, i think, because i must pass to free() a pointer
returned by a previous malloc call. But why this limitation?

Easy: free() expects whatever malloc() returned, and nothing else (barring NULL,
ofcourse). It's undefined behaviour otherwise.
Is it possible, in some way, to free only a part of the memory allocated
by malloc?

Hmm, yes, do a realloc() to shrink the memory.
Remember that i cannot use realloc beacause thread2 cannot access ptr1.

Then all bets are off. Try redesigning your code!
 
R

rihad

Easy: free() expects whatever malloc() returned, and nothing else (barring NULL,
ofcourse).

The part in parentheses is superfluous. Let's optimize it away:

Easy: free() expects whatever malloc() returned, and nothing else.
 
S

Scott Fluhrer

Hi,
i would like to allocate two structures making only one malloc call.
So i do prt=malloc(sizeof(struct1)+sizeof(struct2));
After this operation i make two pointers one to the first struct (ptr1=ptr),
the other to second struct(ptr2=ptr+sizeof(struct2)).
If ptr is of type (struct1*), and the structure alignments come out correct
(which you can't really find out in a platform independent way), the correct
way to do this is:
ptr2 = (struct2*)(ptr + 1);

If all you wanted to do was consolidate the allocations, a cleaner way would
be:

struct combined_struct {
struct1 s1;
struct2 s2;
};
struct combined_struct *p = malloc( sizeof *p );
/* Don't forget the malloc failure check */
ptr = &p->s1;
ptr2 = &p->s2;

This has the advantage that you don't have to worry about alignment, as the
compiler will take care of that for you.

However, this doesn't address the next requirement:
These two pointer are later used by two threads in mutual exclusion so
thread1 can't access ptr2 and thread2 can't access ptr1.
At some time thread2 wants to free his part of memory but a
free(ptr2) or free((struct struct2 *)ptr) or something similar leads to
a SEGV. This happens, i think, because i must pass to free() a pointer
returned by a previous malloc call. But why this limitation?
Is it possible, in some way, to free only a part of the memory allocated
by malloc?
No. it is not possible. Apart from realloc, the only way to free allocated
memory is to call free, which will free all the memory that malloc
allocated. To do what you want to do, you either need to:

- Malloc struct1 and struct2 separately, or
- Use a memory allocator that provides the additional functionality you
want.

BTW: why is allocating the two structures separately difficult?
 
B

Barry Schwarz

Hi,
i would like to allocate two structures making only one malloc call.
So i do prt=malloc(sizeof(struct1)+sizeof(struct2));
After this operation i make two pointers one to the first struct (ptr1=ptr),
the other to second struct(ptr2=ptr+sizeof(struct2)).

Several problems here. Assuming struct1 and struct2 are typedef names
for the appropriate structures and ptr1 and ptr2 are pointers to each
type:

You want ptr2 to point sizeof(struct1) bytes beyond ptr1, not
sizeof(struct2) bytes.

This is not the way pointer arithmetic works. Whenever you add a
quantity to a pointer, the compiler automatically factors in the size
of whatever the pointer points to. In this case, you would use
ptr2 = (struct2*)(ptr1+1)
which would cause ptr2 to have the value described above.

Attempting to use ptr2 after this type of calculation may produce
undefined behavior if the value ptr1+1 is not properly aligned for a
struct2. Consider the simple case where int is aligned on a multiple
of 4 and double is aligned on a multiple of 8.
typedef struct{int i;} struct1;
typedef struct{double d;} struct2;
malloc is guaranteed to return a value in ptr that is a multiple of 8.
This value can be assigned to ptr1 and is a suitable address for
struct1. ptr2 will be assigned a value 4 bytes greater than the value
in ptr1 which is guaranteed to be improperly aligned for struct2.

To make this work, you have to allocate enough space for the
maximum of sizeof(struct1) plus n*sizeof(struct2) plus
sizeof(struct2), where n is sufficiently large enough to make the
second term at least as big as the first. When you compute ptr2, it
needs to be:
ptr2 = (struct2*)ptr1 + n;
You can compute n at run time if need be with
n = sizeof(struct2)/sizeof(struct1) + 1;
These two pointer are later used by two threads in mutual exclusion so
thread1 can't access ptr2 and thread2 can't access ptr1.
At some time thread2 wants to free his part of memory but a
free(ptr2) or free((struct struct2 *)ptr) or something similar leads to
a SEGV. This happens, i think, because i must pass to free() a pointer
returned by a previous malloc call. But why this limitation?

The answer to the why is because that is what the language standard
says. Furthermore, there is no parameter to free stating how much
memory is to be freed so free will always release the same amount that
was originally requested. There is no capability to free part of the
allocation.
Is it possible, in some way, to free only a part of the memory allocated
by malloc?
Nope.

Remember that i cannot use realloc beacause thread2 cannot access ptr1.

Why do you need both structures in the same malloc? By your
description, the are never processed together. Independent objects
should be really independent.



<<Remove the del for email>>
 
M

Micah Cowan

Hi,
i would like to allocate two structures making only one malloc call.
So i do prt=malloc(sizeof(struct1)+sizeof(struct2));
After this operation i make two pointers one to the first struct (ptr1=ptr),
the other to second struct(ptr2=ptr+sizeof(struct2)).

This will only work if you are unlucky. ptr2's location may not
be correctly aligned for accesses to struct2's members: undefined
behavior is the result.

One thing that should work is to ensure that the size fed to
malloc() is twice the maximum of (sizeof struct1) and (sizeof
struct2), and do ptr2 = ((struct struct2 *)(ptr)) + 1.

This will work because, at any point you can validly treat ptr as
pointing to an array of char, an array of struct1 or an array of
struct2 to satisfy the standard's constraints (I think... can
anyone think of a reason why a standard-conformant implementation
could validly fail to digest such a hideous monstrosity)?

But there's no good reason to do this, so don't. Especially since
you can't do what you discuss below.
These two pointer are later used by two threads in mutual exclusion so
thread1 can't access ptr2 and thread2 can't access ptr1.
At some time thread2 wants to free his part of memory but a
free(ptr2) or free((struct struct2 *)ptr) or something similar leads to
a SEGV. This happens, i think, because i must pass to free() a pointer
returned by a previous malloc call. But why this limitation?
Is it possible, in some way, to free only a part of the memory allocated
by malloc?
Remember that i cannot use realloc beacause thread2 cannot access ptr1.

There is not a way to do what you wish. You really shouldn't
restrict yourself to a single malloc() call; use two.

-Micah
 
M

Martijn

Hi,
This will only work if you are unlucky. ptr2's location may not
be correctly aligned for accesses to struct2's members: undefined
behavior is the result.

On that same line: if one has a structure of strings (for example, info for
a file), like so:

struct filename
{
char *path;
char *name;
}

Is the following "valid" or undefined behaviour:

struct filename *fn_ptr;
char fullpath[MAX_PATH + 1];
int pathlength;

/* code to fetch the file path and */
/* determine the length of the path */

fn_ptr = malloc(sizeof(*fn_ptr)
+ strlen(fullpath) + 1);
/* check for errors */

fn_ptr->path = (char*)fn_ptr + sizeof(*fn_ptr);
fn_ptr->name = fn_ptr->path + pathlength;

strcpy(fp_ptr->path, fullpath);

I have code very similar to this in one of my DLLs. It works, but is it
defined behaviour/portable? Or does it suffer from the same allignment
problem? (I would think it is portable, BTW).
 
M

Martijn

i would like to allocate two structures making only one malloc call.
So i do prt=malloc(sizeof(struct1)+sizeof(struct2));
After this operation i make two pointers one to the first struct
(ptr1=ptr), the other to second struct(ptr2=ptr+sizeof(struct2)).
These two pointer are later used by two threads in mutual exclusion so
thread1 can't access ptr2 and thread2 can't access ptr1.
At some time thread2 wants to free his part of memory but a
free(ptr2) or free((struct struct2 *)ptr) or something similar leads
to
a SEGV. This happens, i think, because i must pass to free() a pointer
returned by a previous malloc call. But why this limitation?
Is it possible, in some way, to free only a part of the memory
allocated
by malloc?
Remember that i cannot use realloc beacause thread2 cannot access
ptr1.

The problem worsens if you want to only delete ptr1. How are you going to
tell free not to release _all_ of the memory it allocated the that pointer?
 
C

Chris Torek

Martijn said:
/* code to fetch the file path and */
/* determine the length of the path */

fn_ptr = malloc(sizeof(*fn_ptr)
+ strlen(fullpath) + 1);
/* check for errors */

fn_ptr->path = (char*)fn_ptr + sizeof(*fn_ptr);
fn_ptr->name = fn_ptr->path + pathlength;

strcpy(fp_ptr->path, fullpath);

I have code very similar to this in one of my DLLs. It works, but is it
defined behaviour/portable? Or does it suffer from the same allignment
problem? (I would think it is portable, BTW).

This code is OK, because "char *" is required to have the least
alignment constraints in C. Thus, no matter how big
"sizeof *fn_ptr" is, (char *)fn_ptr + sizeof *fn_ptr is
correctly aligned for more "char"s.

I would, however, write the assignment to fn_ptr->path as:

fn_ptr->path = (char *)(fn_ptr + 1);

which has exactly the same effect, but is more concise.
 
F

f.oppedisano

Thank you all very very much :)))
Some answers:
To shott
If all you wanted to do was consolidate the allocations, a cleaner way would
be:
struct combined_struct {
struct1 s1;
struct2 s2;
};
struct combined_struct *p = malloc( sizeof *p );
/* Don't forget the malloc failure check */
ptr = &p->s1;
ptr2 = &p->s2;
This has the advantage that you don't have to worry about alignment, as the
compiler will take care of that for you.

This is exactly the way the allocation is really made.
But te real problem was the free() function, so i didn't
explain that allocation in detail. Sorry :)
Bisides i cannot understand your second suggestion:

- Use a memory allocator that provides the additional functionality you
want.

Can u explain this please?

To Micah and Barry
As i wrote some lines above i really do ptr2 = &p->s2; so...no problem
about pointer arithmetic.

Regards
Francesco Oppedisano
 
B

Barry Schwarz

Hi,
This will only work if you are unlucky. ptr2's location may not
be correctly aligned for accesses to struct2's members: undefined
behavior is the result.

On that same line: if one has a structure of strings (for example, info for
a file), like so:

struct filename
{
char *path;
char *name;
}

Is the following "valid" or undefined behaviour:

struct filename *fn_ptr;
char fullpath[MAX_PATH + 1];
int pathlength;

/* code to fetch the file path and */
/* determine the length of the path */

fn_ptr = malloc(sizeof(*fn_ptr)
+ strlen(fullpath) + 1);
/* check for errors */

fn_ptr->path = (char*)fn_ptr + sizeof(*fn_ptr);
fn_ptr->name = fn_ptr->path + pathlength;

strcpy(fp_ptr->path, fullpath);

I assume you meant fn_ptr.
I have code very similar to this in one of my DLLs. It works, but is it
defined behaviour/portable? Or does it suffer from the same allignment
problem? (I would think it is portable, BTW).

path is OK because sizeof(char) is always 1 so the computed address is
"properly aligned." and points exactly 1 byte beyond the struct. You
could achieve the same with
fn_ptr->path = (char*)(fn_ptr+1);

name is properly aligned for the same reason (but obviously points
somewhere inside the string pointed to by path).


<<Remove the del for email>>
 
S

Scott Fluhrer

Thank you all very very much :)))
Some answers:
To shott



This is exactly the way the allocation is really made.
But te real problem was the free() function, so i didn't
explain that allocation in detail. Sorry :)
Bisides i cannot understand your second suggestion:

- Use a memory allocator that provides the additional functionality you
want.

Can u explain this please?
There's not much to explain. Your original question was "does the ANSI
mandated malloc/free functions allow me to partially free memory". The
answer is, of course, no [1]. Hence, this suggestion, which is to use
another memory allocator which does provide the additional functionality
(whether you find an existing library or write it yourself). Since you
really don't specify exactly what functionality you do need, I can't provide
much more of a suggestion.


[1] Apart from realloc. I know you know this, and that realloc will not
meet your needs. I need to put in this caveat so that my answer is, in
fact, technically correct.
 
F

f.oppedisano

There's not much to explain. Your original question was "does the ANSI
mandated malloc/free functions allow me to partially free memory". The
answer is, of course, no [1]. Hence, this suggestion, which is to use
another memory allocator which does provide the additional functionality
(whether you find an existing library or write it yourself). Since you
really don't specify exactly what functionality you do need, I can't provide
much more of a suggestion.

Any axample of such a library capable of freeing a
part of the memory allocated?

francesco
 

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,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top