【问题标题】:C: strncpy more characters than allocated then printing... unexpected output?C:strncpy 比分配的字符多,然后打印...意外输出?
【发布时间】:2012-03-25 16:30:03
【问题描述】:

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

#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 个字节α)。这一点我相信我明白。

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

ABCDEFGHIJKLMNOPQRSTUVWXYZ
I
27
26
ABCDEFGHZJKLMNOPQRSTUVWXYZKLMNOPQRSTUVWXYZ

我认为由于 strncpy 不会终止字符串,所以当打印 X 时,它实际上可能会打印 alpha 的完整值 - 但实际上,它正在打印所有 alpha,然后还有更多alpha!

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

【问题讨论】:

    标签: c printf buffer-overflow strcpy


    【解决方案1】:

    使用此代码:

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

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

    当您“printf”x 时,它会一直打印直到遇到空字节,因此它会打印出您复制的所有 26 个字节,以及内存中的其他内容(“alpha”的剩余内容),直到下一个空字节.

    【讨论】:

      【解决方案2】:

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

      strncpy( x, alpha, 26 );
      

      正在修改 alpha 的数据。

      【讨论】:

        【解决方案3】:
         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' 作为字符串的终止字符。在这种情况下,不知何故,“KLMNOPQRSTUVWXYZ”之后恰好出现了“\0”。

        因此,实际上,当您执行超出范围的数组时,您可能会得到任何类型的结果、崩溃、过长的字符串等。

        【讨论】:

        • 我希望KLMNOPQRSTUVWXYZ 会在ABCDEFGHZJKLMNOPQRSTUVWXYZ 之后直接打印出来是有确定性的原因的;我想如果空字符出现在 Z 之后,则不会显示 K-Z 的第二个输出。
        • 您只复制了 26 个字符,因此不会复制 alpha 中“Z”之后可能出现的空字符。但是,越界数组仍然不能保证什么,因为x只分配了10个字节,x的第10个字节之后的内存不属于你,无论如何都可以操作
        【解决方案4】:

        你只是走运了。超出数组范围写入会导致未定义行为

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

        是的,您的程序有时甚至可以按预期工作,但按照标准,它仍然是格式错误的程序。

        【讨论】:

          猜你喜欢
          • 2020-07-20
          • 1970-01-01
          • 2016-04-03
          • 2015-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-19
          相关资源
          最近更新 更多