memcpy堆栈溢出只有打开优化和特定的glibc版本?

时间:2016-10-20 23:17:51

标签: c gcc stack-overflow glibc memcpy

我有一个应用程序,只有在使用-O1编译时才会出现段错误 使用来自Gentoo的gcc 4.9.3和glibc 2.22-r4(它适用于gcc 4.9.2 和来自Debian的glibc 2.19-18。使用-O0它可以正常工作并使用-O2 永远挂在memcpy上。我不认为这是glibc或gcc的错误,但我 找不到我的代码有什么问题。

由于memcpy中的堆栈溢出,似乎发生了错误。

...
Program received signal SIGSEGV, Segmentation fault.
memcpy (__dest=0x7ffff7f42010, __dest@entry=<error reading variable: DWARF-2 expression error: Loop detected (257).>, __src=0x7ffff7f91010, 
    __src@entry=<error reading variable: DWARF-2 expression error: Loop detected (257).>, __len=320000, 
    __len@entry=<error reading variable: DWARF-2 expression error: Loop detected (257).>) at /usr/include/bits/string3.h:53
53        return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
(gdb) where
#0  memcpy (__dest=0x7ffff7f42010, __dest@entry=<error reading variable: DWARF-2 expression error: Loop detected (257).>, __src=0x7ffff7f91010, 
    __src@entry=<error reading variable: DWARF-2 expression error: Loop detected (257).>, __len=320000, 
    __len@entry=<error reading variable: DWARF-2 expression error: Loop detected (257).>) at /usr/include/bits/string3.h:53
#1  0x0000000000401f04 in memcpy (__dest=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __src=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __len=<error reading variable: DWARF-2 expression error: Loop detected (257).>) at /usr/include/bits/string3.h:53
#2  0x0000000000401f04 in memcpy (__dest=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __src=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __len=<error reading variable: DWARF-2 expression error: Loop detected (257).>) at /usr/include/bits/string3.h:53
#3  0x0000000000401f04 in memcpy (__dest=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __src=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __len=<error reading variable: DWARF-2 expression error: Loop detected (257).>) at /usr/include/bits/string3.h:53
#4  0x0000000000401f04 in memcpy (__dest=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __src=<error reading variable: DWARF-2 expression error: Loop detected (257).>, 
    __len=<error reading variable: DWARF-2 expression error: Loop detected (257).>) at /usr/include/bits/string3.h:53
---Type <return> to continue, or q <return> to quit---
...

的valgrind:

...
==2566== Stack overflow in thread 1: can't grow stack to 0xffe801ff8
==2566== 
==2566== Process terminating with default action of signal 11 (SIGSEGV)
==2566==  Access not within mapped region at address 0xFFE801FF8
==2566==    at 0x401EFF: memcpy (string3.h:53)
==2566==  If you believe this happened as a result of a stack
==2566==  overflow in your program's main thread (unlikely but
==2566==  possible), you can try to increase the size of the
==2566==  main thread stack using the --main-stacksize= flag.
==2566==  The main thread stack size used in this run was 8388608.
==2566== Stack overflow in thread 1: can't grow stack to 0xffe801ff0
==2566== 
==2566== Process terminating with default action of signal 11 (SIGSEGV)
==2566==  Access not within mapped region at address 0xFFE801FF0
==2566==    at 0x4A246B0: _vgnU_freeres (vg_preloaded.c:58)
==2566==  If you believe this happened as a result of a stack
==2566==  overflow in your program's main thread (unlikely but
==2566==  possible), you can try to increase the size of the
==2566==  main thread stack using the --main-stacksize= flag.
==2566==  The main thread stack size used in this run was 8388608.
...

在这里和那里添加一些断点我无法确定是什么 导致错误,但由于我只在一个地方调用memcpy,我认为它是 来自那里:

/* Copy the surface b into surface a, both w x h */                             
static inline void                                                              
copy(double *a, double const *b, uint64_t w, uint64_t h)                           
{                                                                               
  memcpy(a, b, (size_t)(w * h) * sizeof(*a));                                   
}   

首先在这里调用:

double *surface = init(args.input[0], &w, &h);                                
if (!surface) {                                                               
  LOG_CRITICAL("%d: %s\n", __LINE__, strerror(errno));                        
  goto main_return;                                                           
}                                                                             
double *osurface = malloc((size_t)(w * h) * sizeof(*osurface));               
if (!osurface) {                                                              
  LOG_CRITICAL("%d: %s\n", __LINE__, strerror(errno));                        
  goto main_surface;                                                          
}                                                                             
copy(osurface, surface, w, h);

该程序似乎没有超过copy

我已检查过gdb,surfaceosurface都已成功完成 分配相同的大小。 init的代码:

/*                                                                              
 * Read a .pgm-like file with the initial state of the plate into a surface     
 * (array of doubles), dynamically allocated to the size of the image and       
 * returned on success. On error, nothing is allocated and NULL is returned.    
 * The error is registered to stderr. The size of the image is read into w,h.   
 * On error, this size may or may not be read into the vars.                    
 */  
static double *                                                                 
init(char const *filename, uint64_t *w, uint64_t *h)                              
{                                                                               
  double *ans = NULL;                                                           
  FILE *f = fopen(filename, "r");                                               
  if (!f) {                                                                     
    LOG_ERROR("Could not open %s: %s\n", filename, strerror(errno));            
    goto init_return;                                                           
  }                                                                             
  char mnumber[3] = { '\0' };                                                   
  uint64_t ignore;                                                              
  int rc = fscanf(f, " %2s %"SCNu64" %"SCNu64" %"SCNu64" ", mnumber, w, h,      
      &ignore);                                                                 
  if (rc != 4) {                                                                
    LOG_ERROR("%s: Could not read header: %s\n", filename, ferror(f) ?          
       strerror(errno) : "EOF");                                                
    goto init_fopen;                                                            
  }                                                                             
  if (strcmp(mnumber, IN_MNUMBER)) {                                            
    LOG_ERROR("%s: Wrong magic number: %s. Expected "IN_MNUMBER"\n",            
        filename, mnumber);                                                     
    goto init_fopen;                                                            
  }                                                                             
  ans = malloc((size_t)(*w * *h) * sizeof(*ans));                               
  if (!ans) {                                                                   
    LOG_ERROR("%d: %s\n", __LINE__, strerror(errno));                           
    goto init_fopen;                                                            
  }                                                                             
  for (uint64_t i = 0; i < *w * *h; i++)                                        
    if (fscanf(f, "%lf ", ans + i) != 1) {                                      
      LOG_ERROR("%s: Reading point %"PRIu64": %s\n", filename,                  
          i, ferror(f) ? strerror(errno) : "EOF");                              
      goto init_malloc;                                                         
    }                                                                           
  goto init_fopen;                                                              
init_malloc:                                                                    
  free(ans);                                                                    
  ans = NULL;                                                                   
init_fopen:                                                                     
  fclose(f);                                                                    
init_return:                                                                    
  return ans;                                                                   
} 

值得一提的是,如果我删除init以外的所有代码,除了 malloc该程序运行在最初的memcpy之后 目前是segfaulting(但后来又在另一个memcpy发生了段错误。)

可以找到包含入侵和必要输入文件的完整代码 here

0 个答案:

没有答案