【问题标题】:Buffer allocation in stack with strlen()使用 strlen() 在堆栈中分配缓冲区
【发布时间】:2014-09-07 02:27:21
【问题描述】:

我有以下代码:

void function(char *str)
{
    int i;
    char buffer[strlen(str) + 1];

    strcpy(buffer, str);
    buffer[strlen(str)] = '\0';

    printf("Buffer: %s\n", buffer);
}

我希望这段代码会引发编译时错误,因为在堆栈上分配的“缓冲区”具有运行时相关长度(基于 strlen())。但是在 GCC 中编译通过了。这是如何运作的?缓冲区是动态分配的,或者如果它仍然是堆栈本地的,那么分配的大小是多少?

【问题讨论】:

  • 这是有效的 C99,是的,它是根据计算的大小在堆栈上分配的。
  • @mafso 为什么说它会导致未定义的行为?
  • 您标记了两种不同的语言。这在(现代)C 中有效,但在(标准)C++ 中无效。你用的是哪个?
  • @DrewMcGowen 对不起,我有点慢。所以我的理解是,这在非 C99 中是完全有效的,并且在每次调用 function() 时,缓冲区都会在堆栈上分配;并且大小将等于 strlen() 的计算结果?

标签: c++ c stack c99


【解决方案1】:

C99 允许可变长度数组。不在 C99 中编译代码不会产生任何错误,因为 GCC 还允许变长数组作为扩展。

6.19 Arrays of Variable Length:

在 ISO C99 中允许使用可变长度自动数组,作为扩展,GCC 在 C90 模式和 C++ 中接受它们

【讨论】:

    【解决方案2】:

    通过反汇编你的函数,你可以很容易地验证这一点:

    $ objdump -S <yourprogram>
    
    ...
    void function(char *str)
    {
       4011a0:   55                      push   %ebp
       4011a1:   89 e5                   mov    %esp,%ebp
       4011a3:   53                      push   %ebx
       4011a4:   83 ec 24                sub    $0x24,%esp
       4011a7:   89 e0                   mov    %esp,%eax
       4011a9:   89 c3                   mov    %eax,%ebx
         int i;
         char buffer[strlen(str) + 1];
       4011ab:   8b 45 08                mov    0x8(%ebp),%eax
       4011ae:   89 04 24                mov    %eax,(%esp)
       4011b1:   e8 42 01 00 00          call   4012f8 <_strlen>
       4011b6:   83 c0 01                add    $0x1,%eax
       4011b9:   89 c2                   mov    %eax,%edx
       4011bb:   83 ea 01                sub    $0x1,%edx
       4011be:   89 55 f4                mov    %edx,-0xc(%ebp)
       4011c1:   ba 10 00 00 00          mov    $0x10,%edx
       4011c6:   83 ea 01                sub    $0x1,%edx
       4011c9:   01 d0                   add    %edx,%eax
       4011cb:   b9 10 00 00 00          mov    $0x10,%ecx
       4011d0:   ba 00 00 00 00          mov    $0x0,%edx
       4011d5:   f7 f1                   div    %ecx
       4011d7:   6b c0 10                imul   $0x10,%eax,%eax
       4011da:   e8 6d 00 00 00          call   40124c <___chkstk_ms>
       4011df:   29 c4                   sub    %eax,%esp
       4011e1:   8d 44 24 08             lea    0x8(%esp),%eax
       4011e5:   83 c0 00                add    $0x0,%eax
       4011e8:   89 45 f0                mov    %eax,-0x10(%ebp)
    ....
    

    无论如何,这里的相关组件是sub %eax,%esp。这表明堆栈已根据之前返回的任何 strlen 进行扩展以获取缓冲区空间。

    【讨论】:

      猜你喜欢
      • 2021-12-29
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      • 2012-11-23
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      相关资源
      最近更新 更多