了解作用域后堆栈使用错误

Understanding a stack-use-after-scope error

我正在使用 C 和 pthreads 库开发多线程客户端,使用 boss/worker 架构设计,但遇到问题 understanding/debugging 导致我的堆栈使用后范围错误客户端失败。 (我对 C 有点陌生)

我试过很多东西,包括全局定义变量,传递双指针引用等

Boss logic within main:
for (i = 0; i < nrequests; i++)
  {

    struct Request_work_item *request_ctx = malloc(sizeof(*request_ctx));
    request_ctx->server = server;
    request_ctx->port = port;
    request_ctx->nrequests = nrequests;

    req_path = get_path(); //Gets a file path to work on

    request_ctx->path = req_path;

    steque_item work_item = &request_ctx; // steque_item is a void* so passing it a pointer to the Request_work_item

    pthread_mutex_lock(&mutex);
      while (steque_isempty(&work_queue) == 0) //Wait for the queue to be empty to add more work
      {
        pthread_cond_wait(&c_boss, &mutex);
      }
      steque_enqueue(&work_queue, work_item); //Queue the workItem in a workQueue (type steque_t, can hold any number of steque_items)
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&c_worker);
  }

Worker logic inside a defined function:
struct Request_work_item **wi;

  while (1)
  {
    pthread_mutex_lock(&mutex);
      while (steque_isempty(&work_queue) == 1) //Wait for work to be added to the queue
      {
        pthread_cond_wait(&c_worker, &mutex);
      }
      wi = steque_pop(&work_queue); //Pull the steque_item into a Request_work_item type
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&c_boss);

    char *path_to_file = (*wi)->path; //When executing, I get this error in this line: SUMMARY: AddressSanitizer: stack-use-after-scope
 ...
 ...
 ...
 continues with additional worker logic

我希望工作人员从队列中拉出 work_item,取消对值的引用,然后执行一些工作。但是,我一直收到 AddressSanitizer: stack-use-after-scope,网上关于这个错误的信息不是很丰富,所以任何指点将不胜感激。

这里的危险信号是&request_ctx是局部变量的地址。它不是指向用 malloc 分配的存储的指针,而是保存该存储的变量的地址。一旦此范围终止,该变量就会消失,即使 malloc-ed 块持续存在。

也许修复只是删除此行中的 & 运算符的地址?

steque_item work_item = &request_ctx; // steque_item is a void* so passing
                                      // it a pointer to the Request_work_item

如果我们这样做,那么评论实际上说的是实话。因为否则我们将 work_item 设为 指向 指向 Request_work_item.

的指针

由于 work_item 的类型为 void*,不幸的是,它可以通过任何一种方式编译。

如果队列另一端的项目的使用者将其提取为 Request_work_item *,那么您不仅可以访问超出范围的对象,还可以访问类型不匹配,即使当消费者使用它时该对象恰好仍在生产者的范围内。消费者最终使用生产者堆栈的一部分,就好像它是一个 Request_work_item 结构一样。 编辑: 我看到您在使项目出队并以 (*wi)->path 访问它时使用了指向指针的指针。考虑更改设计以避免这样做。否则,wi 指针也必须动态分配并释放。生产者必须做类似的事情:

struct Request_work_item **p_request_ctx = malloc(sizeof *p_request_ctx);
struct Request_work_item *request_ctx = malloc(sizeof *request_ctx);

if (p_request_ctx && request_ctx) {
  *p_request_ctx = request_ctx;
   request_ctx->field = init_value;
   // ... etc
   // then p_request_ctx is enqueued.

消费者然后必须 free 结构,以及 free 指针。那个额外的指针在这里看起来像是纯粹的开销;它不提供任何基本或有用的间接级别。