C11 Приложение K: "объекты, которые перекрываются" - PullRequest
4 голосов
/ 15 июня 2019

В Приложении 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 ]

3 голосов
/ 15 июня 2019

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

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

с сноской 418 , говорящей, что

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

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

0 голосов
/ 17 июня 2019

Это встречается повсюду в стандарте, не только в дополнительном интерфейсе проверки границ, но и в обязательных библиотечных функциях, таких как strcpy. Интерфейсные функции проверки границ просто унаследовали один и тот же текст.

Формальное определение объекта:

3,15
объект
область хранения данных в среде исполнения, содержимое которой может представлять Значения

Исходя из этого, строка должна быть целым массивом, включая нулевой терминатор. Поскольку такая функция, как strcpy, прервется, если нулевой терминатор каким-либо образом будет перезаписан во время копирования, ее следует рассматривать как часть объекта (массива).

Кажется, что нет определения термина "перекрытие", но цель довольно ясна: предотвратить ситуации, подобные этой:

  char str[] = "foobar";
  strcpy(str+3,str);

, где одна из возможных реализаций strcpy будет while(*dst++ = *src++){}. Который сломался бы, поскольку он никогда не достигнет нулевого терминатора, и мы закончили бы писать вне границ.

Примечательно, что вы уже обещали компилятору, что параметры не перекрываются, когда вы передаете их функции, ожидающей указателей restrict. Текст в стандарте, касающийся того, что перекрытия не определены, еще яснее.

В примере strcpy любой lvalue-доступ к тому, на что указывает dst, не может изменять то, на что указывает str, или мы нарушаем определение restrict (C17 6.7.3) и тем самым вызвать неопределенное поведение.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...