在C标准的附件K(边界检查接口)中,不断弹出一个短语:
....不得在重叠的对象之间进行复制。
例如,考虑strcpy_s( char * restrict s1, rsize_t s1max, char const * restrict s2 )
,其中s1max
指定s1
的最大容量以启用边界检查。
此时“对象” s1
到底是什么,并且不能与“对象” s2
重叠?
那会是...
或
如果是前者,我想知道缺乏一致性,因为我不知道s2的 buffer 的大小,因此必须对“对象”应用不同的定义“。
如果是后者,我想知道它是否不会破坏给出的“承诺”,因为可以想象的是,如果满足以下条件,则源字符串和最终(复制后)目标字符串可能会重叠源字符串比原始字符串长。
这里“对象”的意图/意图是什么?
答案 0 :(得分:3)
我认为这样做的目的是使s1max
开头的s1
字符不能与s2
中的任何字符重叠,包括空终止符。 K.3.7.1.3p5说:
- 在
strcpy_s
指向的s1max字符数组中,s1
所写的终止空字符(如果有)之后的所有元素都采用未指定的值。 [418]
- 这允许实现将字符从
strcpy_s
复制到s2
,同时检查这些字符是否为空。在发现第一个元素应设置为空字符之前,这种方法可能会向s1
的每个元素写入一个字符。
但是,Microsoft表示“如果s1
和source
重叠,则行为未定义”,因此这暗示在这种情况下实际上会发生任何事情。这似乎否定了边界检查接口的作用。
答案 1 :(得分:0)
它在标准中随处可见,不仅在可选的边界检查接口中,而且在诸如strcpy
之类的强制性库函数中都可以找到。边界检查接口功能仅继承了相同的文本。
一个对象的正式定义是:
3.15
对象
执行环境中数据存储的区域,其内容可以表示 值
基于此,字符串必须是包含空终止符的整个数组。因为如果strcpy
之类的函数如果在复制过程中以某种方式覆盖了空终止符时会中断,则必须将其视为(数组)对象的一部分。
“重叠”一词似乎没有定义,但其意图很明确:防止出现以下情况:
char str[] = "foobar";
strcpy(str+3,str);
strcpy
的一种可能实现是while(*dst++ = *src++){}
。它将中断,因为它永远不会碰到空终止符,而我们最终将写越界。
值得注意的是,您已经向编译器保证,将参数传递给需要restrict
指针的函数时,参数不会重叠。标准中有关重叠的文字未定义,只会更加清晰。
在strcpy
示例中,对dst
所指向的内容的任何左值访问,不允许修改str
所指向的内容,否则我们违反了restrict
的定义(C17 6.7.3),从而调用未定义的行为。
据我所知,这始终是程序员的责任。我所知没有编译器会在调用方提供针对restrict
违规的诊断消息。