C中的空终止错误

时间:2013-04-10 11:22:16

标签: c

我正在阅读Robert C Seaford的C和C ++书中的安全编码。

int main(int argv, char* argv[]) {
  char a[16];
  char b[16];
  char c[32];

  strcpy(a, "0123456789abcdef");
  strcpy(b, "0123456789abcdef");
  strcpy(c, a);
  strcat(c, b);
  printf("a = %s\n", a);
  retrun 0;
}

三个字符数组的静态声明无法为空终止字符分配存储空间。

结果,第一个strcpy()在数组末尾写入一个空字符。

根据编译器分配存储的方式,下一行的strcpy()可能会覆盖此空字节。如果发生这种情况,a现在指向一个包含20个字符的数组,而b指向一个包含10个字符的数组。

我的问题是作者的意思是数组a包含20个字符而数组b指向10个字符?

1 个答案:

答案 0 :(得分:4)

我必须假设“10”我们谈论的是十六进制0x10(16),而“20”我们谈论的是十六进制0x20(32)。

无论如何,关键是字符串操作代码通过空字符的位置确定字符串的长度,而不是数组中实际分配的字符数。如果内存分配如下:

<-------a------><-------b------><--------------c-------------->

然后在第一个strcpy后,内存看起来像这样。 (我将使用!来表示null)。

<-------a------><-------b------><--------------c-------------->
0123456789abcdef!

然后在第二个strcpy后,内存看起来像这样。

<-------a------><-------b------><--------------c-------------->
0123456789abcdef0123456789abcdef!

每个strcpy操作都会溢出它应该写入并使用相邻内存的数组,这是一种非常糟糕的做法。任何操纵a的函数都是一个字符串,它会看到32个(0x20)字符(不计算空值),任何操纵b的函数就像它的字符串一样会看到16(0x10)个字符(不是尽管你只在每个数组中为15个字符分配了足够的内存(不计算空值)。

任何这种情况都不会崩溃的事实是内存如何布局的意外。如果你在一个数组中写入的字符比你有空格要多,并且写入的相邻内存不可写,那么你就会崩溃。

当然,既然您正在阅读安全编码,那么您覆盖其他内容的事实可能是一个严重的安全问题,具体取决于输入的可信度以及被覆盖的确切内容。