在64位机器上运行C代码时出现glibc损坏的双链表错误



我有一个大的C代码,在32位机器上工作良好,但在64位机器上失败

*** glibc detected *** ./XXX.exe: corrupted double-linked list:错误。

我已经运行了Valgrind,并使用print语句来精确地确定错误来自何处,但我对修复一无所知。实际的代码非常大,但我在这里给出相关的部分。希望有人能帮我排除故障。实际的错误来自Buf_Close()模块,它试图将Buf_elm_p p释放为if (p != NULL) free(p);

这些是主代码调用的函数,我只在这里给出这个,因为错误在这里的某个地方。主代码的调用顺序是:

1. Buf_Init 2. Buf_New_p 3. Buf_Close

Buf_bf_p 
Buf_Init( size_t elm_size, 
      int    nelm_buf, 
      long   nbuf )
/*******************************************************************************
!C
!Description: Buf_Init (buffer initialize) initializes buffer data structures 
 and buffers.
!Input Parameters:
 elm_size   element size (bytes)
 nelm_buf   number of elements per buffer
 nbuf       number of buffers
!Output Parameters:
 (returns)      pointer to the buffer data structure 
                or NULL for an error return
*****************************************************************************/
{
  Buf_bf_p bf;
  long buf_size;
  long ibuf;
  /* Calculate buffer size and check */
  buf_size = ((long) elm_size) * nelm_buf;
  /*Allocate the buffer data structure */
  if ((bf = (Buf_bf_p) malloc(sizeof(Buf_bf_t))) == NULL)
    {Buf_Error(&BUF_NOMEMORY, "Init");  return NULL;}
  bf->key = BUF_KEY;
  bf->elm_size = elm_size;
  bf->nelm_buf = nelm_buf;
  bf->nbuf = nbuf;
  bf->buf_size = buf_size;
  bf->fp = NULL;
  bf->access = NO_FILE;
  bf->nbuf_alloc = 1;
  bf->ibuf_end = 0;
  bf->ibuf_newest = 0;
  bf->ibuf_oldest = 0;
  bf->nelm = 0;
  /* Allocate the buffer status data structure */
  bf->nbstat = max(NBSTAT_START, bf->nbuf + 1);
  if ((bf->bstat = (Buf_bstat_t *) 
     malloc(bf->nbstat * sizeof(Buf_bstat_t))) == NULL)
    {Buf_Error(&BUF_NOMEMORY, "Init");  return NULL;}
  /* Allocate the first buffer */
  bf->bstat[0].loc = MEM_ONLY;
  if( (bf->bstat[0].buf_p = (Buf_elm_p) malloc(bf->buf_size)) == NULL)
  { Buf_Error(&BUF_NOMEMORY, "Init");  
    return NULL;
  }
  else
  {
     /* initialize */
     memset( bf->bstat[0].buf_p, '', bf->buf_size ); 
  }
  bf->bstat[0].newer = -1;
  bf->bstat[0].older = -1;
  /* Initialize the rest of the buffer status array */
  printf("bf->nbstat %dn", bf->nbstat);
  for (ibuf = 1; ibuf < bf->nbstat; ibuf++) {
    bf->bstat[ibuf].loc = NOT_ALLOC;
    bf->bstat[ibuf].buf_p = NULL;
    bf->bstat[ibuf].newer = -1;
    bf->bstat[ibuf].older = -1;
    bf->bstat[ibuf].initialized = 1;
  }
  return bf;
}
Buf_elm_p 
Buf_New_p( Buf_bf_p bf, 
           long *ielm )
/*******************************************************************************
!C
!Description: Buf_New_p (new buffer element pointer) returns a memory 
 location and element number of a new element; elements are number
 sequentially as they are allocated.
!Input Parameters:
 bf     pointer to the buffer data structure 
!Output Parameters:
 ielm       new element number
 (returns)      pointer to memory location of new element 
                or NULL for error
!Notes:
   1. 'Buf_Init' must be called before this routine to initialize 
      the buffer data structure.
   2. If there is no more space in memory and disk write access is allowed, 
      the oldest buffer is written to disk and the memory is re-used.
   3. If the file is opened with 'read only' access this routine will return 
      an error.
!END
******************************************************************************/
{
  long ibuf, jelm, jbuf, kbuf;
  long nbuf_cmplt;
  Buf_elm_p p;
  long dsk_loc, eof_loc;

  /* New element number/location */
  *ielm = bf->nelm++;
  ibuf = *ielm / bf->nelm_buf;
  jelm = *ielm % bf->nelm_buf;
  /* Are we at the past the end of the last buffer? */
  if (ibuf > bf->ibuf_end) {
    if (ibuf != (bf->ibuf_end + 1))
      {Buf_Error(&BUF_BADBUF, "New_p");  return NULL;}
    /* Re-allocate buffer status data structure if not large enough */
    if( ibuf >= bf->nbstat ) 
    {
       bf->nbstat += min(bf->nbstat, MAX_NEW_NBSTAT);
       if( (bf->bstat = realloc(bf->bstat, bf->nbstat * sizeof(Buf_bstat_t))) 
           == NULL)
      {  Buf_Error(&BUF_NOMEMORY, "New_p");  
          return NULL;
      }
    }
    if (bf->nbuf_alloc < bf->nbuf  ||  bf->access == NO_FILE) {
      /* Allocate a new buffer */
      if( (p = (Buf_elm_p) malloc(bf->buf_size)) == NULL)
      {  Buf_Error(&BUF_NOMEMORY, "New_p");  
         return NULL;
      }
      else
      {
         /* initialize */
         memset( p, '', bf->buf_size ); 
      }
      bf->nbuf_alloc++;
      if (bf->nbuf < bf->nbuf_alloc) bf->nbuf = bf->nbuf_alloc;
    } else {
      /* Re-use an existing buffer */
      /* Get the oldest buffer */
      jbuf = bf->ibuf_oldest;
      /* Delete oldest buffer from old/new pointer list */
      p = bf->bstat[jbuf].buf_p;
      bf->ibuf_oldest = bf->bstat[jbuf].newer;
      bf->bstat[bf->ibuf_oldest].older = -1;
      bf->bstat[jbuf].buf_p = NULL;
      bf->bstat[jbuf].older = -1;
      bf->bstat[jbuf].newer = -1;
      bf->bstat[jbuf].initialized = 1;
    }
    /* Put current buffer in old/new pointer list */
    bf->bstat[ibuf].loc = MEM_ONLY;
    bf->bstat[ibuf].buf_p = p;
    bf->bstat[ibuf].older = bf->ibuf_newest;
    bf->bstat[ibuf].newer = -1;
    bf->bstat[ibuf].initialized = 1;
    bf->ibuf_end = ibuf;
    bf->bstat[bf->ibuf_newest].newer = ibuf;
    bf->ibuf_newest = ibuf;
  }
  /* Calculate pointer to memory location of element */
  p = (unsigned char *) bf->bstat[ibuf].buf_p + (jelm * bf->elm_size);
  return p;
}

int 
Buf_Close( Buf_bf_p bf )
/*******************************************************************************
!C
!Description: Buf_Close (buffer cache file close) writes the remainder of the 
 cache to the disk cache file and closes the file and frees memory of the 
 buffer data structure and buffers.
!Input Parameters:
 bf     pointer to the buffer data structure 
 Notes:
   1. 'Buf_Create' or 'Buf_Open' must be called before this routine to open
      the file.
!END
*****************************************************************************/
{
  int i;
  long dsk_loc;
  logical_t cmplt_flag;
  /* int b; */
  Buf_elm_p p;
  long ibuf, nelm_wrt;
  int  nb;
  unsigned char header[HEADER_SIZE];
  /* Write remaining buffers which are still only in memory */
  for (ibuf = 0; ibuf < (bf->ibuf_end + 1); ibuf++)
  /* for (ibuf = 0; ibuf < (bf->ibuf_end); ibuf++)*/{
    p = bf->bstat[ibuf].buf_p;
    /* Free the buffer memory */
**THIS FOLLOWING LINE IS WHERE THE ERROR IS COMING FROM**
**VALGRIND SHOWS `Conditional jump or move depends on uninitialised value(s)` ERROR**
**BUT AM NOT SURE HOW `p` is coming out to be uninitialized`**
if (p != NULL) free(p);  
}
  /* Free the buffer status memory */
  free(bf->bstat);
  /* Free the buffer cache data structure */
  bf->fp = (FILE *)NULL;
  bf->key = 0;
  free(bf);  
  printf("buf here 5n");
  return BUF_NORMAL;
}

我在一个有很多有问题的实践的项目上工作(目前正在努力清理它们)。我遇到了这个错误,并尝试了所有我能想到的方法来找出问题所在,包括clang杀毒器、各种valgrind工具和各种其他技巧。

问题:在main()返回的同时,exit()在一个线程中被调用,所以所有的全局/静态构造函数同时在两个单独的线程中被启动。我其实有点生气,我没有早点把它们联系起来。

此错误也显示为:

  • double free or corruption
    • …这也可能是由另一个问题引起的
  • segfault/sig11 inside exit()
  • malloc_consolidate内部崩溃,调用堆栈看起来像:

我猜你不能在项目项后面添加代码示例

#0  0xabcdabcd in malloc_consolidate () from /lib/libc.so.6
#1  0xabcdabcd in _int_free () from /lib/libc.so.6
#2  0xabcdabcd in operator delete (...)
#3  0xabcdabcd in operator delete[] (...)
(...)

此外,我无法让它在valgrind下运行时显示这个问题——无论是时间问题,还是valgrind工作方式的一些工件,隐藏了我可能永远不会知道的问题。

通过静态分析来理解程序逻辑有点困难。然而,Valgrind打印"有条件的跳跃或移动取决于未初始化的值"程序试图以一种可能影响程序外部可见行为的方式使用未初始化的数据。未初始化数据的来源往往是:

  1. 未初始化的过程中的局部变量。
  2. 在你(或构造函数)写东西之前,堆块的内容(用malloc, new或类似的函数分配)。

要查看程序中未初始化数据的来源信息,可以使用选项——track-origins=yes因此,您可以像下面这样运行程序(./a.t out):

valgrind——tool=memcheck——track-origins=yes ./a.out

这可能是有帮助的,并提供更有用的信息,更接近您的问题的实际来源。您可以从以下位置找到更多详细信息:

http://valgrind.org/docs/manual/mc-manual.html

最新更新