Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用Valgrind进行奇怪的无效读取_C_Valgrind - Fatal编程技术网

C 使用Valgrind进行奇怪的无效读取

C 使用Valgrind进行奇怪的无效读取,c,valgrind,C,Valgrind,我有一个奇怪的案例,就是使用Valgrind进行无效读取。当我使用gcc(Debian 4.7.2-5)4.7.2运行ValgrindValgrind-3.9.0中的示例代码时,我得到以下错误,但是,在不同的物理机器、相同的工具版本上运行它,我没有得到任何错误。知道为什么吗 ==17440== Invalid read of size 4 ==17440== at 0x4E46360: tcmapputkeep2 (tokyocabinet_all.c:1705) ==17440==

我有一个奇怪的案例,就是使用Valgrind进行无效读取。当我使用gcc(Debian 4.7.2-5)4.7.2运行Valgrind
Valgrind-3.9.0
中的示例代码时,我得到以下错误,但是,在不同的物理机器、相同的工具版本上运行它,我没有得到任何错误。知道为什么吗

==17440== Invalid read of size 4
==17440==    at 0x4E46360: tcmapputkeep2 (tokyocabinet_all.c:1705)
==17440==    by 0x4E62A8A: tcpathlock (tokyocabinet_all.c:10138)
==17440==    by 0x4E6E7AB: tchdbopen (tokyocabinet_all.c:11779)
==17440==    by 0x4E79BCA: tcbdbopenimpl (tokyocabinet_all.c:19512)
==17440==    by 0x4E7AFED: tcbdbopen (tokyocabinet_all.c:16870)
==17440==    by 0x400CC9: main (in a.out)
==17440==  Address 0x5f1d608 is 24 bytes inside a block of size 26 alloc'd
==17440==    at 0x4C28D84: malloc (vg_replace_malloc.c:291)
==17440==    by 0x4E5A8A0: tcrealpath (tokyocabinet_all.c:7426)
==17440==    by 0x4E6E797: tchdbopen (tokyocabinet_all.c:11767)
==17440==    by 0x4E79BCA: tcbdbopenimpl (tokyocabinet_all.c:19512)
==17440==    by 0x4E7AFED: tcbdbopen (tokyocabinet_all.c:16870)
==17440==    by 0x400CC9: main (in a.out)
==17440==
hop
bar:step
baz:jump
foo:hop
==17440== Invalid read of size 4
==17440==    at 0x4E46C20: tcmapout2 (tokyocabinet_all.c:1857)
==17440==    by 0x4E62AF3: tcpathunlock (tokyocabinet_all.c:10150)
==17440==    by 0x4E736F5: tchdbclose (tokyocabinet_all.c:11807)
==17440==    by 0x4E7A857: tcbdbcloseimpl (tokyocabinet_all.c:19608)
==17440==    by 0x4E7B0C7: tcbdbclose (tokyocabinet_all.c:16885)
==17440==    by 0x400E9E: main (in a.out)
==17440==  Address 0x5f1d608 is 24 bytes inside a block of size 26 alloc'd
==17440==    at 0x4C28D84: malloc (vg_replace_malloc.c:291)
==17440==    by 0x4E5A8A0: tcrealpath (tokyocabinet_all.c:7426)
==17440==    by 0x4E6E797: tchdbopen (tokyocabinet_all.c:11767)
==17440==    by 0x4E79BCA: tcbdbopenimpl (tokyocabinet_all.c:19512)
==17440==    by 0x4E7AFED: tcbdbopen (tokyocabinet_all.c:16870)
==17440==    by 0x400CC9: main (in a.out)

#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
TCBDB*bdb;
BDBCUR*cur;
国际编码;
字符*键,*值;
/*创建对象*/
bdb=tcbdbnew();
/*打开数据库*/
如果(!tcbdbopen(bdb,“casket.tcb”,BDBOWRITER | BDBOCREAT)){
ecode=tcbdbecode(bdb);
fprintf(stderr,“打开错误:%s\n”,tcbdberrmsg(ecode));
}
/*存储记录*/
如果(!tcbdbput2(bdb,“foo”,“hop”)||
!tcbdbput2(bdb,“条”,“步”)||
!tcbdbput2(bdb,“baz”,“jump”)){
ecode=tcbdbecode(bdb);
fprintf(stderr,“put error:%s\n”,tcbdberrmsg(ecode));
}
/*检索记录*/
价值=tcbdbget2(bdb,foo);
如果(值){
printf(“%s\n”,值);
自由(价值);
}否则{
ecode=tcbdbecode(bdb);
fprintf(stderr,“获取错误:%s\n”,tcbdberrmsg(ecode));
}
/*遍历记录*/
cur=tcbdbcurnew(bdb);
tcbdbcurfirst(cur);
while((key=tcbdbcurkey2(cur))!=NULL){
值=tcbdbcurval2(cur);
如果(值){
printf(“%s:%s\n”,键,值);
自由(价值);
}
免费(钥匙);
tcbdbcurnext(cur);
}
tcbdbcurdel(cur);
/*关闭数据库*/
如果(!tcbdbclose(bdb)){
ecode=tcbdbecode(bdb);
fprintf(stderr,“关闭错误:%s\n”,tcbdberrmsg(ecode));
}
/*删除对象*/
tcbdbdel(bdb);
返回0;
}

我的直觉是valgrind错误是假阳性

我怀疑它是由一个优化的strlen操作引起的,该操作应用于26字节的对象,该对象包含一个25个字符的字符串

尽管您认为这两个系统使用相同的编译器,但在编译strlen调用的方式上,这两个系统之间可能存在一些差异,或者其他一些差异,请参见下文

在一个系统上,strlen是通过对四字节字进行字对齐读取来完成的。循环获取超出对象末尾的一些额外字节,Valgrind将其标记为错误

不过,这种越界访问是无害的,因为长度操作不依赖于这些字节(不管这些字节中可能有什么垃圾,它都会计算出正确的字符串长度)。此外,如果单词的基址位于映射页中,则这些越界字节不能位于未映射页中,因为单词与其大小的倍数对齐,并且基址位于有效对象中。(也就是说,如果A是一个可被4整除的地址,并且字节A位于有效页内,那么字节A+1到A+3不能位于未映射页中:它们与字节A位于同一页中!)

因此,总而言之,这个Valgrind错误可能并不指向东京内阁中的任何错误


两个系统之间的一个可能区别是数据库的绝对路径。

尽管您的
main
程序将数据库指定为相对路径
“casket.tcb”
,但库使用
realpath
函数将其转换为绝对路径。字符串操作在该路径上执行,长度可能不同,除非两个系统上的目录结构完全相同,并且在不同系统的相应子目录中执行这些测试


在一个系统上,经过优化的strlen可以处理一个大小正好可以被4整除的malloced对象,因此循环优化不会产生越界访问。

值得一提的是,东京内阁网站“强烈建议”使用京都内阁。这可能部分原因是TC中的bug无法修复。你使用的是什么版本的TC?谢谢你的提示,我使用的是1.4.48(最新版本)。仅仅因为作者认为每个人都应该使用京都内阁而不是东京内阁,这并不能证明京都内阁的问题更少。(有多少次旧版本的用户被闪亮的新版本的承诺烧掉了?)SourceForge中没有1.4.48。在文件部分,我们只能找到日期为2009年的1.4.32。此外,令人困惑的是,东京内阁Sourceforge页面提供了一个名为东京长廊(Tokyo Promenade)的下载。您提供的页面的tarball值仅为1.4.48;但是在1.4.33到1.4.47之间发生了什么呢?可浏览的源代码repo在哪里;
tokyocabinet_all.o
模块由
cat myconf.c tcutil.c md5.c tchdb.c tcbdb.c tcfdb.c tctdb.c tcadb.c>tokyocabinet_all.c
制成。感谢您的回答,我当然同意您的说法,这似乎是valgrind的假阳性。@PeteDarrow这几乎肯定是正确的答案,应该被接受。
#include <tcutil.h>
#include <tcbdb.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

int main(int argc, char **argv){
  TCBDB *bdb;
  BDBCUR *cur;
  int ecode;
  char *key, *value;

  /* create the object */
  bdb = tcbdbnew();

  /* open the database */
  if(!tcbdbopen(bdb, "casket.tcb", BDBOWRITER | BDBOCREAT)){
    ecode = tcbdbecode(bdb);
    fprintf(stderr, "open error: %s\n", tcbdberrmsg(ecode));
  }

  /* store records */
  if(!tcbdbput2(bdb, "foo", "hop") ||
     !tcbdbput2(bdb, "bar", "step") ||
     !tcbdbput2(bdb, "baz", "jump")){
    ecode = tcbdbecode(bdb);
    fprintf(stderr, "put error: %s\n", tcbdberrmsg(ecode));
  }

  /* retrieve records */
  value = tcbdbget2(bdb, "foo");
  if(value){
    printf("%s\n", value);
    free(value);
  } else {
    ecode = tcbdbecode(bdb);
    fprintf(stderr, "get error: %s\n", tcbdberrmsg(ecode));
  }

  /* traverse records */
  cur = tcbdbcurnew(bdb);
  tcbdbcurfirst(cur);
  while((key = tcbdbcurkey2(cur)) != NULL){
    value = tcbdbcurval2(cur);
    if(value){
      printf("%s:%s\n", key, value);
      free(value);
    }
    free(key);
    tcbdbcurnext(cur);
  }
  tcbdbcurdel(cur);

  /* close the database */
  if(!tcbdbclose(bdb)){
    ecode = tcbdbecode(bdb);
    fprintf(stderr, "close error: %s\n", tcbdberrmsg(ecode));
  }

  /* delete the object */
  tcbdbdel(bdb);

  return 0;
}