2014-07-22 106 views
0

我正在编写一个小的C代码来接收一些用户输入,这将是一个字符串。现在我读了很多地方,使用gets()会非常不安全,因为它可能导致缓冲区溢出攻击。而在大多数地方,我发现作为一种替代方法是使用fgets(),而就缓冲区溢出而言更安全。调整gets()以避免缓冲区溢出

现在我有一个问题场景,我不知道之前的缓冲区大小。它不能确定。它可能是任何东西。所以在这种情况下,fgets()会很方便吗?

另外,如果我使用gets()来解决这个问题,那么会出现什么问题呢?

char * temp_buffer_to_hold_user_input = NULL; 
cahr * actual_buffer_that_stores_user_input = NULL; 
int length_of_user_input =0; 

/* taking user input, irrespective of its length using gets() */ 

gets(temp_buffer_to_hold_user_input); 

/* now finding the length of the user input string and allocating the required number of bytes for proper (safe) usage */ 

length_of_user_input=length(temp_buffer_to_hold_user_input); 
actual_buffer_that_stores_user_input = (char*)malloc(length_of_user_input*sizeof(char)); 
strcpy(actual_buffer_that_stores_user_input, temp_buffer_to_hold_user_input); 

/* and now we work with our actual buffer */ 

那么gets()的上述用法仍然存在缓冲区溢出问题?因为在上面我们没有首先声明一个固定大小的缓冲区......所以没有缓冲区溢出是我所期望的。

如果我错过了某些东西,请纠正我!

+4

确实没有缓冲区溢出。 'gets()'将字符串存储在'NULL'处将会受到伤害。 – Quentin

+1

只要说** NO **到'gets()'并且继续你的生活。仅供参考:自2011年12月以来,'gets()'不再是C语言的一部分(一些C2011编译器将其作为扩展提供;其他编译器可能不兼容C2011)。 – pmg

+0

因为使用动态数组(char * temp_buffer_to_hold_user_input = NULL;),所以不会发生缓冲区溢出问题。我认为没有必要将i/p存储到另一个阵列。 – Sathish

回答

5
char * temp_buffer_to_hold_user_input = NULL; 

您将指针设置为NULL。因此有根本没有缓冲区gets将会失败,出现未定义的行为(实际上可能是分段错误)。

gets要求您提供一个有效的指针缓冲区。空指针不指向任何东西,因此这个前提条件不被满足。由于所有缓冲区的长度都是有限的,并且用户输入的长度未知,因此根本没有办法避免发生潜在的缓冲区溢出(更不用说安全风险)。从官方标准中删除了gets已被删除。

正确的方法是使用fgets。具有可变大小的输入处理是棘手的,所以你有两个选择:

  • 使用fgets有“足够大的我所有的情况下,”缓冲区大小。简单的出路。最糟糕的情况是你失去了一些输入。
  • 反复使用fgets并连接到某些动态分配的数组(并且不要忘记根据需要调整此数组的大小!),直到达到分隔符为止。 注意:取决于你对字符串所做的事情,你可能甚至不需要把整个事情都放在一起,这简化了事情。
+0

我同意。在实践中你可以做的是重复调用“fgets”,使用有限长度temp_buffer_to_hold_user_input,直到你读取的缓冲区为空,并且每次增加actual_buffer_that_stores_user_input的大小并追加新数据。 –

2

如果你不知道你在动手之前可以看看到getline(),或建立自己的功能和realloc你的字符串,像缓冲区大小:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(void) 
{ 
    char buf[8], *s = NULL, *p; 
    size_t i = 0; 

    while (fgets(buf, sizeof buf, stdin)) { 
     if (i++ == 0) { 
      s = malloc(sizeof buf); 
      if (s == NULL) { 
       perror("malloc"); 
       exit(EXIT_FAILURE); 
      } 
      strcpy(s, buf); 
     } else { 
      s = realloc(s, (i + 1) * sizeof(buf)); 
      if (s == NULL) { 
       perror("realloc"); 
       exit(EXIT_FAILURE); 
      } 
      strcat(s, buf); 
     } 
     if ((p = strchr(s, '\n'))) { 
      *p = '\0'; 
      break; 
     } 
    } 
    printf("%s\n", s); 
    free(s); 
    return 0; 
} 

没有一个中间缓冲区:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define BUF_LEN 8 

int main(void) 
{ 
    size_t len = BUF_LEN; 
    char *s, *p; 

    p = s = malloc(len); 
    if (s == NULL) { 
     perror("malloc"); 
     exit(EXIT_FAILURE); 
    } 
    while (fgets(p, BUF_LEN, stdin)) { 
     if ((p = strchr(p, '\n'))) { 
      *p = '\0'; 
      break; 
     } else { 
      len += BUF_LEN - 1; 
      s = realloc(s, len); 
      if (s == NULL) { 
       perror("realloc"); 
       exit(EXIT_FAILURE); 
      } 
      p = s + len - BUF_LEN; 
     } 
    } 
    printf("%s\n", s); 
    free(s); 
    return 0; 
} 
+1

我喜欢关于总是检查'malloc'和'realloc'的结果的示例代码下面的警告。 http://en.wikipedia.org/wiki/File:MagrittePipe.jpg –

0

扭捏得到(),以避免缓存溢出

其他人已经在正文中处理了您的问题。这是一个简单的答案,可以解决标题中的问题。

标准C通过gets_s提供gets的“更安全”变体。它被添加到C标准ISO/IEC TR 24731-1。其中,TR 24731-1的安全功能检查目标缓冲区大小,以避免其“不安全”对应端的许多缓冲区溢出问题。

下面是从文档:

enter image description here

所以,你真的不需要调整任何东西。您只需要使用正确的作业功能;)