使用 strlen() 在堆栈中分配缓冲区
Posted
技术标签:
【中文标题】使用 strlen() 在堆栈中分配缓冲区【英文标题】:Buffer allocation in stack with 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() 的计算结果? 【参考方案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
进行扩展以获取缓冲区空间。
【讨论】:
以上是关于使用 strlen() 在堆栈中分配缓冲区的主要内容,如果未能解决你的问题,请参考以下文章