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
重叠?
会不会是...
- s1[0]..s1[s1max](到缓冲区末尾,即内存对象),
或
- s1[0]..s1[strnlen( s1, s1max )] (到字符串末尾,即字符串对象)?
如果是前者,我想知道缺乏一致性,因为我不知道 buffer 即 s2 的大小,并且必须应用不同的"the object".
的定义
如果是后者,我想知道它是否不会破坏给定的 "the promise",因为可以想象源字符串和 eventual (post-copy) 如果源字符串比原始字符串长,目标字符串可能重叠。
此处 "object" 的意图/预期定义是什么?
我认为其意图是从 s1
开始的 s1max
个字符不得与 s2
中的任何字符重叠,包括空终止符。 K.3.7.1.3p5 表示:
- 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 说
- 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
违规给出诊断消息
在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
重叠?
会不会是...
- s1[0]..s1[s1max](到缓冲区末尾,即内存对象),
或
- s1[0]..s1[strnlen( s1, s1max )] (到字符串末尾,即字符串对象)?
如果是前者,我想知道缺乏一致性,因为我不知道 buffer 即 s2 的大小,并且必须应用不同的"the object".
的定义如果是后者,我想知道它是否不会破坏给定的 "the promise",因为可以想象源字符串和 eventual (post-copy) 如果源字符串比原始字符串长,目标字符串可能重叠。
此处 "object" 的意图/预期定义是什么?
我认为其意图是从 s1
开始的 s1max
个字符不得与 s2
中的任何字符重叠,包括空终止符。 K.3.7.1.3p5 表示:
- All elements following the terminating null character (if any) written by
strcpy_s
in the array of s1max characters pointed to bys1
take unspecified values whenstrcpy_s
returns. [418]
用 footnote 418 说
- This allows an implementation to copy characters from
s2
tos1
while simultaneously checking if any of those characters are null. Such an approach might write a character to every element ofs1
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
违规给出诊断消息