Prevent invalid memory access valgrind C - c

I am trying to understand why valgrind is screaming at me (pretty new to C programming and valgrind).
I implemented a generic linked list (found in github - thanks to fabianosalles) that holds struct that looks like this:
typedef struct symbol_entity
{
/* Symbol name */
char *name;
/* Symbol address */
unsigned int address;
/* Indicates if symbol is extern */
bool is_extern;
/* Indicates if symbol is entry */
bool is_entry;
/* Indicates if symbol is instruction */
bool is_instruction;
/* Indicates if symbol is opcode */
bool is_opcode;
} symbol_entity;
Furthermore, I implemented a method that insert data to the linked list called add_symbol_to_list_with_result.
It returns true and set result_symbol to the one who was added to list in case added successfully. Otherwise if symbol already exists it returns false and should initialize result_symbol to null. (maybe there is a better choice, you are more than welcome to suggest!)
bool add_symbol_to_list_with_result(linked_list **symbols, char *name, bool is_extern, bool is_entry, bool is_instruction, bool is_opcode, unsigned int address, symbol_entity **result_symbol)
{
*result_symbol = (symbol_entity *)verified_malloc(sizeof(symbol_entity));
(*result_symbol)->name = verified_malloc(sizeof(char) * strlen(name));
strncpy((*result_symbol)->name, name, strlen(name));
(*result_symbol)->is_extern = is_extern;
(*result_symbol)->is_entry = is_entry;
(*result_symbol)->is_instruction = is_instruction;
(*result_symbol)->address = address;
(*result_symbol)->is_opcode = is_opcode;
if (!list_contains(*symbols, *result_symbol))
{
list_add(*symbols, *result_symbol);
return TRUE;
}
free(*result_symbol);
result_symbol = NULL;
return FALSE;
}
list_add looks like:
void list_add(linked_list *list, void *data)
{
node_item *newNode;
if (list != NULL && data != NULL)
{
newNode = verified_malloc(sizeof(node_item));
newNode->data = verified_malloc(list->data_size);
memcpy(newNode->data, data, list->data_size);
if (list->head == NULL)
{
list->head = newNode;
list->tail = newNode;
}
else
{
list->tail->next = newNode;
list->tail = newNode;
}
list->count++;
}
}
and of course verified malloc looks like:
void *verified_malloc(long size)
{
void *ptr;
ptr = malloc(size);
if (ptr == NULL)
{
printf("Fatal error! Memory allocation failed!");
exit(1);
}
return ptr;
}
add_symbol_to_list_with_result method get called multiple times, and I can see in valgrind output stuff like that:
==9179== Uninitialised value was created by a heap allocation
==9179== at 0x402D17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9179== by 0x804C074: verified_malloc (in /home/user/.....)
==9179== by 0x804A0F5: list_add (in /home/user/.....)
==9179== by 0x804B4E6: add_symbol_to_list_with_result (in /home/user/.....)
=
.
.
.
==9179== Address 0x4263d94 is 0 bytes after a block of size 4 alloc'd
==9179== at 0x402D17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9179== by 0x804C074: verified_malloc (in /home/user/.....)
==9179== by 0x804B454: add_symbol_to_list_with_result (in /home/user/.....)
Any help with this type of output?
EDIT:
symbols is declared in a different C file:
linked_list *symbols;
linked_list initialized with this method:
linked_list *list_create(int dataSize, callback_free free_callback, callback_compare compare_callback)
{
linked_list *list;
if (dataSize > 0)
{
/* Initialize parameters in linked list */
list = (linked_list *)verified_malloc(sizeof(linked_list));
list->count = 0;
list->data_size = dataSize;
list->head = NULL;
list->tail = NULL;
list->callback_free = free_callback;
list->callback_compare = compare_callback;
}
return list;
}
and is passes to multiple methods using &symbols

Please try
(*result_symbol)->name = verified_malloc(sizeof(char) * (strlen(name)+1));
to account for the required "\0" at end of string.
And after line
strncpy((*result_symbol)->name, name, strlen(name));
include the line
(*result_symbol)->name[strlen(name)]='\0'
just to be sure.
Furthermore, I would guess an allocation problem for **symbol which goes into bool add_symbol_to_list_with_result - please show the allocation for **symbol.
Question
Is list->data_size equal to sizeof(symbol_entity)?
memcpy(newNode->data, data, list->data_size);
Please try
memcpy(newNode->data, data, sizeof(symbol_entity));
Memory handling
Please note that your memory handling of *result_symbol is not accurate: In case of return TRUE, you keep *result_symbol completely, although only char array of name pointer would be required (*result_symbol was copied.)
In case of return FALSE, you free *result_symbol, but not the name pointer.
In both cases some memory is lost.
Missing code
Yes, the additional code which you provided is useful. However, as larger parts, like the other typedef structdefinitions and any memory handling above the provided subroutines is missing, ... I can not see anything more. In the beginning, you refer to github. Do you have link to more (the full) code?

Related

Printing just some elements of a List using pointers

Create a function that receives two Lists (L1,L2), initialize L2, and insert in L2 the elements of L1 excluding the ones in odd postion (Assume that the first element of the list is in position zero). Then print L2.
My prof gave us the solution (below), but I need to create a main() that calls this function and returns L2, and since I'm a newbie nothing seems to work.
I tried initializing L1 and then calling the function, but all I got was a huge amount of errors.
That's the final function:
struct list{
int value;
struct list * nextPtr;
};
void createSubList(struct list * l1Ptr, struct list ** l2PtrPtr) {
init(l2PtrPtr);
while(l1Ptr!=NULL) {
pre_insert(l2PtrPtr, l1Ptr­>value);
l1Ptr = l1Ptr­>nextPtr;
if (l1Ptr != NULL)
l1Ptr = l1Ptr­>nextPtr;
}
}
I expect to see L2 printed after calling the function.
That's my final file:
#include <stdlib.h>
#include <string.h>
struct list {
int value;
struct list *nextPtr;
};
void init( struct list **ptrptr){
*ptrptr!=NULL;
}
void prn (struct list * lptr) {
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n'); }
void pre_insert(struct list ** ptrptr, int value){
struct list * tmp_ptr;
tmp_ptr=*ptrptr;
*ptrptr=(struct list *)malloc(sizeof(struct list));
(*ptrptr)->value=value;
(*ptrptr)->nextPtr=tmp_ptr;
}
void createSubList(struct list* l1Ptr, struct list** l2PtrPtr) {
init(l2PtrPtr);
while(l1Ptr!=NULL) {
pre_insert(l2PtrPtr, l1Ptr->value);
l1Ptr = l1Ptr->nextPtr;
if (l1Ptr != NULL)
l1Ptr = l1Ptr->nextPtr;
}
prn(l1Ptr);
}
void main(){
struct list* l1Ptr;
init(&l1Ptr);
struct list* l2ptr;
init(&l2ptr);
pre_insert(&l1Ptr , 1);
pre_insert(&l1Ptr , 2);
pre_insert(&l1Ptr , 3);
pre_insert(&l1Ptr , 4);
pre_insert(&l1Ptr , 5);
pre_insert(&l1Ptr , 6);
createSubList(l1Ptr,&l2ptr);
}
Errors I get:
[Finished in 0.1s with exit code -11]
[shell_cmd: gcc "/home/vittorio/Scrivania/CProjects/new.c" -o "/home/vittorio/Scrivania/CProjects/new" && "/home/vittorio/Scrivania/CProjects/new"]
[dir: /home/vittorio/Scrivania/CProjects]
[path: /home/vittorio/bin:/home/vittorio/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin]
Once you get the non-ASCII chars squared away. Take your implementation piece-by-piece. For starters, unless you are on a non-conforming system, the proper declarations for main are int main (void) and int main (int argc, char **argv) (which you will see written with the equivalent char *argv[]). note: main is a function of type int and it returns a value. See: C11 Standard §5.1.2.2.1 Program startup p1 (draft n1570). See also: What should main() return in C and C++?.
So, for conforming implementation, main() without arguments should be:
int main (void) {
struct list *l1Ptr = NULL;
struct list *l2ptr = NULL;
...
(note: just ditch your init() function, you don't need to function call overhead just to set a pointer NULL)
Next issue along the way is your pre_insert must distinguish between adding the 1st node to the list, and adding all others. For the 1st node, just set your *ptrptr to your initialize tmp_ptr to establish the head of the list. For the remaining nodes, you are using chaining where you set tmp_ptr->nextPtr = *ptrptr; to make the next pointer in the new node point to the old-start of your list, then set *ptrptr = tmp_ptr; to make it your new start of the list, e.g.
void pre_insert (struct list **ptrptr, int value)
{
struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
if (tmp_ptr == NULL) { /* validate EVERY allocation */
perror ("malloc-tmp_ptr");
exit (EXIT_FAILURE);
}
tmp_ptr->value = value; /* initialize struct members */
tmp_ptr->nextPtr = NULL;
if (!*ptrptr) /* if 1st node, simply assign */
*ptrptr = tmp_ptr;
else {
tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
*ptrptr = tmp_ptr; /* now set list to point to tmp */
}
}
Your createSubList had similar redundant logic, showing your were struggling. All you need is a simply 1/0 toggle to add or skip nodes from list1. For example:
void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
int i = 0;
while (l1Ptr != NULL) {
if (i == 0) { /* only store even nodes */
pre_insert (l2PtrPtr, l1Ptr->value);
i = 1;
}
else
i = 0;
l1Ptr = l1Ptr->nextPtr;
}
}
As discussed in the comments, you need a way to print your lists, and equally important, a way to free the memory allocated to the nodes where you are done with them. Simple functions are all you need, e.g.
void prnlist (struct list *lptr)
{
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n');
}
void freelist (struct list *lptr)
{
while (lptr) {
struct list *victim = lptr;
lptr = lptr->nextPtr;
free (victim);
}
}
(note: do you see why you have to save a pointer to the current node, and then advance the node before calling free on your victim?)
That's it, aside from my additional comments in-line. Putting it altogether you could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct list {
int value;
struct list *nextPtr;
};
void pre_insert (struct list **ptrptr, int value)
{
struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
if (tmp_ptr == NULL) { /* validate EVERY allocation */
perror ("malloc-tmp_ptr");
exit (EXIT_FAILURE);
}
tmp_ptr->value = value; /* initialize struct members */
tmp_ptr->nextPtr = NULL;
if (!*ptrptr) /* if 1st node, simply assign */
*ptrptr = tmp_ptr;
else {
tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
*ptrptr = tmp_ptr; /* now set list to point to tmp */
}
}
void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
int i = 0;
while (l1Ptr != NULL) {
if (i == 0) { /* only store even nodes */
pre_insert (l2PtrPtr, l1Ptr->value);
i = 1;
}
else
i = 0;
l1Ptr = l1Ptr->nextPtr;
}
}
void prnlist (struct list *lptr)
{
while (lptr) {
printf (" %d", lptr->value);
lptr = lptr->nextPtr;
}
putchar ('\n');
}
void freelist (struct list *lptr)
{
while (lptr) {
struct list *victim = lptr;
lptr = lptr->nextPtr;
free (victim);
}
}
int main (void) {
struct list *l1Ptr = NULL;
struct list *l2ptr = NULL;
for (int i = 1; i < 10; i++)
pre_insert (&l1Ptr , i);
createSubList (l1Ptr, &l2ptr);
prnlist (l2ptr); /* print list 2 */
freelist (l1Ptr); /* don't forget to free what you allocate */
freelist (l2ptr);
}
Example Use/Output
$ ./bin/llcreatesublist
1 3 5 7 9
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/llcreatesublist
==23324== Memcheck, a memory error detector
==23324== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23324== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==23324== Command: ./bin/llcreatesublist
==23324==
1 3 5 7 9
==23324==
==23324== HEAP SUMMARY:
==23324== in use at exit: 0 bytes in 0 blocks
==23324== total heap usage: 14 allocs, 14 frees, 224 bytes allocated
==23324==
==23324== All heap blocks were freed -- no leaks are possible
==23324==
==23324== For counts of detected and suppressed errors, rerun with: -v
==23324== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
You need to add #include <stdio.h>
In the init function the code *ptrptr!=NULL; shall be *ptrptr=NULL;, i.e. no !
Then change void main(){ to int main(){
That should solve the warnings.
Then you need to do the actual printing. So in main do:
prn(l1Ptr);
createSubList(l1Ptr,&l2ptr);
prn(l2ptr);
BTW: Notice that the prn(l1Ptr); inside createSubList will not print anything as l1Ptr is already NULL when you call prn. So you should simply delete that line.
With the above change your output should be:
6 5 4 3 2 1
2 4 6
The created sub-list is reverted compared to the original list due to use of pre_insert that adds new nodes in the front.

Error while trying to free memory

I'm take some errors trying free memory. A post all my code below.
I'm using ubuntu and I compile my code with gcc. But when I try execute my code I take an error while trying free memory.
I put comments on my code to explain my doubt. I'm working with stack structre.
How Do I free memory without take error to turn free memory for char?
If I whoud not free the memory allocated for the data (a char), and only to free the memory for the element (which contains the char data), which happens with memory allocated to the data? is it free?
ERROR
{
*** glibc detected *** ./pilha: free(): invalid next size (fast): 0x08b86018 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x74f82)[0xb7637f82]
./pilha[0x80485ba]
./pilha[0x804864c]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75dc4d3]
./pilha[0x8048411]
======= Memory map: ========
}
CODE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct Stack_element{
char *data;
struct Stack_element *next;
}Element;
typedef struct Position{
Element *top;
int size;
}stack;
void start(stack *aux){
aux->top = NULL;
aux->size = 0;
}
int push(stack *aux, char value){
Element *new_element;
if ((new_element = (Element*) malloc(sizeof(Element))) == NULL)
return -1; //an error occur
if ((new_element->data = (char*) malloc(sizeof(char))) == NULL)
return -1; //an error occur
strcpy(new_element->data, &value);
new_element->next = aux->top;
aux->top = new_element;
aux->size++;
}
int empty(stack *aux){
if ((aux->size) == 0){
return -1;
}
return 0;
}
char pop(stack *aux){
Element *element;
char value='0';
if (empty(aux)){
return '1';
}
element = aux->top;
aux->top = aux->top->next;
/*
To observe the line below. When a element exist in the stack and
I try remove this element, first I free the data in that node (element)
so I turn free memory allocated for the element.
If I didn't free data memory allocated before (in push fuction), I
don't get any error. But the memory allocated for the data, what happens?
Does is it continues allocated?
*/
value = *(element->data);
free(element->data);//THE ERROR OCCURS HERE, IN THIS LINE
free(element);//Just after free the data element memory, I also free the element's memory
aux->size--;
return value;
}
int main(){
stack p;
char value;
start(&p);
//no error occurs. there isn't any element at this moment.
printf("%c\n",pop(&p));
//valor = 't';
if (push(&p, 't')){
printf("Add a char\n");
}
pop(&p);//the error occurrs now, after insert an new element in the stack
printf("The End.");
}
In your code,
strcpy(new_element->data, &value);
is not correct. You have allocated memory for only one char which is not having space for null terminator. Instead you should use
*(new_element->data) = value;
Otherwise, with the improper usage of strcpy(), you'e messing up the allocated memory by making memory overrung which causes undefined behaviour.
At least this statement in function push is invalid
strcpy(new_element->data, &value);
You should write
if ( ( new_element->data = (char*) malloc( 2 * sizeof(char))) == NULL)
{
free( new_element );
return -1; //an error occur
}
new_element->data[0] = value;
new_element->data[1] = '\0';
Or
if ( ( new_element->data = (char*) malloc( sizeof(char))) == NULL)
{
free( new_element );
return -1; //an error occur
}
*new_element->data = value;
Function empty looks strange. Usually -1 is returned from a function when some error occurred. As for the function empty then neither error can occur. So it is better when the function returns 1 if the stack is empty. I would write it like
int empty( stack *aux )
{
return aux->size == 0;
}
Also it is not clear why function pop returns character '1' when the stack is empty. It would be better if it returns simply '\0'. So instead of
char pop(stack *aux){
Element *element;
char value='0';
if (empty(aux)){
return '1';
}
//,,
I would write
char pop(stack *aux){
if ( empty( aux ) ) return '\0';
Element *element;
//,,

Homework: Freeing data in a struct

I'm just learning to use valgrind and c, and I have an invalid free() output when trying to free data from a struct. I believe it's because data is not being freed from the struct correctly.
This is my struct:
typedef struct song_
{
char *artist;
char *title;
mtime *lastPlayed;
} song;
And this is the function which tries to free it:
void songDelete(song *s)
{
//artist
free(s->artist) ;
//title
free(s->title) ;
//time
if(NULL != s->lastPlayed)
mtimeDelete(s->lastPlayed) ;
//song
free(s);
}
mtime and mtimeDelete are some user-defined variables and methods, but I feel like they're not relevant to my question. I know it's wrong to ask someone to do my homework for me, I'd just like a push in the right direction if possible.
No, that's definitely the right way to do it.
So, if valgrind is complaining, it's probably because the values in artist, title or lastPlayed are not actually valid pointers.
That's the first thing I'd be checking.
In other words, make sure what you put in there are valid pointers. Simply creating a song with:
song *AchyBreakyHeart = malloc (sizeof (song));
won't populate the fields (they'll be set to arbitrary values). Similarly,
AchyBreakyHeart->artist = "Bill Ray Cyrus";
will populate it with a string constant rather than a valid pointer in the heap.
The ideal thing would be to have a "constructor", similar to the destructor you've provided, something like:
song *songCreate (char *artist, char *title, mtime *lastPlayed) {
song *s = malloc (sizeof (song));
if (s == NULL) return NULL;
s->artist = strdup (artist);
if (s->artist == NULL) {
free (s);
return NULL;
}
s->title = strdup (title);
if (s->title == NULL) {
free (s->artist);
free (s);
return NULL;
}
s->lastPlayed = mtimeDup (lastPlayed);
if (s->lastPlayed == NULL) {
free (s->title);
free (s->artist);
free (s);
return NULL;
}
return s;
}
This guarantees that the object is either fully constructed or not constructed at all (ie, no half-states).
Better yet would be to adapt the constructor/destructor pair to handle NULLs in conjuction with each other, to simplify the pair. First, a slightly modified destructor, the only change being that it can accept NULL and ignore it:
void songDelete (song *s) {
// Allow for 'songDelete (NULL)'.
if (s != NULL) {
free (s->artist); // 'free (NULL)' is valid, does nothing.
free (s->title);
if (s->lastPlayed != NULL) {
mtimeDelete (s->lastPlayed) ;
}
free (s);
}
}
Next, the constructor which, rather than trying to remember what has been allocated, instead sets them all to NULL initially and just calls the destructor if something goes wrong:
song *songCreate (char *artist, char *title, mtime *lastPlayed) {
// Create song, null all fields to ease destruction,
// then only return it if ALL allocations work.
song *s = malloc (sizeof (song));
if (s != NULL) {
s->artist = s->title = s->lastPlayed = NULL;
s->artist = strdup (artist);
if (s->artist != NULL) {
s->title = strdup (title);
if (s->title != NULL) {
s->lastPlayed = mtimeDup (lastPlayed);
if (s->lastPlayed != NULL) {
return s;
}
}
}
}
// If ANY allocation failed, destruct the song and return NULL.
songDelete (s);
return NULL;
}
Your code appears correct.
Make sure that your struct is initialized correctly (with pointers set to NULL or a valid value).
int main() {
song_ *s = calloc(sizeof(song_));
free(s);
return 0;
}
Did you create an object/pointer to your Struct using malloc (heap allocation)? or just song s; (stack allocation) ??
You can't free it if it hasn't been malloc'd, or in other words you can't free a variable on stack, it has to be on the heap.

C free function (not using malloc)

I'm writing my own memory allocation program (without using malloc) and now I'm stuck with the free function (asfree in my code). I believe the functionality for the allocation is all there, the only problem lays on the free function. So by running the code below I can allocate 32 blocks: each block has a size of 48 + 16 (size of header).
So how can I deallocate/free all of them just after I have allocated them? Could you have a look at my free function and point me at the right direction?
P.S.: This is for learning purposes. I'm trying to get my head around structs, linked lists, memory allocations.
Thanks in advance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFER_SIZE 2048
typedef struct blk_struct
{
size_t size_blk;
struct blk_struct *next;
char data[0];
}blk_struct;
struct blk_struct *first = NULL;
static char buffer[BUFFER_SIZE];
void *asalloc(size_t size)
{
int nunits = (size + sizeof(blk_struct));
static int val = 1;
blk_struct *block, *current;
//locate position for block
if(first == NULL)
{
block = (blk_struct *)&buffer[0];
// Sanity check size.
if(nunits > BUFFER_SIZE)
return NULL;
// Initialise structure contents.
block->size_blk = size;
block->next = NULL;
// Add to linked list.
first = block;
// Give user their pointer.
return block->data;
}
//create a free list and search for a free block
for(current = first; current != NULL; current = current->next)
{
// If this element is the last element.
if(current->next == NULL)
{
block = (blk_struct *) (current->data + current->size_blk);
// Check we have space left to do this allocation
if((blk_struct *) &block->data[size] >
(blk_struct *) &buffer[BUFFER_SIZE])
{
printf("No more space\n");
return NULL;
}
// Initialise structure contents.
block->size_blk = size;
block->next = NULL;
// Add to linked list.
current->next = block;
// Give user their pointer.
return block->data;
}
}
printf("List Error\n");
return NULL;
}
// 'Free' function. blk_ptr = pointer to the block of memory to be released
void asfree(void *blk_ptr)
{
struct blk_struct *ptr = first;
struct blk_struct *tmp = NULL;
while(ptr != NULL)
{
if(ptr == blk_ptr)
{
printf("Found your block\n");
free(blk_ptr);
break;
}
tmp = ptr;
ptr = ptr->next;
}
}
// Requests fixed size pointers
int test_asalloc(void)
{
void *ptr = NULL;
int size = 48;
int i = 1;
int total = 0;
do
{
ptr = asalloc(size);
if(ptr != NULL)
{
memset(ptr, 0xff, size);
printf("Pointer %d = %p%s", i, ptr, (i % 4 != 0) ? ", " : "\n");
// each header needs 16 bytes: (sizeof(blk_struct))
total += (size + sizeof(blk_struct));
i++;
}
asfree(ptr); // *** <--- Calls the 'free' function ***
}
while(ptr != NULL);
printf("%d expected %zu\nTotal size: %d\n", i - 1,
BUFFER_SIZE / (size + sizeof(blk_struct)), total);
}
int main(void)
{
test_asalloc();
return 0;
}
I can see some problems with your asfree.
You need to subtract sizeof(blk_struct) when looking for block head. As allocated data the user wants to free are right behind the header and you have pointer to that data, not the header.
The second problem is what to do when you get the header. You cannot just call free on the data. You need to have some flag in the header and mark the block as free. And next time you try to allocate a block you need to be able to reuse free blocks, not just creating new blocks at the end. It is also good to be able to split a large free block into two smaller. To avoid fragmentation is is needed to merge neighbour free blocks to one larger.
Currently I am writing an OS as a school project. I recommend you to use simple alocator working like this:
Blocks of memory have headers containing links to neighbour blocks and free flag.
At the beginning there is one large block with free flag covering whole memory.
When malloc is called, blocks are searched from first to last. When large enough block is found it is split into two(allocated one and free reminder). Pointer to allocated block data is returned.
When free is called, matching block is marked as free. If neighbour blocks are also free they are merged.
I think this is the basic to be able to do malloc and free without fragmentation and loosing memory.
This is how a structure of headers and footer can look like:
// Header of a heap block
typedef struct {
// Size of the block including header and footer
size_t size;
// Indication of a free block
bool free;
// A magic value to detect overwrite of heap header.
uint32_t magic;
} heap_block_head_t;
// Footer of a heap block
typedef struct {
// A magic value to detect overwrite of heap footer.
uint32_t magic;
// Size of the block
size_t size;
} heap_block_foot_t;
The heap full of blocks with headers and footers like the one above is much like a linked list. Blocks do not describe their neighbours explicitly, but as long as you now they are there you can find them easily. If you have a position of one header then you can add block size to that position and you have a position of a header of the next block.
// Get next block
heap_block_head_t *current = ....
heap_block_head_t *next = (heap_block_head_t*)(((void*) current) + current->size);
// Get previous block
heap_block_head_t *current = ....
heap_block_foot_t *prev_foot = (heap_block_foot_t*)(((void*) current) - sizeof(heap_block_foot_t));
heap_block_head_t *prev = (heap_block_head_t*)(((void*) prev_foot) + sizeof(heap_block_foot_t) - prev_foot->size);
// Not sure if this is correct. I just wanted to illustrate the idea behind.
// Some extra check for heap start and end are needed
Hope this helps.

malloc , how free return value in a function

My app is use in stlinux (sh4) and unfortunately valgrind does not support sh4 cpu.
since I saw memory leak with my app, I had used mtrace, and it confirmed that some memory is not free. The problem is, variable of malloc used in the return, therefore I do not have any idea, how could I free it (since if it would be free, then returning in the functions is meaningless)?
I had written cs_malloc (put bellow code from oscam-simple.c in above link), mtrace log says, that in line:
*tmp = malloc (size);
memory is not free
/* This function encapsulates malloc. It automatically adds an error message to the log if it failed and calls cs_exit(quiterror) if quiterror > -1.
result will be automatically filled with the new memory position or NULL on failure. */
void *cs_malloc(void *result, size_t size, int32_t quiterror){
void **tmp = result;
*tmp = malloc (size);
if(*tmp == NULL){
cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
if(quiterror > -1) cs_exit(quiterror);
} else {
memset(*tmp, 0, size);
}
return *tmp;
}
And then for malloc, I call it, like this:
// create the AES key entry for the linked list
if(!cs_malloc(&new_entry, sizeof(AES_ENTRY), -1)) return;
Please take a look at these 3 functions (which malloc is not free , and as other users said, valgrind claim that these codes cause memory leaks module-datastruct-llist.c
The memory leaks cause by 3 different parts:
in below codes "new" would never free , but since it use in return of that function, I don't have idea, how could I free it:
LL_NODE* ll_append_nolock(LLIST *l, void *obj)
{
if (l && obj) {
LL_NODE *new;
if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
new->obj = obj;
if (l->last)
l->last->nxt = new;
else
l->initial = new;
l->last = new;
l->count++;
return new;
}
}
also "l" use in below function, again since it use in return function, I have no idea how to free it. :
LLIST *ll_create()
{
LLIST *l = cs_malloc(&l, sizeof(LLIST), 0);
pthread_mutex_init(&l->lock, NULL);
return l;
}
same story with new :
LL_NODE *ll_prepend(LLIST *l, void *obj)
{
if (l && obj) {
LL_NODE *new;
if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
new->obj = obj;
ll_lock(l);
new->nxt = l->initial;
l->initial = new;
if (!l->last)
l->last = l->initial;
l->count++;
ll_unlock(l);
return new;
}
return NULL;
}
For more functions you could see module-datastruct-llist.c
Would highly appreciate, if any expert tell me, how could I fix that memory leak (if you feel, cs_malloc should be rewritten, or need to add new function, please write the source code you are meaning.
The most common implementations of malloc use heap memory, which is global, so it's very common to have storage allocated in one place passed around between a number of functions before it is finally freed.
Now, there are for instance calls to ll_append_nolock where you ignore the malloced return. I.e.
ll_append_nolock(it->l, obj);
so to avoid a leak you need to do what you do in other places, i.e let the calling function receive the allocated memory into a pointer:
LL_NODE *n = ll_append_nolock(l, obj);
/* do stuff with "n", which points to memory allocated under the name of "new" */
free(n);
And when you're through with n (which as noted above points to the storage allocted under the name "new", that is: same memory, different names), you free it.
HTH.
In your function cs_malloc the first parameter is result however you never assign to it in the function cs_malloc.
Later you use cs_malloc like this
if(!cs_malloc(&new,sizeof(LL_NODE), -1)) return NULL;
new->obj = obj;
which will not work since since "new" is left uninitialized
you should either assign to result in your cs_malloc or just return the block in cs_malloc, if you fail to allocate just return NULL instead.
e.g.
void *cs_malloc(size_t size, int32_t quiterror)
{
void* tmp = calloc(1,size);
if(tmp == NULL)
{
cs_log("Couldn't allocate memory (errno=%d %s)!", errno, strerror(errno));
if(quiterror > -1) cs_exit(quiterror);
}
return tmp;
}
and
if (new = cs_malloc(sizeof(LL_NODE),-1))
{
new->obj = obj;
}
else
{
return NULL;
}
#Anders
Thanks for reply , i would take consideration your note ,an would change it as u described to see memory leaks how it's goes...
How , this line should be change to the new cs_malloc function u had written:
1.
LLIST *l = cs_malloc(&l, sizeof(LLIST), 0);
pthread_mutex_init(&l->lock, NULL);
return l;
2.
if(!cs_malloc(&para,sizeof(struct read_thread_param), -1)) return FALSE;
para->id=i;

Resources