Search code examples
clanguage-lawyerc11c17

C11 Annex K: "objects that overlap"


There is a phrase that keeps popping up in Annex K of the C standard (bounds-checking interfaces):

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

Considering, for example, strcpy_s( char * restrict s1, rsize_t s1max, char const * restrict s2 ), in which s1max specifies the maximum capacity of s1 to enable the bounds checking.

What exactly would be "the object" s1 at this point, which must not overlap with "the object" s2?

Would that be...

  • s1[0]..s1[s1max] (to the end of the buffer, i.e. the memory object),

or

  • s1[0]..s1[strnlen( s1, s1max )] (to the end of the string, i.e. the string object)?

If it is the former, I wonder about the lack of consistency, as I do not know the size of the buffer that is s2, and would have to apply a different definition of "the object".

If it is the latter, I wonder if it doesn't break "the promise" that is given, as conceivably the source string and the eventual (post-copy) destination string could overlap if the source string is longer than the original one.

What is the intention / the intended definition of "object" here?


Solution

  • I believe the intent is such that the s1max characters starting from s1 must not overlap any of the characters in s2 including the null terminator. K.3.7.1.3p5 says that:

    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]

    with the footnote 418 saying that

    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.

    However, Microsoft's says that "if source and dest overlap, the behavior is undefined", so this would hint that in fact anything could happen in that case. This seems to negate the usefulness of the bounds-checking interface.