Malloc segmentation error

Here is a piece of code in which a segmentation error occurs (perror is not raised):

job = malloc(sizeof(task_t)); if(job == NULL) perror("malloc"); 

To be more precise, gdb says that segfault happens inside the __int_malloc call, which is a routine call made by malloc .

Since the malloc function is called in parallel with other threads, initially I thought this could be a problem. I used version 2.19 of glibc.

Data Structures:

 typedef struct rv_thread thread_wrapper_t; typedef struct future { pthread_cond_t wait; pthread_mutex_t mutex; long completed; } future_t; typedef struct task { future_t * f; void * data; void * (*fun)(thread_wrapper_t *, void *); } task_t; typedef struct { queue_t * queue; } pool_worker_t; typedef struct { task_t * t; } sfuture_t; struct rv_thread { pool_worker_t * pool; }; 

Now a future implementation:

 future_t * create_future() { future_t * new_f = malloc(sizeof(future_t)); if(new_f == NULL) perror("malloc"); new_f->completed = 0; pthread_mutex_init(&(new_f->mutex), NULL); pthread_cond_init(&(new_f->wait), NULL); return new_f; } int wait_future(future_t * f) { pthread_mutex_lock(&(f->mutex)); while (!f->completed) { pthread_cond_wait(&(f->wait),&(f->mutex)); } pthread_mutex_unlock(&(f->mutex)); return 0; } void complete(future_t * f) { pthread_mutex_lock(&(f->mutex)); f->completed = 1; pthread_mutex_unlock(&(f->mutex)); pthread_cond_broadcast(&(f->wait)); } 

The thread pool itself:

 pool_worker_t * create_work_pool(int threads) { pool_worker_t * new_p = malloc(sizeof(pool_worker_t)); if(new_p == NULL) perror("malloc"); threads = 1; new_p->queue = create_queue(); int i; for (i = 0; i < threads; i++){ thread_wrapper_t * w = malloc(sizeof(thread_wrapper_t)); if(w == NULL) perror("malloc"); w->pool = new_p; pthread_t n; pthread_create(&n, NULL, work, w); } return new_p; } task_t * try_get_new_task(thread_wrapper_t * thr) { task_t * t = NULL; try_dequeue(thr->pool->queue, t); return t; } void submit_job(pool_worker_t * p, task_t * t) { enqueue(p->queue, t); } void * work(void * data) { thread_wrapper_t * thr = (thread_wrapper_t *) data; while (1){ task_t * t = NULL; while ((t = (task_t *) try_get_new_task(thr)) == NULL); future_t * f = t->f; (*(t->fun))(thr,t->data); complete(f); } pthread_exit(NULL); } 

And finally, task.c:

 pool_worker_t * create_tpool() { return (create_work_pool(8)); } sfuture_t * async(pool_worker_t * p, thread_wrapper_t * thr, void * (*fun)(thread_wrapper_t *, void *), void * data) { task_t * job = NULL; job = malloc(sizeof(task_t)); if(job == NULL) perror("malloc"); job->data = data; job->fun = fun; job->f = create_future(); submit_job(p, job); sfuture_t * new_t = malloc(sizeof(sfuture_t)); if(new_t == NULL) perror("malloc"); new_t->t = job; return (new_t); } void mywait(thread_wrapper_t * thr, sfuture_t * sf) { if (sf == NULL) return; if (thr != NULL) { while (!sf->t->f->completed) { task_t * t_n = try_get_new_task(thr); if (t_n != NULL) { future_t * f = t_n->f; (*(t_n->fun))(thr,t_n->data); complete(f); } } return; } wait_future(sf->t->f); return ; } 

A queue is an unblocked lfds queue.

 #define enqueue(q,t) { \ if(!lfds611_queue_enqueue(q->lq, t)) \ { \ lfds611_queue_guaranteed_enqueue(q->lq, t); \ } \ } #define try_dequeue(q,t) { \ lfds611_queue_dequeue(q->lq, &t); \ } 

The problem occurs whenever the number of calls for asynchronization is very large.

Valgrind Output:

 Process terminating with default action of signal 11 (SIGSEGV) ==12022== Bad permissions for mapped region at address 0x5AF9FF8 ==12022== at 0x4C28737: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
+8
c segmentation-fault malloc stack-overflow buffer-overflow
source share
2 answers

I found out what the problem is: stack overflow.

First, let me explain why the stack overflow occurs inside malloc (which is probably why you are reading this). When my program was launched, the stack size increased with each start (recursively) of another task (due to the way I programmed it). But for every such time, I had to assign a new task using malloc. However, malloc makes other subprocess calls that cause the stack to grow even larger than a simple call to do another task. So what happens, even if there wasn’t a malloc, I would get a stack overflow. However, since I had malloc, the moment was in malloc before it overflowed, making another recursive call. The illustration below shows what happens:

Source Stack Status:

 ------------------------- | recursive call n - 3 | ------------------------- | recursive call n - 2 | ------------------------- | recursive call n - 1 | ------------------------- | garbage | ------------------------- | garbage | <- If the stack passes this point, the stack overflows. ------------------------- 

when calling malloc:

 ------------------------- | recursive call n - 3 | ------------------------- | recursive call n - 2 | ------------------------- | recursive call n - 1 | ------------------------- | malloc | ------------------------- | __int_malloc | <- If the stack passes this point, the stack overflows. ------------------------- 

Then the stack contracted again, and my code introduced a new recursive call:

 ------------------------- | recursive call n - 3 | ------------------------- | recursive call n - 2 | ------------------------- | recursive call n - 1 | ------------------------- | recursive call n | ------------------------- | garbage | <- If the stack passes this point, the stack overflows. ------------------------- 

Then he again called malloc inside this new recursive call. However, this time it overflowed:

 ------------------------- | recursive call n - 3 | ------------------------- | recursive call n - 2 | ------------------------- | recursive call n - 1 | ------------------------- | recursive call n | ------------------------- | malloc | <- If the stack passes this point, the stack overflows. ------------------------- | __int_malloc | <- This is when the Qaru occurs. ------------------------- 

[The rest of the answer is more focused on why I had this problem in my code in particular.]

Usually, when Fibonacci, for example, a certain number n is recursively calculated, the stack size grows linearly with that number. However, in this case I create tasks using a queue to store them and canceling the task (fib) for execution. If you draw it on paper, you will see that the number of tasks grows exponentially with n, and not linearly (also note that if I used the stack to store tasks as they were created, the number of tasks, since the stack size would only grow linearly with n. So what happens is that the stack grows exponentially with n, which leads to stack overflow ... Now comes the part why this overflow occurs inside a call in malloc. I explained above that the stack overflow occurred inside call malloc because im permanently there was the big stack. It so happened that the stack was almost broken, and as malloc function call inside of it, the stack grows more than just a challenge mywait and fiction.

Thanks everyone! If not for your help, I would not have been able to figure it out!

+9
source share

SIGSEGV (segmentation error) is triggered in malloc, usually caused by heap corruption. Damage to the heap does not cause segmentation errors, so you will see that only when malloc tries to get there. The problem is that the code that creates the heap can be at any point, even far from which malloc is called. This is usually the pointer to the next block inside malloc, which is changed by your damaged heap to an invalid address, so when you call malloc, the invalid pointer gets dereferenced and you get a segmentation error.

I think you can try a piece of code that is isolated from the rest of the program to reduce the visibility of the error.

In addition, I see that you never free memory here, and there may be a possible memory leak.

To check for a memory leak, you can run the top command top -b -n 1 and check:

 RPRVT - resident private address space size RSHRD - resident shared address space size RSIZE - resident memory size VPRVT - private address space size VSIZE - total memory size 
+9
source share

All Articles