gui*_*mtr 11 c stack-overflow malloc buffer-overflow segmentation-fault
以下是发生分段错误的代码段(不会调用perror):
job = malloc(sizeof(task_t));
if(job == NULL)
perror("malloc");
Run Code Online (Sandbox Code Playgroud)
更确切地说,gdb说segfault在__int_malloc调用内部发生,这是一个子例程调用malloc.
由于malloc函数与其他线程并行调用,最初我认为它可能是问题所在.我使用的是glibc 2.19版.
数据结构:
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;
};
Run Code Online (Sandbox Code Playgroud)
现在未来的实施:
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));
}
Run Code Online (Sandbox Code Playgroud)
线程池本身:
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);
}
Run Code Online (Sandbox Code Playgroud)
最后是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 ;
}
Run Code Online (Sandbox Code Playgroud)
队列是lfds无锁队列.
#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); \
}
Run Code Online (Sandbox Code Playgroud)
只要对异步的调用次数非常高,就会出现问题.
Valgrind输出:
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)
Run Code Online (Sandbox Code Playgroud)
Jek*_*yll 13
在malloc中触发的SIGSEGV(分段错误)通常是由堆损坏引起的.堆损坏不会导致分段错误,因此只有当malloc尝试访问时才会看到.问题是创建堆损坏的代码可能在任何位置甚至远离调用malloc的位置.它通常是malloc中的下一个块指针,它被堆损坏更改为无效地址,因此当您调用malloc时,无效指针会被取消引用并且您会遇到分段错误.
我认为您可以尝试从程序的其余部分中隔离代码的一部分,以降低错误的可见性.
此外,我发现你永远不会释放内存,可能会有内存泄漏.
为了检查内存泄漏,您可以运行top命令top -b -n 1并检查:
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
Run Code Online (Sandbox Code Playgroud)
gui*_*mtr 12
我已经弄清楚问题是什么:堆栈溢出.
首先,让我解释为什么在malloc内部发生堆栈溢出(这可能就是你读这个的原因).当我的程序运行时,每次开始执行(递归)另一个任务(因为我编写它的方式)时,堆栈大小不断增加.但是对于每一个这样的时间,我不得不使用malloc分配一个新任务.但是,malloc进行其他子例程调用,这使得堆栈的大小增加甚至超过执行另一个任务的简单调用.所以,发生的事情是,即使没有malloc,我也会得到堆栈溢出.但是,因为我有malloc,所以堆栈溢出的那一刻是在malloc中,在它溢出之前再进行另一次递归调用.下面的插图显示了发生的事情:
初始堆栈状态:
-------------------------
| recursive call n - 3 |
-------------------------
| recursive call n - 2 |
-------------------------
| recursive call n - 1 |
-------------------------
| garbage |
-------------------------
| garbage | <- If the stack passes this point, the stack overflows.
-------------------------
Run Code Online (Sandbox Code Playgroud)
在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.
-------------------------
Run Code Online (Sandbox Code Playgroud)
然后堆栈又缩小了,我的代码进入了一个新的递归调用:
-------------------------
| 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.
-------------------------
Run Code Online (Sandbox Code Playgroud)
然后,它在这个新的递归调用中再次调用malloc.但是,这次它溢出了:
-------------------------
| 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 stack overflow occurs.
-------------------------
Run Code Online (Sandbox Code Playgroud)
[其余的答案更侧重于我为什么在我的代码中遇到这个问题.]
通常,当递归地计算Fibonacci(例如,具有特定数量n)时,堆栈大小随该数量线性增长.但是,在这种情况下,我正在创建任务,使用队列来存储它们,并将(fib)任务出列以执行.如果你在纸上绘制这个,你会发现任务的数量随着n而呈指数增长,而不是线性增长(还要注意,如果我在创建任务时使用了堆栈来存储任务,那么任务分配为因为堆栈大小只会随着n线性增长.所以会发生的事情是堆栈随n呈指数增长,导致堆栈溢出......现在出现了为什么在malloc调用中发生这种溢出的部分.所以基本上,as我在上面解释过,堆栈溢出发生在malloc调用中,因为它是堆栈最大的地方.发生的事情是堆栈几乎爆炸,并且由于malloc调用其中的函数,堆栈增长的不仅仅是调用mywait和FIB.
谢谢你们!如果这不是你的帮助,我将无法弄明白!