C11附件K:“重叠的对象”

时间:2019-06-15 09:05:25

标签: c language-lawyer c11 c17

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

  

....不得在重叠的对象之间进行复制。

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

此时“对象” s1到底是什么,并且不能与“对象” s2重叠?

那会是...

  • s1 [0] .. s1 [s1max](到缓冲区的末尾,即内存对象)

  • s1 [0] .. s1 [strnlen(s1,s1max)](到字符串的末尾,即字符串对象)?

如果是前者,我想知道缺乏一致性,因为我不知道s2的 buffer 的大小,因此必须对“对象”应用不同的定义“。

如果是后者,我想知道它是否不会破坏给出的“承诺”,因为可以想象的是,如果满足以下条件,则源字符串和最终(复制后)目标字符串可能会重叠源字符串比原始字符串长。

这里“对象”的意图/意图是什么?

2 个答案:

答案 0 :(得分:3)

我认为这样做的目的是使s1max开头的s1字符不能与s2中的任何字符重叠,包括空终止符。 K.3.7.1.3p5说:

  
      
  1. strcpy_s指向的s1max字符数组中,s1所写的终止空字符(如果有)之后的所有元素都采用未指定的值。 [418]
  2.   

footnote 418表示

  
      
  1. 这允许实现将字符从strcpy_s复制到s2,同时检查这些字符是否为空。在发现第一个元素应设置为空字符之前,这种方法可能会向s1的每个元素写入一个字符。
  2.   

但是,Microsoft表示“如果s1source重叠,则行为未定义”,因此这暗示在这种情况下实际上会发生任何事情。这似乎否定了边界检查接口的作用。

答案 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违规的诊断消息。