【问题标题】:sscanf function changes the content of another stringsscanf 函数改变另一个字符串的内容
【发布时间】:2013-05-16 16:50:14
【问题描述】:

我在使用 sscanf 读取字符串时遇到问题。我已经简化了代码以专注于问题。下面是整个代码中的一个函数,它应该打开一个文件并读取一些东西。但是sscanf 的行为很奇怪。例如,我声明了一个名为atm 的字符串,其内容为'ATOM'。在sscanf 之前,它将这个字符串打印为ATOM,而在它之后为空。可能是什么问题呢?我认为这一定是分配问题,但我找不到。我尝试了一些关于其他主题的建议,例如将 %s 替换为其他内容,但没有帮助。

 void Get (struct protein p, int mode, int type) 
 {
   FILE *fd; //input file
   char name[100]="1CMA"; //array for input file name
   char string[600]; //the array where each line of the data file is stored when reading
   char atm[100]="ATOM";
   char begin[4];
   int index1 =0;

   fd = fopen(name, "r"); // open the input file

   if(fd==NULL) {
     printf("Error: can't open file.\n");
     return 1;
   }    

   if( type==0 ) { //pdb file type
     if( mode==0 ) { 
       while( fgets(string, 600, fd)!=NULL ) {
         printf("1 %s\n",atm);
         sscanf (string, "%4s", begin );
         printf("2 %s \n",atm);
       }
     }   
   }
   fclose(fd);
   free(fd);
   free(name);
 }

【问题讨论】:

    标签: c string pointers buffer-overflow scanf


    【解决方案1】:

    字符串begin 不足以容纳sscanf 将读取的四个字符它的\0 终止符。如果\0 被写入atm(取决于字符串在内存中的位置),atm 将被修改。来自sscanf manpage,关于s指令:

    s    匹配一系列非空白字符;下一个指针必须是一个指向字符数组的指针,它的长度足以容纳输入序列和自动添加的终止空字节 ('\0')。输入字符串在空白处或最大字段宽度处停止,以先发生者为准。

    我能够在我的机器上重现这种行为,尽管字符串在内存中的确切位置有点不同。但是,通过打印字符串的地址,很容易准确地确定发生了什么。这是一个最小的例子:

    #include<stdio.h>
    
    int main() { 
      char begin[2];
      char atm[100]="ATOM";
    
      printf("begin:    %p\n", begin);
      printf("begin+16: %p\n", begin+16);
      printf("atom:     %p\n", atm);
      printf("1 %s\n",atm);
      sscanf("AAAABBBBCCCCDDDD", "%16s", begin);
      printf("2 %s \n",atm);
      return 0;
    }
    

    这会产生输出:

    $ ./a.out 
    begin:    0x7fffffffe120
    begin+16: 0x7fffffffe130
    atom:     0x7fffffffe130
    1 ATOM
    2  
    

    我打印了指针的值来计算溢出到atm 的字符串需要多大。因为(在我的机器上)atombegin+16 开始,将十六个字符读入begin 会在begin+16 处放置一个空终止符,这是atm 的第一个字符,所以现在atm 的长度为0。

    【讨论】:

    • 谢谢你确实是问题所在,这个帖子很有启发性。
    • @Sina 很高兴为您提供帮助!我几乎以“恭喜您成功加入 Buffer Overflow Club,最大的职业程序员协会之一!”开始回答,但有时幽默不会出现在文字中。这些是非常容易编写的错误类型,并且可能潜伏在许多代码行中。很高兴我们今天能抓到一只! :)
    • 谢谢,实际上我收到了一条关于 matlab 的消息:p 我通常在数学部分闲逛。一个后续问题,由于我使用的是 tcc 编译器,因此很难捕捉到这些错误,尤其是当代码太长时,我什至看到编译器也错过了这些错误的实例,甚至被说服写入第四个条目一个需要几天才能找到的三维数组。是否有任何编译器或调试器可以建议您捕获此类错误?
    • @Sina 那里有编译器(和编译器插件)试图检测一些缓冲区溢出,但我没有使用它们中的任何一个。抱歉,我无法在这方面提供更多帮助。
    猜你喜欢
    • 2022-08-12
    • 2011-02-19
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2013-03-21
    • 2014-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多