C11 附件 K:"objects that overlap"

C11 Annex K: "objects that overlap"

在C标准的Annex K(边界检查接口)中有一个短语不断弹出:

....copying shall not take place between objects that overlap.

考虑,例如,strcpy_s( char * restrict s1, rsize_t s1max, char const * restrict s2 ),其中s1max指定s1的最大容量以启用边界检查。

此时 "the object" s1 究竟是什么,不能与 "the object" s2 重叠?

会不会是...

如果是前者,我想知道缺乏一致性,因为我不知道 buffer 即 s2 的大小,并且必须应用不同的"the object".

的定义

如果是后者,我想知道它是否不会破坏给定的 "the promise",因为可以想象源字符串和 eventual (post-copy) 如果源字符串比原始字符串长,目标字符串可能重叠。

此处 "object" 的意图/预期定义是什么?

我认为其意图是从 s1 开始的 s1max 个字符不得与 s2 中的任何字符重叠,包括空终止符。 K.3.7.1.3p5 表示:

  1. All elements following the terminating null character (if any) written by strcpy_s in the array of s1max characters pointed to by s1 take unspecified values when strcpy_s returns. [418]

footnote 418

  1. This allows an implementation to copy characters from s2 to s1 while simultaneously checking if any of those characters are null. Such an approach might write a character to every element of s1 before discovering that the first element should be set to the null character.

但是,Microsoft 表示 "if source and dest overlap, the behavior is undefined",因此这暗示实际上在这种情况下任何事情都可能发生。这似乎否定了 bounds-checking 接口的有用性。

这在标准中随处可见,不仅在可选的 bounds-checking 接口中,而且在 strcpy 等强制性库函数中也有。 bounds-checking 接口函数只是继承了完全相同的文本。

对象的正式定义是:

3.15
object
region of data storage in the execution environment, the contents of which can represent values

基于此,字符串必须是包括空终止符在内的整个数组。因为如果空终止符在复制过程中以某种方式被覆盖,诸如 strcpy 之类的函数将会中断 - 它必须被视为(数组)对象的一部分。

似乎没有术语 "overlap" 的定义,但意图相当明确:防止出现如下情况:

  char str[] = "foobar";
  strcpy(str+3,str);

其中 strcpy 的一种可能实现是 while(*dst++ = *src++){}。这会中断,因为它永远不会遇到空终止符,我们最终会写出边界。

值得注意的是,您已经向编译器保证,当您将参数传递给需要 restrict 指针的函数时,参数不会重叠。标准中关于未定义重叠的文本只是让它更加清晰。

strcpy示例中,任何对dst指向的左值访问,都不允许修改str指向的内容,否则我们违反了[=15的定义=] (C17 6.7.3) 从而调用未定义的行为。

据我所知,这始终是程序员的责任。据我所知,没有编译器会针对 caller-side.

上的 restrict 违规给出诊断消息