【问题标题】:glibc detected *** free(): invalid pointerglibc 检测到 *** free(): 无效指针
【发布时间】:2012-05-04 16:40:40
【问题描述】:

我对这段代码有以下问题。有人可以帮忙吗?

注意:QueueItem 是在不同的线程上创建的。

WorkItem * Dequeue(Queue ** Q)    
{    
    if(QueueIsEmpty(*Q)) return NULL;

    QueueItem * tmp = (*Q)->Head;
    (*Q)->Head = ((*Q)->Head)->NextItem;
    WorkItem * retval = tmp->workItem;
    free(tmp); //Generates  glibc detected *** free(): invalid pointer
    return retval;
}

edit 当多个线程运行时,此函数在访问时受到保护。

WorkItem * DequeueSynchronous(Queue ** Q)
{
    WorkItem * retval;
    pthread_mutex_lock((*Q)->QueMutex);
    retval = Dequeue (Q);
    pthread_mutex_unlock((*Q)->QueMutex);
    return retval;
}

(*Q)->头部;分配给我的 malloc。

Queue * Queue_Init(pthread_mutex_t * mutex)
{
    Queue * retval = (Queue *)malloc(sizeof(Queue *));
    retval->Head = retval->Tail =NULL;
    retval->QueMutex = mutex;
    return retval;
}

void Enqueue (Queue * Q, WorkItem * WI)
{

   if(!Q)return;
   QueueItem * QI = (QueueItem *) malloc(sizeof(QueueItem *));
   QI->workItem = WI;
   QI->NextItem = NULL;

   if(QueueIsEmpty(Q))
   {
       Q->Head = Q->Tail = QI;
       return;
   }

   Q->Tail->NextItem = QI;
   Q->Tail = QI;
}

void EnqueueSynchronous (Queue * Q, WorkItem * WI)
{

   pthread_mutex_lock(Q->QueMutex);
   Enqueue (Q, WI);
   pthread_mutex_unlock(Q->QueMutex);
}

也感谢您的意见,我会看看 valgrind。

编辑 2

typedef struct {
    char ** FileNames;
    int  ** Results;
    int NumOfItems;
}WorkItem;

typedef struct QI{
    WorkItem * workItem;
    struct QI * NextItem;
}QueueItem;

typedef struct {
    QueueItem * Head, * Tail;
    pthread_mutex_t * QueMutex;
}Queue;

出队被称为 -Dequeue(&WorkQue) 所有调用Dequeue 的线程都被赋予&WorkQue 作为其参数的一部分;

typedef struct{
    int ThreadID;
    WorkItem * workItem;
    char ** keywordsArray;
    int nKeywords;
    Queue ** WorkQueue, ** WorkCompletedQ;   
}ThreadArgs;

 pthread_t threads[NTHREADS];
ThreadArgs threadArgs[NTHREADS];

for(i=0;i<NTHREADS;i++)
{
    threadArgs[i].ThreadID=i;
    threadArgs[i].workItem = Dequeue(&WorkQue);
    threadArgs[i].WorkQueue = &WorkQue;
    threadArgs[i].WorkCompletedQ = &WorkCompletedQ;
    threadArgs[i].nKeywords=_kwlist->length;
    threadArgs[i].keywordsArray = ListToArray(*_kwlist);
}    

for(i=0;i<NTHREADS;i++)
{
    pthread_create(&threads[i], NULL, WorkerThread,(void *)&(threadArgs[i]));
}

每个线程使用myWork = DequeueSynchronous(myThreadArgs-&gt;WorkQueue);调用出队

【问题讨论】:

    标签: c pointers free glibc


    【解决方案1】:

    查看您更新的代码,我认为您由于以下几行而出现内存损坏:

    Queue * retval = (Queue *)malloc(sizeof(Queue *));
    

    请注意,您只为指向 Queue 的指针分配了足够的空间 - 您应该改为:

    Queue * retval = (Queue *)malloc(sizeof(Queue)); // version one
    

    或者更好:

    Queue * retval = (Queue *)malloc(sizeof(*retval)); // version two
    

    第二个版本更好,因为它对retval 类型的变化具有鲁棒性。

    这两行都说“为队列分配足够的空间,并设置队列指针retval 指向它”。您的上一行说“为队列指针分配足够的空间,并设置队列指针retval 指向它”。旧版本导致分配不足(因为结构几乎肯定比指针大)。

    然后,当您分配超出实际分配空间的 Queue 结构部分时,您会标记内存的其他部分。我怀疑这会导致您标记malloc()s 的一些内部控制数据,这就是后来导致无效免费的原因。您需要将所有 malloc() 调用更改为 malloc 结构的大小而不是指针的大小。

    请注意,您还应该not cast the result of malloc。在我看来,你最后的malloc() 语句应该是这样的:

    Queue * retval = malloc(sizeof(*retval));
    

    如果这不能解决问题,您能否编辑您的问题以包括:

    1. Queue结构的定义
    2. 你怎么称呼DequeueSynchronous(或者,*Q变成**Q

    与此无关,请注意,您还有一个错误,即当列表在出队后变为空时,您不会清除尾部。我怀疑你可能需要写:

    (*Q)->Head = ((*Q)->Head)->NextItem;
    if ((*Q)->Head == NULL) (*Q)->Tail = NULL;
    

    如果队列中现在没有头部,这将清除尾部。

    【讨论】:

    • 我已经在使用 gdb,但会给 valgrind 一个机会。双重免费是不可能的。感谢您的输入
    • @chris 我想我找到了你的问题 - 请参阅我的更新答案
    • 感谢@Tim,您对 malloc 的建议有助于减少 valgrind 上出现的大部分无效读写。我正在将其更改为 V1,但我更喜欢 v2 并使用它。而且我的 glibc 还检测到 *** free(): invalid pointer 错误。谢谢! :)
    【解决方案2】:

    据我们所知,这并没有本质上的错误。但问题一定是tmp(换句话说,函数入口处的(*Q)-&gt;Head)不是指向malloc()分配的块的指针。如果它是以任何其他方式分配的——或者如果它是指向块中间而不是开始的指针——那么你不能用free()释放它。

    也有可能它已经被释放了;也许您的多个线程导致它被多次释放。

    【讨论】:

    • 嗯 (*Q)->head 是由 malloc 分配的,当我运行多个线程时,一次不超过一个可以访问队列。感谢您的意见。
    猜你喜欢
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-16
    • 1970-01-01
    • 2016-03-27
    • 2016-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多