C:strncpy比分配更多的字符然后打印...意外输出?

时间:2012-03-08 05:49:19

标签: c printf buffer-overflow strcpy

在一些教授给出的示例代码中:

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

int main()
{
  char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  printf( "%s\n", alpha );
  printf( "%c\n", alpha[8] );
  alpha[8] = 'Z';   /* segmentation fault if alpha is declared statically! */

  printf( "%d\n", sizeof( alpha ) );
  printf( "%d\n", strlen( alpha ) );

  char x[10];
  strncpy( x, alpha, 26 );
   /* strncpy() will NOT copy or append a '\0' */
  printf( "%s\n", x );

  return EXIT_SUCCESS;
}

当第一次编译和运行时,程序会出现段错误,因为我在几分钟的谷歌搜索中看到了一个针对缓冲区溢出的gcc保护机制(由printf( "%s\n", x );触发,其中x已被填充26来自alpha的字节)。我相信我理解这一点。

但是,当使用gcc -fno-stack-protector禁用保护机制时,我看到的输出是:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
I
27
26
ABCDEFGHZJKLMNOPQRSTUVWXYZKLMNOPQRSTUVWXYZ

我认为,因为strncpy不会终止字符串,所以当打印X时,它实际上可能会打印alpha的完整值 - 但事实上,它打印的所有alpha },然后还有一些alpha

有人可以在这里提供一些见解吗?

4 个答案:

答案 0 :(得分:2)

你很幸运。超出数组范围的写入会导致未定义的行为

未定义的行为意味着任何行为都是可能的,它总是不会导致分段错误,它只是意味着程序无效并且可能显示任何行为。

是的,您的程序有时甚至可以按照需要运行,但它仍然是按照标准生成的程序。

答案 1 :(得分:2)

 char x[10];   strncpy( x, alpha, 26 );    
/* strncpy() will NOT copy or append a '\0' */   
printf( "%s\n", x ); 

要strncpy,你传递的是26,作为n的值,所以它复制了26个字符,但是当你使用printf打印时,printf将尝试搜索'\ 0'作为字符串的终止字符。在这种情况下,'\ 0'碰巧出现在“KLMNOPQRSTUVWXYZ”之后。

所以,实际上,当你做一个超出范围的数组时,你可能得到任何结果,崩溃,一个太长的字符串等。

答案 2 :(得分:1)

问题在于内存布局 在这个程序中,“alpha”就在“x”之后。所以当你打电话时

strncpy( x, alpha, 26 );

正在修改alpha的数据。

答案 3 :(得分:1)

使用此代码:

   char x[10];
   strncpy( x, alpha, 26 );

您正在将26个字节的数据复制到10个字节的数组,这意味着您将覆盖16个字节的任何与“x”相邻的内存。在这种情况下,看起来与“x”相邻的是“alpha”,所以你破坏了初始数组的一部分

当你“printf”x时,它会一直打印直到它到达一个空字节,所以它打印出你复制的所有26个字节,加上内存中的任何其他内容(“alpha”的幸存内容)直到下一个空字节