【问题标题】:Is this macro safe for copying a string?这个宏对于复制字符串是否安全?
【发布时间】:2012-10-18 02:55:35
【问题描述】:

这个宏是安全的还是我应该确保 alloca 永远不会返回 NULL?

#define DO_COPY(x) strcpy(alloca(strlen((x)) + 1), x)

【问题讨论】:

  • alloca()?如果是malloc,我会说是的,你必须检查一下。
  • stackoverflow.com/questions/1018853/… - 如果你使用alloca,你需要非常确定你在做什么......
  • 这完全取决于您使用它的上下文。

标签: c


【解决方案1】:

如果字符串是用户控制的,我会说 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 为单位)的返回值之前,除了快速对齐之外,没有任何完整性检查。

【讨论】:

  • 我之前在 StackOverflow 上问过一个与您关注的问题相关的问题:stackoverflow.com/questions/5543330。那里的答案让我相信,对于桌面操作系统和适当的编译器,情况并不像你说的那么惨淡。编译器是否有任何原因不生成访问新堆栈分配页面的代码以及alloca()
  • 哦,对于 GCC,它是可选的。您需要使用-fstack-check
  • @PascalCuoq 我刚刚在 MacOS 和两种不同风格的 Linux 上检查了 gcc 和 clang,它们都跳过了任何类型的健全性检查。可能有启用检查的标志,但编译器中的安全功能如果默认不启用(并且很难禁用),则它们是无用的。
  • 我可以轻松地将我的代码替换为使用 malloc 吗?与我交谈过的大多数人都告诉我要不惜一切代价避免使用 alloca。
猜你喜欢
  • 2021-01-02
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 2013-03-13
  • 2010-09-24
  • 2011-02-07
相关资源
最近更新 更多