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

CjR*_*bin 5 c address-sanitizer

我正在使用 C 和 pthreads 库开发多线程客户端,使用 boss/worker 架构设计,并且在理解/调试范围后堆栈使用错误时遇到问题,该错误导致我的客户端失败。(我对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
Run Code Online (Sandbox Code Playgroud)

我希望工作人员从队列中提取 work_item,取消引用这些值,然后执行一些工作。但是,我不断收到 AddressSanitizer: stack-use-after-scope,并且在线有关此错误的信息不是很丰富,因此任何指针将不胜感激。

Kaz*_*Kaz 4

这里的危险信号是&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
Run Code Online (Sandbox Code Playgroud)

如果我们这样做,那么评论实际上就是事实。因为否则我们将创建work_item一个指向.Request_work_item

不幸的是,由于work_item具有类型void*,因此它可以以任何一种方式编译。

如果队列另一端的项目的使用者将其提取为 a 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.
Run Code Online (Sandbox Code Playgroud)

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