memory leak when calling pthread_exit() - c

i need to create a thread pool it,it works but in function do_work that the function pthread_create calls i have problem in the free (memory leak) just when calling pthread_exit()
*in function create threadpool i just initilaize the struct and call
function do work *
void* do_work(void* p)
{
threadpool* pool = (threadpool*)p;
work_t* work;
while(1)
{
pthread_mutex_lock(&pool->qlock);
if(pool->shutdown == 1)
{
pthread_mutex_unlock(&pool->qlock);
//pthread_exit(EXIT_SUCCESS);// here is the free problem when deleting it all good
return NULL;
}
while(!pool->qsize)
{
if(pthread_cond_wait(&pool->q_not_empty,&pool->qlock))
perror("pthread_cond_wait\n");
if(pool->shutdown)
break;
}
//Check if the system is shutting down
if(pool->shutdown == 1)
{
pthread_mutex_unlock(&pool->qlock);
//pthread_exit(EXIT_SUCCESS);y
return NULL;
}
work = pool->qhead; //set the cur variable.
pool->qsize--; //decriment the size.
if(pool->qsize == 0) {
pool->qhead = NULL;
pool->qtail = NULL;
}
else {
pool->qhead = work->next;
}
if(pool->qsize == 0 && ! pool->shutdown) {
//the q is empty again, now signal that its empty.
pthread_cond_signal(&(pool->q_empty));
}
pthread_mutex_unlock(&(pool->qlock));
(work->routine) (work->arg); //actually do work.
free(work);
}
}

The pattern looks like a fairly standard thread pool:
typedef struct {
pthread_mutex_t qlock;
pthread_cond_t q_not_empty;
volatile work_t *qhead;
volatile work_t *qtail;
size_t qsize; /* Not needed */
volatile int shutdown;
} threadpool;
Properly indenting OP's code would make it more readable.
However, the implementation looks odd. I would expect
void *do_work(void *poolptr)
{
threadpool *const pool = poolptr;
work_t *work;
pthread_mutex_lock(&(pool->qlock));
while (!(pool->shutdown)) {
if (!(pool->qhead)) {
/* Queue empty */
pthread_cond_wait(&(pool->q_not_empty), &(pool->qlock));
continue;
}
work = pool->qhead;
pool->qhead = work->next;
if (!pool->qhead)
pool->qtail = NULL;
work->next = NULL;
pthread_unlock(&(pool->qlock));
work->process(work);
pthread_lock(&(pool->qlock));
}
pthread_mutex_unlock(&(pool->qlock));
return (void *)0;
}
and the code that appends a new work item to the queue to be
void append(threadpool *pool, work_t *work)
{
work->next = NULL;
pthread_mutex_lock(&(pool->qlock));
if (pool->qtail) {
pool->qtail->next = work;
pool->qtail = work;
} else {
pool->qhead = work;
pool->qtail = work;
}
pthread_cond_signal(&(pool->q_not_empty));
pthread_mutex_unlock(&(pool->qlock));
}
It is difficult to say where OP's implementation leaks memory. The most likely candidate is OP's arg member in each work_t, if it is dynamically allocated.
My implementation above passes the entire work_t to the routine function, which I renamed to process. It is responsible for freeing the work structure, too. The minimal definition for the work structure is
typedef struct work_t {
struct work_t *next;
void (*process)(struct work_t *);
/* Optional other fields */
} work_t;
Other possible causes for the memory leaks is if the qsize member is not properly updated everywhere. Because there is no use for it, really, I just omit it altogether.
The simpler the code, the easier it is to avoid bugs.

Related

C. double free or corruption (!prev) Aborted (core dumped)

I'm trying to use a "fixed memory scheme" and pre-allocate memory & reuse it via alloc, init, free fashion as many times as possible.
free() will called at shutdown only, but I want to test many iterations.
Although I call my alloc function bn_tree_alloc_node_space_heap() & init function bn_tree_init_node_heap(), I can only call free function bn_tree_free_node_space once.
Below is a complete reproducible snippet of my memory management, maint_test.c:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#define BN_TREE_HEAP_SIZE 100
/*variables internal*/
typedef struct bntree_internals;
/*bn_tree_node is single bntree_t leaf*/
typedef struct bn_tree_node {
struct bn_tree_node* left;
struct bn_tree_node* right;
float* dataset;
float distance_to_neighbor;
int visited;
int heap_index;
} bn_tree_node;
/*tree*/
typedef struct {
/*in order to keep track of the bn-tree root*/
bn_tree_node* _root;
/*pointer to internal variables struct*/
struct bntree_internals* _internals;
} bntree_t;
/*bn tree leaf nodes heap*/
bn_tree_node* node_processing_space = NULL;
/*leaf nodes*/
void bn_tree_alloc_node_space_heap(int max_dimensions);
bn_tree_node*
get_pre_allocated_bn_tree_node_heap();
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions);
void bn_tree_free_node_space(bn_tree_node* nodes);
int main(int argc, char** argv) {
/*PROBLEM:called the alloc,init,free cycle several times, problem,
getting seg fault on 2nd call of free()*/
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
return (EXIT_SUCCESS);
}
void bn_tree_alloc_node_space_heap(int max_dimensions) {
if (NULL == node_processing_space) {
node_processing_space = (bn_tree_node*) calloc(BN_TREE_HEAP_SIZE, sizeof (bn_tree_node));
//TODO: bn_tree_set_k_dimensions (max_dimensions);
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
node_processing_space[i].dataset = (float*) calloc(max_dimensions, sizeof (float));
}
//bn_heap_tail_index = bn_heap_head_index = 0;
}
}
bn_tree_node* get_pre_allocated_bn_tree_node_heap() {
return node_processing_space;
}
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions) {
int i = 0;
int c = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
/*reset values */
if (NULL != nodes[i].dataset) {
c = 0;
for (; c < max_dimensions; c++) {
nodes[i].dataset[c] = FLT_MIN;
}
}
nodes[i].visited = 0;
nodes[i].distance_to_neighbor = FLT_MAX;
nodes[i].left = NULL;
nodes[i].right = NULL;
nodes[i].heap_index = -1;
}
}
/*PROBLEM is subsequent call to free(), but if I alloc again why cant I free again?*/
void bn_tree_free_node_space(bn_tree_node* nodes) {
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if (nodes[i].dataset) {
free(nodes[i].dataset);
}
}
free(nodes);
nodes = NULL;
}
Here is the output that I expect/want:
alloc
init
free
alloc
init
free
alloc
init
free
alloc
init
free
But Im getting this output/error:
alloc
init
free
alloc
init
double free or corruption (!prev)
Aborted (core dumped)
How can fix this?
Can't I do alloc,init,free as many times as I want (as long as I called alloc before free) OR I can do only alloc() once, then many init(), free() once?
Thanks a million & please be kind enough to provide concise answers with minimal changes.
The problem is that your bn_tree_free_node_space function takes, as its argument, a copy of the pointer variable - that is, you are passing the pointer by value - thus, the line nodes = NULL; at the end of that function only sets the local variable to NULL and does not change the value of the node_processing_space variable.
To fix this (with minimal changes to your code logic1), you need to pass that function a pointer to the pointer, and dereference that in the function. So, your function should look like this:
void bn_tree_free_node_space(bn_tree_node** nodes) // Argument is pointer-to-pointer
{
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if ((*nodes)[i].dataset) { // Now we need to use (*nodes) to get the underlying pointer
free((*nodes)[i].dataset); // ... same here
}
}
free(*nodes); /// ... and here
*nodes = NULL;
}
You will, of course, also need to change the function prototype (just before your main) to match the new definition:
void bn_tree_free_node_space(bn_tree_node** nodes); // Must match definition!
Fruther, you will (clearly) need to change the calls to that function to pass the address of the node_processing_space pointer:
bn_tree_free_node_space(&node_processing_space); // Likewise for the other 3 calls!
Feel free to ask for further clarification and/or explanation.
1 EDIT: There are other ways (some may argue better ways) to implement your system, and also other 'minor' issues in your code. However, you did explicitly ask for "concise answers with minimal changes," so I have endeavoured to comply with that request!

Why is there a Segmentation fault from trying to add to count and printf?

#include <stdio.h> /* the "QueueTypes.h" file, */
#include <stdlib.h> /* given above on lines 1:15, is */
#include "QueueImplementation.c"
void main(void){
Queue *que;
ItemType *num;
num = 0;
InitializeQueue(que);
int count = 0;
int check;
int i;
if(Empty(que) != 1){
count = count + 1;
}
printf("%d", count); <- segmentation fault
if(Remove(que, num) != 0){
count = count + 1; <- segmentation fault
}
These are the parts of the program that keep getting segmentation faults. Am I illegally accessing anything?
this is queueimplementation.c. When i remove the lines that are being pointed out, the program works fine and returns errors as normal.
/* ------------< begin file "QueueImplementation.c" >------------ */
#include <stdio.h> /* the "QueueTypes.h" file, */
#include <stdlib.h> /* given above on lines 1:15, is */
#include "QueueInterface.h" /* included in "QueueInterface.h" */
/* on line 3 of Program 7.4. */
void SystemError(char *errorMsg) {fprintf(stderr,errorMsg);}
void InitializeQueue(Queue *Q)
{
Q->Front = NULL;
Q->Rear = NULL;
}
/* -------------------- */
int Empty(Queue *Q)
{
return (Q->Front == NULL);
}
/* -------------------- */
int Full(Queue *Q)
{ /* we assume an already constructed queue, Q, is */
return 0; /* not full, since it could potentially grow */
} /* as a linked structure */
/* -------------------- */
int Insert(ItemType R, Queue *Q)
{
QueueNode *Temp;
/* attempt to allocate */
Temp = (QueueNode *) malloc(sizeof(QueueNode)); /* a new node */
if (Temp == NULL) { /* Temp = NULL signals allocation */
SystemError("system storage is exhausted"); /* failure */
return 0;
} else {
Temp->Item = R;
Temp->Link = NULL;
if ( Q->Rear == NULL ) {
Q->Front = Temp;
Q->Rear = Temp;
} else {
Q->Rear->Link = Temp;
Q->Rear = Temp;
}
}
return 1;
}
/* -------------------- */
int Remove(Queue *Q, ItemType *F)
{
QueueNode *Temp;
if (Q->Front == NULL) {
SystemError("attempt to remove item from empty Queue");
return 0 ;
} else {
*F = Q->Front->Item;
Temp = Q->Front;
Q->Front = Temp->Link;
free(Temp);
if (Q->Front == NULL) Q->Rear = NULL;
return 1;
}
}
/* -------------------- */
You have not initialized the pointer que when you pass it to InitializeQueue().
A better implementation might be to pass a pointer to the pointer que (i.e. a Queue**) to InitializeQueue()
void InitializeQueue(Queue **Q)
{
*Q = malloc(sizeof**Q); // set aside memory for your queue
Q->Front = NULL;
Q->Rear = NULL;
}
And call it like this
Queue *que;
InitializeQueue(&que);
If you can't change the implementation of QueueImplementation.c, then call malloc before the function call, like so:
Queue *que = malloc(sizeof*que);
InitializeQueue(que);
Or don't use heap allocation at all (my recommendation):
Queue que; // note that this is not a pointer
InitializeQueue(&que); // we have to take the address of it
Just note that with the above option, que can only be legally accessed within the function that defined it. However, this shouldn't affect you since you define it in main, so it will exist for the lifetime of your program.
As for both malloc options, remember to call free() once you finish using it.
You also fail to initialize num anywhere before you pass it to Remove(). You should fix it similarly.
You might consider using a debugger such as valgrind. Segmentation faults don't always occur (if they occur at all) at the same line of code that caused it and can be unreliable as a way of error checking.
P.S. It's sufficient to use if (Empty(que)) instead of if (Empty(que) != 1) because expressions are "true" when they evaluate to a non-zero integer. It's arguably safer because all "true" values don't have to be 1.
P.P.S. Don't #include .c files. Include the .h file and compile the .c file with your main program. If you're using gcc, then
gcc myprogram.c QueueImplementation.c
Other compilers use the same syntax (there's probably an exception somewhere but I haven't encountered it).
In C, when you just declare a pointer Queue *, it doesn't magically point to a new "valid" instance of Queue. In fact, it points to a random location in memory which most likely doesn't contain anything that makes sense to you.
To simplify, in your code you are doing:
Get me a pointer que, I don't care where it points to.
Put { NULL, NULL } to where the pointer points to.
So you are writing { NULL, NULL } to a random part of system memory.
This is not how you do it. Look at the example Luddite has provided.
And additionally, please read this article to understand what is going on here:
https://www.cs.cf.ac.uk/Dave/C/node10.html

How to access recursive structure with pointers

I am getting a really strange error in my C program and therefore I need your help guys! So I have a recursive structure called path, where sometimes I store the address of the "parent" path in the structure field mother:
typedef struct path{
struct path* mother;
struct path** children;
int length;
uint8_t* inf;
} path;
So in my example I just generate one path like this:
int child_num=2;
int bytes=10;
path* my_path=malloc(sizeof(path));
if (path==NULL) throw error...
my_path->inf=malloc(sizeof(uint8_t)*bytes);
memset(my_path->inf, 4, bytes);
my_path->children=malloc(sizeof(path*)*child_num);
for(int i=0; i<child_num; i++){
my_path->children[i]->mother=my_path;
my_path->children[i]->inf=malloc(sizeof(uint8_t)*bytes);
memset(my_path->children[i]->inf, 5, bytes);
}
So now since I stored the link to the parent structure, I want to use another helping pointer to get access to its information:
path* my_pointer=my_path->children[0]->mother; //this is just for the example
So i checked the addresses and everything seems to be alright, but if I know use the pointer in another method, pointing to the field "inf", it works if I use the variable "path" so:
method(path->inf, bytes);
it is fine, but as soon as I do:
method(my_pointer->inf, bytes);
the method crashes at the marked line:
void method(uint8_t* element, int bytes) {
if (element==NULL) ... //<=== here it crashes
//do something
}
I really dont get what I am doing wrong, I printed the addresses and everything seems to be good, even if I access a certain byte over the variable "my_pointer", so like
my_pointer->inf[1]
it returns me the corresponding value, but in the separate method it doesnt work.
Like the comments indicate we can't exactly answer your question with the information provided, but we can point you in the right direction.
First, I noticed in your examples that you're using path as a variable name to a typedef'd path structure. You need to either be more verbose with your variable names or actually copy paste some code to make sure that we can look at the actual problem, because it could simply be an issue with naming.
All in all I think it would do you a world of good to employ a bit of code hygiene. Organize some of the functions you use for data structure overhead at file scope:
static int path_alloc(path* p);
static int path_alloc_kids(path* p, int num);
static int path_alloc(path* p) {
if(p == NULL) { return -1; }
p = (path*)malloc(sizeof(path));
if(p == NULL) { return -2; }
return 0;
}
static int path_alloc_kids(path* p, int num) {
if(p == NULL || num <= 0) { return -1; }
if(!path_alloc(p)) { /* Easier to read and understand, no error handling here to muddle things up */
/* You don't actually need a path**, do you? Think of char *argv[] a.k.a. char **argv, is that what you're actually going for? */
p->children = (path*)malloc(sizeof(path) * num);
if(p->children == NULL) { return -2; }
p->length = num;
} else { return -1; } /* Simple */
return 0;
}
This makes it a LOT easier to understand your code, which is the main issue with pointers. Add in some methods to free the allocated children and roots and you're set to use this path structure in a relatively abstracted way. You may want to consider using a path and a path_node in a linked-list fashion, that way you only allocate what you need.
struct spath_node; /* So it knows of itself */
typedef struct spath_node {
struct spath_node *parent;
struct spath_node *next;
uint8_t *data;
int data_size;
} path_node;
Then allocate by passing in a data size and parent, a NULL parent could mean it's a root node.
static int path_alloc_node(path_node *parent, int data_size, uint8_t *data);
This makes for relatively slow insert/traversal, but easier to understand where you went wrong.
EDIT: To be clear, this is how we would add children to the linked-list example:
static int path_alloc_node(path_node *parent, int data_size, uint8_t *data) {
path_node *tmp;
if(parent == NULL || data_size <= 0) { return -1; }
if(parent->next != NULL) { return -3; }
tmp = (path_node*)malloc(sizeof(path_node));
if(tmp == NULL) { return -2; }
else parent->next = tmp;
if(data == NULL) { /* Assume the caller is requesting a new data block of the given size */
data = (uint8_t*)malloc((size_t)data_size);
if(data == NULL) { return -2; }
}
parent->next->data = data;
parent->next->data_size = data_size;
parent->next->next = NULL;
parent->next->parent = parent;
return 0;
}

Am I calling free() correclty on my struct pointer?

So while testing my struct I use the following method. You can see that I call free on the pointer at the end of the method. Is this right?
void test() {
VariableVector *labelVector = initVariableVector();
VariableVector *variableVector = initVariableVector();
// do some stuff with labelVector and variableVector
free(labelVector);
free(variableVector);
}
This is what my struct init methods look like:
Variable* initVariable(char *variableName, char *arrayOfElements,
int32_t address) {
Variable* initializedVariable = malloc(sizeof(Variable));
if (initializedVariable != NULL ) {
initializedVariable->variableName = variableName;
initializedVariable->arrayOfElements = arrayOfElements;
initializedVariable->address = address;
return initializedVariable;
} else {
return NULL ;
}
}
VariableVector* initVariableVector() {
VariableVector* initializedVariableVector = malloc(
sizeof(VariableVector));
if (initializedVariableVector != NULL ) {
initializedVariableVector->size = 0;
initializedVariableVector->capacity = VECTOR_INITIAL_CAPACITY;
initializedVariableVector->variables = malloc(
sizeof(Variable) * VECTOR_INITIAL_CAPACITY);
return initializedVariableVector;
} else {
return NULL ;
}
}
Your idea is correct, but your implementation is not.
initVariableVector() does 2 malloc's for one object, but you only do 1 free.
You should have function to destroy it too.
void destroyVariableVector(VariableVector* vector)
{
if(vector) {
free(vector->variables);
free(vector);
}
}
EDIT: You're not checking whether the memory allocation for the member "variables" in structure VariableVector is successful. Which means that even at the end you do not free it manually, so it leads to memory leak.
My advice:
Use "init*" functions, but at the same time use "free*" functions. It keeps the code clearer and takes care of all memory releasing.
initVariableVector, the opposite should be freeVariableVector
And the latter function could look like:
void freeVariableVector(VariableVector *vv)
{
if (vv) {
if (vv->variables)
free(vv->variables);
free(vv);
}
}

Simple coding error (potentially) in kernel code

Here are the related structs:
typedef struct OS_BM {
void *free; /* Pointer to first free memory block */
void *end; /* Pointer to memory block end */
U32 blk_size; /* Memory block size */
U32 owner_one;
} *P_BM;
typedef struct NEW { //struct ADDED BY ME
void *free;
U8 pid;
} *P_GH;
Here is the code in question (only the part "ADDED BY ME"):
void *rt_alloc_box (void *box_mem) {
/* Allocate a memory block and return start address. */
void **free;
#if !(defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
int irq_dis;
irq_dis = __disable_irq ();
free = ((P_BM) box_mem)->free;
if (free) {
array[counter]->free=((P_BM) box_mem)->free; //ADDED BY ME- MAY NOT BE WORKING
array[counter]->pid = rt_tsk_self(); //ADDED BY ME
counter++; //ADDED BY ME
((P_BM) box_mem)->free = *free;
}
if (!irq_dis) __enable_irq ();
#else
do {
if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0) {
__clrex();
break;
}
} while (__strex((U32)*free, &((P_BM) box_mem)->free));
#endif
return (free);
}
int free_owner (void *box_mem, void *box){ //FUNCTION ADDED BY ME
int i;
for(i = 0; i<8;i++){
if (box == array[i]->free;){ //MAY NOT BE WORKING
if(rt_tsk_self() == (array[i]->pid))
return (0);
}
}
return (1);
}
Code Description: The first function is to do with memory allocation, but I need to added protection/ownership to the memory block that is allocated from the pool. That is why I am putting the memory block address as well as the process ID (returned from rt_tsk_self()) into an extra global array that I created. The second function just checks if the process with using the allocated block has the same ownership as the one created (again it uses rt_tsk_self()).
Actual Problem: The lines commented with "MAY NOT BE WORKING" don't seem to work as I am sure that I can put the process ID into the array as well as checking that it is in there, but I cannot do the same with memory block address. This is very likely to just be a simple coding error rather than conceptual.
if (box == array[i]->free;){ //MAY NOT BE WORKING
Shouldn't this be:
if (box == *(array[i]->free)){ //MAY NOT BE WORKING
Also, somehow comparing void pointers make me, uneasy.

Resources