忘れてください

strcpy 中的 overlap 问题

2 min read

起因#

我们有以下代码:

void remove_leading_zeros(char *str) {
  int i = 0;
  while (str[i] == '0' && str[i + 1] != '\0') {
    i++;
  }
  if (i > 0) {
    strcpy(str, str + i);
  }
}

在运行这个函数时,假设我们的代码如下:

char* s = "0077160493132716049313271604931327160493";
remove_leading_zeros(s);
printf("%s\n", s);

我们将会得到 77160493132716049313271604931327160493,这里高亮的地方是错误的地方

原因与解决#

这个问题在以下文章/论坛中都有提到

  1. strcpy-on-overlapped-strings
  2. strcpy substring
  3. strcpy overlapping memory

造成这个错误的原因就是 UB,本质上在 manual 中,我们可以看见这样一句话:

image.png

原因可能如下:

  • strcpy  通常从前向后复制字符,直到遇到空字符。当  dest > src  且存在重叠时,已复制的数据会破坏  src  未复制部分,导致后续复制操作读取错误数据,这一般会出现在 strcpy(s + 1, s) 这样的调用中。
  • C 标准明确不要求  strcpy  处理重叠内存,因此不同库的实现可能不一致,但均不保证正确性,这在不同平台之间尤为明显。

解决方法为使用 memmove ,其专为处理重叠内存设计,会检测方向并选择从后向前或从前向后复制。对于字符串操作,可结合  strlen  确定长度后使用  memmove:

char* s = "hello";
memmove(s + 1, s, strlen(s) + 1);
CONVERSATION

讨论

想法、补充,或只是打个招呼。

关系图谱 ↓

全局关系图谱

页面标签
笔记
↑ ↓ 选择↵ 打开Esc 关闭