C11 Приложение K: "объекты, которые перекрываются"

Есть фраза, которая продолжает появляться в Приложении K стандарта C (интерфейсы проверки границ):

.... копирование не должно происходить между объектами, которые перекрываются.

Учитывая, например, 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 и должен был бы применить другое определение "объекта".

Если это последнее, мне интересно, не нарушает ли это "обещание", которое дано, поскольку исходная строка и конечная (конечная) строка назначения могут перекрываться, если исходная строка длиннее исходной.

Каково намерение / предполагаемое определение "объекта" здесь?

2 ответа

Решение

Я считаю, что намерение таково, что s1max символы начиная с s1 не должен накладываться ни на один из символов в s2 в том числе нулевой терминатор. K.3.7.1.3p5 говорит, что:

  1. Все элементы, следующие за завершающим нулевым символом (если есть), записаны strcpy_s в массиве символов s1max, на которые указывает s1 принимать неопределенные значения, когда strcpy_s возвращается. [418]

со сноской 418 о том, что

  1. Это позволяет реализации копировать символы из s2 в s1 одновременно проверяя, являются ли какие-либо из этих символов нулевыми. Такой подход может написать символ для каждого элемента s1 перед обнаружением, что первый элемент должен быть установлен в нулевой символ.

Тем не менее, Microsoft говорит, что "если source а также dest перекрытие, поведение не определено ", так что это намекает на то, что на самом деле все может произойти в этом случае. Это, кажется, сводит на нет полезность интерфейса проверки границ.

Это встречается повсеместно в стандарте, не только в дополнительном интерфейсе проверки границ, но и в обязательных библиотечных функциях, таких как 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 нарушения на стороне звонящего.

Другие вопросы по тегам