这个宏是安全的还是我应该确保 alloca 永远不会返回 NULL?
#define DO_COPY(x) strcpy(alloca(strlen((x)) + 1), x)
如果字符串是用户控制的,我会说 alloca 不安全。在许多编译器中实现 alloca 的方式,它不会对它从堆栈指针中减去(或者如果你的堆栈以这种方式增长,则添加到)堆栈指针的量进行任何类型的健全性检查。即使堆栈周围有大的红色区域,使 alloca():ed 字符串指向堆栈外部的方式也相对容易。
特别是在线程环境中,线程堆栈可能非常小并且彼此靠近。
在 linux 机器上我可以测试它需要一个 10MB 的字符串才能开始在其他一些线程堆栈上涂鸦。在 MacOS 上 512kB 似乎就足够了。
这是一个快速的技巧,看看你最终能有多接近(请注意,如果堆栈分配是使用 OpenBSD 中的一些随机分配器完成的,或者其他一些重视分配器安全性的系统,这并不能真正告诉你太多)。
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <stdint.h>
void *
x(void *v)
{
int x;
return &x;
}
int
main(int argc, char **argv)
{
pthread_t ta, tb;
char *va, *vb;
pthread_create(&ta, NULL, x, NULL);
pthread_create(&tb, NULL, x, NULL);
pthread_join(ta, (void **)&va);
pthread_join(tb, (void **)&vb);
printf("diff: %d\n", abs((intptr_t)vb-(intptr_t)va));
return 0;
}
这是 strcpy(alloca(strlen(s) + 1), s) 被编译为:
movq %rbx, %rdi
call _strlen
addq $31, %rax
andq $-16, %rax
subq %rax, %rsp
movq %rsp, %rdi
movq %rbx, %rsi
call _strcpy
请注意,在从堆栈指针中减去 strlen(在 %rax 中)的返回值之前,除了快速对齐之外,没有任何完整性检查。