Malloc 分段错误

2023-11-22

这是发生分段错误的代码段(未调用 perror):

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

更准确地说,gdb 说segfault发生在一个__int_malloccall,这是一个子例程调用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;
};

现在未来的实施:

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));
}

线程池本身:

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);
}

最后是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 ;
}

该队列是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);               \
  }

每当对 async 的调用次数非常多时,就会出现此问题。

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)

我已经弄清楚问题是什么:堆栈溢出。

首先,让我解释一下为什么 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.
-------------------------

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.
-------------------------

然后堆栈再次缩小,我的代码进入了新的递归调用:

-------------------------
| 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.
-------------------------

然后,它在这个新的递归调用中再次调用 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.
-------------------------

[答案的其余部分更集中于为什么我的代码中特别出现这个问题。]

通常,当递归计算斐波那契数时,例如,计算某个数字 n 时,堆栈大小随该数字线性增长。 但是,在本例中,我正在创建任务,使用队列来存储它们,并将(fib)任务出队以供执行。如果你把它画在纸上,你会发现任务的数量随着 n 呈指数增长,而不是线性增长(另请注意,如果我在创建任务时使用堆栈来存储任务,则分配的任务数量为以及堆栈大小只会随着 n 线性增长。所以会发生的是堆栈随着 n 呈指数增长,导致堆栈溢出...现在是为什么这种溢出发生在对 malloc 的调用中的部分。所以基本上,我上面解释过,堆栈溢出发生在 malloc 调用内部,因为它是堆栈最大的地方。所发生的情况是堆栈几乎爆炸,并且由于 malloc 调用其中的函数,堆栈的增长不仅仅是 mywait 和谎言。

谢谢你们!如果不是你的帮助我根本无法弄清楚!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Malloc 分段错误 的相关文章

随机推荐

  • 在 C# 中使用 Lisp

    正如很多人指出的那样这个问题 Lisp主要是作为一种学习体验 尽管如此 如果我能以某种方式使用我的 Lisp 算法并将它们与我的 C 程序结合起来 那就太好了 在大学里 我的教授从来没能告诉我如何在程序中使用 Lisp 例程 不 不是用 L
  • 我如何才能收到 Cocoa 应用程序中系统时间更改的通知?

    我有一个可可应用程序 用于记录事件的日期戳 我需要知道系统时间何时重置以及重置多少 但我似乎无法在任何地方发出通知来告诉我发生了这样的事情 由于 NTP 重置时钟或用户重置 例如从系统偏好设置 可能会发生此更改 如果有一个就太好了NSNot
  • 自定义改造 ErrorHandler 给出 UndeclaredThrowableException

    基于这篇文章我应该如何在 Android 上使用 Retrofit 处理 无互联网连接 我做了一个定制ErrorHandler private static class CustomErrorHandler implements Error
  • 如何将字符串解析为java.sql.date

    我有一个字符串 String s 01 NOVEMBER 2012 然后我想将其解析为 sqlDate 并将其插入数据库 是否可以将字符串解析为sql Date 是的 sql日期格式是 yyyy mm dd Use SimpleDateFo
  • 获取模型后渲染 Marionette 区域

    我想使用 Derick Bailey 在 通用问题解决方案 在这个thread获取模型后渲染视图 我将在这里报告他的解决方案 MyView Backbone View extend initialize function this mode
  • 在 ocaml 中输入级别整数

    有人可以给我关于在 OCaml 3 12 中制作类型级整数支持加法和减法运算的建议 建议吗 例如 如果我有这样表示的数字 type zero type a succ type pos1 zero succ type pos2 zero su
  • 如何在Python中从负纪元创建日期时间

    第一次使用 StackExchange 我正在使用 ArcGIS Server 和 Python 在尝试使用地图服务的 REST 端点执行查询时 我在 JSON 响应中获取负纪元中 esriFieldTypeDate 字段的值 JSON 响
  • XamlParseException 无法分配给属性。绑定不适用于附加属性

    我想为 Windows 应用商店应用程序创建带有附加属性的自定义文本框 我正在关注这个解决方案 现在它使用硬编码值作为属性值 但我想使用绑定来设置值 但它不起作用 我尝试搜索很多但没有帮助我任何解决方案 异常详细信息是这样的 Windows
  • CSV 的替代品?

    我打算构建一个 RESTful 服务 它将返回自定义文本格式 鉴于我的数据量非常大 XML JSON 太冗长了 我正在寻找一种基于行的文本格式 CSV 是一个明显的候选者 不过我想知道是否还有更好的东西 我通过一些研究唯一发现的是CTX a
  • 正确安装 mingw-get - mingw/msys 路径缺失以及更多!

    我运行的是Windows XP 我一直在关注本教程所以下载 mingw get insthere 我已经这样做过几次了 最后一次我检查了 boes 以安装所有内容 包括但不限于 gcc g MSYS 和 MinGW 编译套件 我告诉它也创建
  • 使用 Tensorflow 2.0 进行逻辑回归?

    我正在尝试使用 TensorFlow 2 0 构建多类逻辑回归 并且我编写了我认为正确的代码 但它没有给出好的结果 我的准确率实际上是 0 1 甚至损失也没有减少 我希望有人能在这里帮助我 这是我到目前为止编写的代码 请指出我在这里做错了什
  • 通过核心数据、NSExpression 进行不同计数到 NSFetchedResultsController

    目前使用核心数据 我有一张表 我试图在其中检索以下信息 SELECT item COUNT FROM myTable GROUP BY item 为了产生这种类型的结果 item COUNT group 1 2 group 2 5 grou
  • ConfigurationManage ->section.SectionInformation.ProtectSection() 是否依赖于机器?

    在代码中 Configuration config ConfigurationManager OpenExeConfiguration Application ExecutablePath ConnectionStringsSection
  • 使用 Image.FromFile 不会释放文件句柄

    我正在将多个多图像 tiff 文件连接到单个多图像 tiff 文件 并且在删除源 tiff 文件时遇到问题 因为 Image 类继续保留它们的句柄 我正在通过 Image FromFile 读取 tiff 图像 Bitmap resultT
  • 如何将输入元素与其标签放在同一行?

    我想放一个label and an input type text 在同一条线上 我想要input的宽度来填充包含元素的剩余宽度 无论标签文本的长度如何 请参见第一张图片 我尝试使用width auto 为了input 但它似乎有一个静态宽
  • C 如何在不使用图形库或任何其他库函数的情况下绘制点/设置像素

    我试图了解如何在不使用库函数的情况下绘制一组形成圆圈的点 设置像素 现在 获取给定半径的点的 x y 坐标非常简单 for x r x
  • 似乎无法覆盖 Magento 中的结帐控制器

    我正在尝试对 Magento 商店中的 Checkout 控制器进行一些更改 但是 当我尝试将控制器文件放入本地目录时 它似乎并不尊重本地文件 我已经检查过这些文件是否位于各自代码池中的同一位置 并且这些文件的名称相同 但它只是不会这样做
  • 在动态元素上使用 .on() 和 e.stopPropagation()

    我一直在尝试使用捕获元素之外的点击事件stopPropagation container children on click function e e stopPropagation container on click function
  • 将使用 S3 类的包转换为 S4 类,性能会下降吗?

    我有一个当前使用的 R 包S3类系统 具有两个不同的类和几种用于通用 S3 函数的方法 例如plot logLik and update 用于模型公式更新 由于我的代码由于所有有效性检查而变得更加复杂if else结构 因为没有基于两个参数
  • Malloc 分段错误

    这是发生分段错误的代码段 未调用 perror job malloc sizeof task t if job NULL perror malloc 更准确地说 gdb 说segfault发生在一个 int malloccall 这是一个子