起因
我们有以下代码:
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,这里高亮的地方是错误的地方
注意
这个
BUG在glibc版本为2.35时会消失,但是在2.39时会触发,你可以通过Ubuntu-24来重现它
原因与解决
这个问题在以下文章/论坛中都有提到
造成这个错误的原因就是 UB,本质上在 manual 中,我们可以看见这样一句话:

原因可能如下:
strcpy通常从前向后复制字符,直到遇到空字符。当dest > src且存在重叠时,已复制的数据会破坏src未复制部分,导致后续复制操作读取错误数据,这一般会出现在strcpy(s + 1, s)这样的调用中。- C 标准明确不要求
strcpy处理重叠内存,因此不同库的实现可能不一致,但均不保证正确性,这在不同平台之间尤为明显。
解决方法为使用 memmove ,其专为处理重叠内存设计,会检测方向并选择从后向前或从前向后复制。对于字符串操作,可结合 strlen 确定长度后使用 memmove:
char* s = "hello";memmove(s + 1, s, strlen(s) + 1);