【问题标题】:strdupa() in C - Dangers and DuplicatesC 中的 strdupa() - 危险和重复
【发布时间】:2016-02-17 02:41:42
【问题描述】:

我用 C 编写程序。我读到了 strdup() 函数。据我所知,strdup() 函数分配空间,而strcpy() 没有。但是strdup() 的问题是它分配空间但不释放它。 strdupa() 分配和释放空间。但在某些地方我读到strdupa() 函数很危险。如果有人能告诉我为什么strdupa() 很危险,那将会很有帮助。此外,当我尝试在我的 Open Suse 12.1 32 位系统中运行程序时,gcc 给出了一个错误,提示 strdupa() 不存在。如果strdupa() 是一个危险的功能,有人可以告诉我strdupa() 的副本以及使用该功能时要使用的标题。

【问题讨论】:

  • “但是 strdup() 的问题是它分配空间但不释放它”。 malloc 也有这个“问题”。关键是它本身不是问题,因为调用代码可以free 它。有些人认为,如果编码人员忘记释放内存,可能会导致内存泄漏。但在许多情况下,您实际上确实希望内存在当前函数之外持续存在,因此实际上不释放内存是我们想要的。
  • 所以你说使用 strdup() 函数比使用 strdupa() 更好
  • 不,我说的是适合工作的正确工具。
  • 所以你的意思是说,将一个字符串复制到另一个字符串并自动分配内存,strdup() 更好。
  • 这不是“更好”或“更差”的问题。关键是,如果你使用“strdup()”,那么你需要知道它执行了一个“malloc()”,而“free()”是你的责任。如果字符串需要在复制它的函数之外持续存在,这正是您想要和需要的行为。作为补充说明,"strdup()" 是 Posix 标准,“strdupa()”不是。

标签: c strdup


【解决方案1】:

strdupa() 函数被记录为使用alloca() 函数分配内存。这意味着它的内存在函数返回时被释放。 alloca() 函数不是特别可移植的; strdupa() 函数同样不是那么便携。

手册页记录了 strdupa() 函数仅在使用 -D_GNU_SOURCE 编译时可用,或者在使用 gcc -std=gnu11 或类似的东西时可用。

如果你需要在调用strdupa()的函数返回后访问内存,那么你不能使用strdupa()——strdup()是必须的。如果您担心可移植性,您可能会使用strdup(),尽管这仅由 POSIX (strdup()) 而不是由标准 C 定义。请注意,strdup()TR 24731-2: Extensions to the C Library - Part II: Dynamic allocation functions 的一部分。 AFAIK,alloca() 既不是 POSIX 的一部分,也不是标准 C 库的提议扩展的一部分。


使用'strdupa()'有什么危险吗?

这取决于您对“危险”的定义。是的。如果堆栈上没有足够的空间存放字符串,那么strdupa() 将失败,而strdup() 不会。有些人不喜欢alloca(),因此他们不热衷于使用alloca() 的代码。 alloca() 手册页包含大量有关问题的注释,其中一个是您无法判断 alloca() 何时失败。

是否有用于检查 alloca() 故障的工具 - 例如 valgrind 是否存在内存泄漏?

您寻找核心转储;如果程序崩溃,可能是因为alloca() 分配失败。使用valgrind 可能会发现问题;但是,您仍然无法可靠地从问题中恢复,并且您的生产代码可能不会在valgrind 下运行,因此它最多只能作为诊断辅助工具。如果您想要可靠的行为,请使用 strdup() — 并接受您需要手动释放分配的内存。

来自alloca() 的手册页

备注
alloca() 函数依赖于机器和编译器。对于某些应用程序,与使用 malloc(3) 和 free(3) 相比,使用它可以提高效率。在某些情况下,它还可以简化使用 longjmp(3) 或 siglongjmp(3) 的应用程序中的内存释放。否则,不鼓励使用它。

由于alloca() 分配的空间是在堆栈帧内分配的,如果函数返回被调用 longjmp(3) 或 siglongjmp(3) 跳过,则该空间会自动释放。

不要尝试释放 (3) alloca() 分配的空间!

GNU 版本说明
通常,gcc(1) 使用内联代码将调用转换为alloca()。当给定-ansi-std=c89-std=c99-fno-builtin 选项时(并且不包括标题<alloca.h>),则不会执行此操作。但要小心!默认情况下,<stdlib.h> 的 glibc 版本包括 <alloca.h> 并包含以下行:

#define alloca(size)   __builtin_alloca (size)

如果有这个函数的私有版本,后果会很混乱。

代码被内联的事实意味着不可能获取这个函数的地址,或者通过链接不同的库来改变它的行为。

内联代码通常由一条调整堆栈指针的指令组成,并且不检查堆栈溢出。因此,没有 NULL 错误返回。

错误
如果堆栈帧无法扩展,则没有错误指示。 (但是,在分配失败后,如果程序尝试访问未分配的空间,它很可能会收到 SIGSEGV 信号。)

在许多系统上,alloca() 不能在函数调用的参数列表中使用,因为 alloca() 保留的堆栈空间将出现在函数参数空间中间的堆栈中。

【讨论】:

  • 使用'strdupa()'有什么危险
  • @Screwdriver "alloca() 函数返回一个指向已分配空间开头的指针。如果分配导致堆栈溢出,则程序行为未定义。”,除了“返回后不使用”之外答案中给出。
  • 这取决于你对“危险”的定义。是的。如果堆栈上没有足够的空间存放字符串,那么strdupa() 将失败,而strdup() 不会。有些人不喜欢alloca(),因此他们不热衷于使用alloca() 的代码。 alloca() 手册页(链接在答案中)包含大量有关问题的注释,其中一个是您无法判断 alloca() 何时失败。
  • 是否有工具可以检查 'alloca()' 故障。比如内存泄漏的“valgrind”?
  • 您寻找核心转储;如果程序崩溃,可能是因为alloca() 分配失败。使用valgrind 可能会发现问题;但是,您仍然无法可靠地从问题中恢复,并且您的生产代码可能不会在valgrind 下运行,因此它最多只能作为诊断辅助工具。如果您想要可靠的行为,请使用 strdup() — 并接受您需要手动释放分配的内存。
猜你喜欢
  • 2015-11-13
  • 2012-07-18
  • 1970-01-01
  • 2011-06-21
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
相关资源
最近更新 更多