【问题标题】:Valgrind says "Source and destination overlap in memcpy" about two buffers but they seems to not overlapValgrind 说关于两​​个缓冲区的“源和目标在 memcpy 中重叠”,但它们似乎没有重叠
【发布时间】:2011-09-13 03:07:15
【问题描述】:

OP 末尾的 LAST EDIT

我用 Valgrind 测试了一个项目中使用的函数,它显示“源和目标在 memcpy 中重叠”,并且还给了我“无效读取”和“无效写入”错误。我修复了代码以便不重叠这两个缓冲区但没有结果。代码如下:

static
int download_build_buffer(char **seq_numbered_buffer, int seq_n, int dim_payload, char *buffer) {

if(!seq_numbered_buffer)
    return 1;

/* allocates seq_numbered_buffer */
if(*seq_numbered_buffer != NULL) {
    free(*seq_numbered_buffer);
    *seq_numbered_buffer = NULL;
}
if(!(*seq_numbered_buffer = malloc((SIZE_SEQ_N + SIZE_DIM_S + dim_payload + 1) * sizeof(char))))
    return 1;

#if DEBUG_DOWNLOAD
fprintf(stderr, "download_build_buffer %d: seq->%d, dim->%d\n",
                getpid(), seq_n, dim_payload);
#endif

/* prints sequence number in its string */
seq_n = htonl(seq_n);
if(!memcpy(*seq_numbered_buffer, &seq_n, SIZE_SEQ_N))
    return 1;
dim_payload = htonl(dim_payload);
if(!memcpy(&(*seq_numbered_buffer)[SIZE_SEQ_N], &dim_payload, SIZE_DIM_S))
    return 1;

/* creates payload -> buffer = seq_number + buffer */
if(!memcpy(&(*seq_numbered_buffer)[SIZE_SEQ_N+SIZE_DIM_S], buffer, dim_payload))
    return 1;
(*seq_numbered_buffer)[SIZE_SEQ_N+SIZE_DIM_S+dim_payload] = 0;

return 0;
}

这个函数被调用如下:

/* allocates buffer */
if(buffer != NULL) {
    free(buffer);
    buffer = NULL;
}
assert((buffer = malloc((dim_payload+1)*sizeof(char)))
               != NULL);

/* stores bytes in buffer */
if((n = read(fd, buffer, dim_payload)) <= 0)
    break;
buffer[n] = 0;
buf_len = n;

/* increments seq_number */
seq_n = next_request;

/* creates payload -> buffer = seq_number + buffer */
if(download_build_buffer(&seq_numbered_buffer, seq_n, dim_payload, buffer))
    return 1;

其中 seq_numbered 缓冲区和缓冲区被定义和初始化为:

char *seq_numbered_buffer = NULL,
     *buffer = NULL;

另外,我尝试用 memmove 替换 memcpy 但没有结果:( 我的 Valgrind 输出是

==3921== Source and destination overlap in memcpy(0x41bb2b0, 0x41bb070, 131072)
==3921==    at 0x4027BD6: memcpy (mc_replace_strmem.c:635)
==3921==    by 0x8049A8D: download_build_buffer (uftp_server.c:791)
==3921==    by 0x8049F4C: server_download_file (uftp_server.c:989)
==3921==    by 0x804A4E1: data_connection_proc (uftp_server.c:1209)    
==3921==    by 0x804AEE8: main (uftp_server.c:1512)
==3921== 
==3921== Invalid read of size 4
==3921==    at 0x4027D42: memcpy (mc_replace_strmem.c:635)
==3921==    by 0x8049A8D: download_build_buffer (uftp_server.c:791)
==3921==    by 0x8049F4C: server_download_file (uftp_server.c:989)
==3921==    by 0x804A4E1: data_connection_proc (uftp_server.c:1209)
==3921==    by 0x804AEE8: main (uftp_server.c:1512)
==3921==  Address 0x41db06c is not stack'd, malloc'd or (recently) free'd
==3921== 
==3921== Invalid write of size 4
==3921==    at 0x4027D44: memcpy (mc_replace_strmem.c:635)
==3921==    by 0x8049A8D: download_build_buffer (uftp_server.c:791)
==3921==    by 0x8049F4C: server_download_file (uftp_server.c:989)
==3921==    by 0x804A4E1: data_connection_proc (uftp_server.c:1209)
==3921==    by 0x804AEE8: main (uftp_server.c:1512)
==3921==  Address 0x41db2ac is not stack'd, malloc'd or (recently) free'd
==3921== 
==3921== Invalid write of size 1
==3921==    at 0x8049A9C: download_build_buffer (uftp_server.c:792)
==3921==    by 0x8049F4C: server_download_file (uftp_server.c:989)
==3921==    by 0x804A4E1: data_connection_proc (uftp_server.c:1209)
==3921==    by 0x804AEE8: main (uftp_server.c:1512)
==3921==  Address 0x41db2b0 is not stack'd, malloc'd or (recently) free'd
==3921== 
server_download_file 3921: download finished
--3921-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--3921-- si_code=1;  Faulting address: 0x0;  sp: 0x62af9e0c

valgrind: the 'impossible' happened:
Killed by fatal signal
==3921==    at 0x38034171: unlinkBlock (m_mallocfree.c:244)

sched status:
running_tid=1

Thread 1: status = VgTs_Runnable
==3921==    at 0x4026864: malloc (vg_replace_malloc.c:236)
==3921==    by 0x804911B: file_release_lock (uftp_server.c:423)
==3921==    by 0x8049DE9: server_download_file (uftp_server.c:930)
==3921==    by 0x804A4E1: data_connection_proc (uftp_server.c:1209)
==3921==    by 0x804AEE8: main (uftp_server.c:1512)

如果有的话,请向我询问其他信息,谢谢

编辑 在最后memcpy之前,dim_payload用htonl()转成网络格式,从512传到131072..需要用ntohl()返回512。

【问题讨论】:

  • if(!memcpy(*seq_numbered_buffer, &seq_n, SIZE_SEQ_N)) memcpy 不返回错误条件。它只返回其第一个参数的值。如果第一个参数的值为 NULL,谁知道它会做什么(它可能会崩溃)。
  • 第一个参数不能为 NULL,因为我在 memcpy 之前添加了一个检查,如果它为 NULL,则使函数返回
  • 并不意外。这意味着“如果”和“返回”不做任何事情! (也不清楚您是否在其他地方执行了奇怪的“if”和“return”代码)。如果它什么都不做,你为什么要拥有该代码?
  • 我不明白.. NULL 定义为 (void *)0.. 如果我测试 !0 为 1:它将执行“return 1;”..

标签: c valgrind overlap memcpy memmove


【解决方案1】:

assert 不应该有副作用。在没有它们的情况下编译时,它们的表达式会被简单地忽略。在这种情况下,以下可能会导致您的问题:

assert((buffer = malloc((dim_payload+1)*sizeof(char)))
           != NULL);

我会将其替换为:

buffer = malloc((dim_payload+1)*sizeof(char));
assert(buffer != NULL);

哦,还有,sizeof(char)总是 1,所以你可以放弃它。

【讨论】:

  • +1。我要补充一点,assert 不适合用于测试malloc 的成功。 assert(condition) 应该只在condition总是为真时使用。
  • 奇怪的事情..我改变了它但没有任何反应:|顺便说一句,我在不调试时运行它没有问题。我在上面的 OP 中添加了我的 Valgrind 输出
猜你喜欢
  • 1970-01-01
  • 2014-10-27
  • 1970-01-01
  • 2010-12-29
  • 2014-04-03
  • 1970-01-01
  • 2022-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多