Поведение undefined превышает лимит перевода и есть ли инструменты проверки, чтобы найти его?

ОРИГИНАЛЬНЫЙ ВОПРОС:

Я ищу стандарт C90 для вещей, о которых нужно знать, при написании высокодоходного кода, не имея большого доверия к доброй воле поставщика компилятора и предполагая, что мое программное обеспечение иногда может кого-то убивать, если я что-то делаю неправильно. Скажем, я немного параноик.

В настоящий момент я думаю о "лимитах перевода" (5.2.4.1 ANSI/ISO 9899: 1990). Как указано в стандарте и в: "ли ansi C ограничивает количество внешних переменных в программе?", это минимальные требования для стандартного соответствия реализация. Теперь, с другой стороны, это означает, что любая реализация не должна делать больше - и если я хочу быть уверенным, что мой код работает для любой реализации confrom, эти лимиты представляют собой абсолютные ограничения для меня.

До сих пор так раздражает.

Таким образом, поставщик компилятора выбирает лимиты, равные или превышающие минимальные требуемые пределы трансакций.

Что происходит сейчас, если вы превысите эти ограничения, связанные с реализацией, для конкретной реализации? В моей копии ANSI/IO 9899: 1990 (C90) я ничего не нашел, поэтому я думаю, что это Undefined Поведение "3. вида" (бездействия). С другой стороны, это было бы не в первый раз, когда я неправильно понял стандарт или не нашел правильный проход.

Итак, вот мои вопросы:

  • Превышает пределы перевода определенного поведения реализации Undefined в C90?

  • Поддерживается ли поведение C90 для исправленных версий до C95/C96 и для новых итераций C99 и C11?

  • Кто-нибудь видел инструмент проверки, который проверяет минимальные или (инструменты) пользовательские ограничения?

АСПЕКТЫ ЗА ОРИГИНАЛЬНЫМ ВОПРОСОМ:

Интересные аспекты в ответах и ​​комментариях:

1) Как Майкл Барр указал в прямом комментарии к вопросу, согласно C -Стандарт (я только проверил C90 без исправлений, а проект C99, Майкл ссылался на здесь), реализация c в C должна только принимать ОДНУ программу, который содержит все пределы одновременно, что в строжайшей интерпретации аннулирует любые минимальные гарантии.

2) В качестве rubenvb и Keith Thompson отметили, что реализация какого-то качества должна обеспечивать диагностику для случая, что их реализация определены пределы превышены, особенно если они не соответствуют минимальным требованиям (rubenvb связал пример для MSVC в comment).

3) Поскольку превышение пределов компилятора может быть Undefined, но, несомненно, приведет к некоторой ошибке, значения "переменных", к которым применяются ограничения перевода для определенной части моего кода, представляют собой предпосылки для повторного использования.

Мои личные стратегии борьбы с ними

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

2) Итак, я буду исследовать документацию компилятора и способность страдать от поддержки компилятора для получения подтверждения, что:  - что для каждого предела перевода, если превышено, диагностика будет поднята, и  - потому что это поведение Undefined, если каждый экземпляр превышения предела перевода приведет к диагностике - или еще одна ошибка уже предотвратила компиляцию.

3) Таким образом, я постараюсь получить инструмент (или разработать сам, если я действительно должен), который измеряет эти значения и предоставляет их в качестве предварительного условия для повторного использования кода для моей программы. Как отметил Keith Thompson в этом ответе , некоторые из значений могут потребовать более глубоких знаний о том, как осуществляется реализация... реализован. Я не совсем уверен, что может помочь в таких случаях помимо действий в 2.), но, насколько я вижу, мне нужно проверить - но мне нужно только проверить, есть ли UB (без диагностики), и если это случай, успешный тест не может гарантировать правильность в общем случае.

ОТВЕТИЛ:

Да, это поведение Undefined путем пропуска.

Кейт Томпсон показал в своем (принятом) anwser терминологию и ссылку на стандартные документы C, что это поведение Undefined.

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

Ответ 1

Я считаю, что поведение undefined.

Стандарт требует диагностики для любой единицы перевода, которая нарушает правило ограничения или синтаксиса (N1570 5.1.1.3), и может не успешно перевести блок перевода, содержащий директиву #error, которая выживает на этапе предварительной обработки (N1570 4, пункт 4). (N1570 является черновиком стандарта C11, но это то же самое на C90, C99 и C11, за исключением того, что #error был добавлен C99.)

Все ограничения и правила синтаксиса явно указаны в стандарте. Превышение предела, определенного реализацией, не нарушает ни ограничение, ни синтаксическое правило. Я думаю, что достаточно очевидно, что для реализации успешной обработки другой корректной программы, которая превышает лимит перевода, не требуется реализация, но стандарт ничего не говорит о том, как она должна реагировать на такое нарушение. Следовательно, поведение undefined путем пропуска.

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

Чтобы ответить на третью часть вашего вопроса, нет, я не слышал о статическом инструменте проверки, который проверяет программы на нарушение минимальных пределов перевода. Такой инструмент может быть весьма полезен и, вероятно, не будет слишком сложно писать, если у вас есть C-парсер. Для ограничения размера объекта (32767 байт в C90, 65535 байт на C99 и C11), он должен знать, как компилятор определяет размеры объекта; int arr[30000]; может или не может превышать 65535 байт, в зависимости от sizeof (int). Я не был бы слишком удивлен, если бы кто-то уже реализовал такой инструмент, и я просто не слышал об этом.

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

Стандарт представляет границы перевода довольно странным образом. Я думаю, в частности, оговорке, которая гласит:

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

(раздел 5.2.4.1 на C90, C99 и C11). Таким образом, извращенная реализация может принимать ровно одну программу и отвергать все остальные.

Я считаю, что определение разумных пределов, которые должны выполняться всеми реализациями, было бы непрактичным. В стандарте можно сказать, что все реализации должны всегда принимать объекты не менее 32767 байт, но как насчет программы, которая определяет миллион таких объектов? Пределы взаимодействуют друг с другом чрезвычайно сложными способами, а характер взаимодействия зависит от внутренней структуры каждого компилятора. (Если вы считаете, что вы можете определить требования к лимитам перевода лучше, чем это делает стандарт C, я рекомендую вам попробовать.)

Вместо этого стандарт утверждает требования таким образом, что самый простой способ реализовать полезный компилятор, который подчиняется букве стандарта, - это реализовать полезный компилятор, который подчиняется духу стандарта, не налагая никаких необоснованных ограничений, Бесполезный компилятор, который соответствует букве стандарта, возможен, но не имеет значения; Я не знаю, что кто-либо когда-либо реализовал такую ​​вещь, и я уверен, что никто не попытается ее использовать.

Ответ 2

Это не поведение undefined, это определенное поведение реализации. Это означает, что все зависит от компилятора.

Да, минимальные рекомендации по внедрению остаются теми же или расширены для более новых версий стандартов.

Возможно, вы могли бы использовать Clang для этого, но вам нужно будет написать инструмент самостоятельно, используя API Clang, я не знаю о существовавшей ранее реализации.


В любом случае: ограничения не устанавливаются стандартом: "Они все равно [как] рекомендации в любом случае" (на самом деле это не что иное, как рекомендации). Вам нужно будет проверить компиляторы, которые вы используете для создания кода, чтобы узнать, не нажимаете ли вы какие-либо ограничения, никоим образом не обходите это, только размахивая документом стандартов в чьем-то носу. И поскольку реализация MSVC особенно прискорбно, я бы даже осмелился сказать, что если она скомпилирует ваш код (если в коде не будет никаких незаконных конструкций), вы довольно безопасны.

Ответ 3

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

Было бы полезно, если бы Стандарт предоставил средство, с помощью которого программа могла бы обеспечить некоторую меру предсказуемого поведения при работе с любым объемом доступной памяти, но в настоящее время она этого не делает. На многих платформах будет некоторое количество доступной памяти, которая будет достаточно большой, чтобы загрузчик ОС не отклонил исполняемый файл, но тем не менее будет достаточно мал, чтобы приложение сразу переполнило стек при запуске. Авторы стандарта C не хотели заявлять, что C нельзя использовать с такими платформами, но они также не могут ничего сказать о том, какие платформы будут делать при попытке запустить код с этим критическим объемом памяти.