跳转到内容

C 编程/C 参考/非标准/strlcpy

来自维基教科书,开放的书籍,为了一个开放的世界

在计算机编程中,strlcpy 函数旨在用一个安全的版本替换函数strcpy(将字符串复制到目标缓冲区),该安全版本不会溢出目标缓冲区。它几乎总是伴随着strlcat 函数,该函数为strcat(将源字符串追加到目标缓冲区)提供类似的替代方案。

标准 C 函数可以用来避免缓冲区溢出,strncpystrncat,存在严重的設計缺陷,使得它們难以使用且不必要地慢。strlcpystrlcat被设计成,尽可能使正确使用变得简单。

这些不是 C 标准库函数,但可以在几个 Unix 操作系统的库中使用,包括 BSD、Mac OS X、Solaris、Android 和 IRIX,显着例外是 Linux 上的 glibc,尽管它可以在libbsd 中使用。

size_t strlcpy(char *destination, const char *source, size_t size);
size_t strlcat(char *destination, const char *source, size_t size);

strncpy, strlcpy一样,它将目标的大小作为参数,并且不会写入超过该数量的字节,以防止缓冲区溢出(假设size是正确的)。但是,与strncpy, strlcpy 不同,它总是向目标写入单个NUL字节(如果size不为零)。生成的字符串保证以NUL-结尾,即使被截断。另外,它不像NUL那样,浪费时间写入多个字节来填充缓冲区的剩余部分。strncpy.[1]

此外,strlcpy计算并返回整个源字符串的长度(strncpy不返回长度)。这个长度可以与目标缓冲区的大小进行比较,以检查它是否被截断,以及如何绕过截断,例如

char *copy; // this will point at our copy of the string
size_t length; // this will hold the length of the string

// Copy to a fast block of memory on the stack:
char stack_buffer[128];
length = strlcpy(stack_buffer, source, sizeof(stack_buffer));

if (length < sizeof(stack_buffer)) {
  // it fit, use the stack buffer
  copy = stack_buffer;
} else {
  // it was truncated, use a slower buffer on the heap: 
  copy = malloc(length+1);
  if (copy != NULL)
    memcpy(copy, source, length+1);
}

// Now use the copy of the string. The length is often useful, too:
use(copy, length);

// free the buffer if we allocated it:
if (copy != stack_buffer) free(copy);

strlcat等效于将追加的字符串写入无限大的临时缓冲区,然后从该缓冲区进行strlcpy到目标。

strlcpystrlcat由 Todd C. Miller 和 Theo de Raadt 开发,并首次在 OpenBSD 版本 2.4 中实现。后来被许多操作系统采用,包括 FreeBSD (从版本 3.3 开始)、Solaris、Mac OS X 和通过 libbsd 的 GNU 基于系统。许多应用程序包和库包含它们自己的这些函数副本,包括 glib、rsync、Samba、KDE 和 Linux 内核本身。

GNU C 库维护者 Ulrich Drepper 是strlcpystrlcat函数的批评者之一;[2] 因此,这些函数没有被添加到 glibc 中。Drepper 认为strlcpystrlcat使程序员更容易忽略截断错误,因此可能会引入比它们消除的错误更多。[2] 他对使用任何涉及静态分配的字符串函数时可能出现的截断的担忧,也为其他人所分享。[3]

Drepper 推荐的替代方案是

  *((char *) mempcpy (dst, src, n)) = '\0';

其他批评是,这些函数是非标准的,并且 BSD 和 Solaris 实现之间存在实现差异(strlcat的返回值,当目标缓冲区中没有 NUL 时,会有所不同)。[4]

参考文献

[编辑 | 编辑源代码]
  1. Miller, Todd C.; de Raadt, Theo (1999). "strlcpy and strlcat - consistent, safe, string copy and concatenation". USENIX '99.
  2. a b libc-alpha 邮件列表,来自 2000 年 8 月 8 日主题的选定邮件:536061
  3. Antill, James. 使用字符串 API 的安全性:在字符串库 API 中查找与安全性相关的事项
  4. Antill, James. 使用字符串 API 的安全性
[编辑 | 编辑源代码]
的讨论
华夏公益教科书