Frama-c, по-видимому, позволяет выполнять циклические вычисления целых чисел без знака, в то время как предполагает, что целочисленные вычисления со знаком не будут переполняться, и это необходимо для последующего подтверждения с помощью флага -wp-rte
. (Я лично использую Frama-C 20.0 Calcium.) Я хотел бы каким-то образом создать гарантию / требование, что некоторые вычисления / свойства не переполняются. Упрощенная версия проблемы, которую я пытаюсь решить:
#include <stdint.h>
struct example_struct {
unsigned int a;
unsigned int b;
};
/*@
predicate valid_example_struct_one{L}(struct example_struct ex_struct) =
ex_struct.a * ex_struct.b <= UINT_MAX;
*/
Очевидно, что приведенный выше предикат всегда верен из-за циклического перехода к беззнаковой целочисленной математике. Я хотел бы иметь возможность привести a и b к целочисленному типу, который не будет переполняться, или как-то указать, что он не может переполняться, используя другой метод. Похоже, что следующее работает:
/*@
predicate valid_example_struct_two{L}(struct example_struct ex_struct) =
1 <= UINT_MAX / ex_struct.a / ex_struct.b;
*/
Однако я не уверен, что приведенное выше действительно эквивалентно, поскольку оно изо всех сил пытается доказать (обратите внимание на поменяемые местами a и b):
1 <= UINT_MAX / ex_struct.b / ex_struct.a;
И я хотел бы включить "тип" для метода Байеса, но когда я отбрасываю это, чтобы получить синтаксис в моем списке, я все равно получаю сообщение об ошибке:
2 ответа
Ваш предикат
/*@
predicate valid_example_struct_one{L}(struct example_struct ex_struct) =
ex_struct.a * ex_struct.b <= UINT_MAX;
*/
Не является «всегда истинным из-за циклического перехода к беззнаковой целочисленной математике». Как упоминалось в руководстве по ACSL, все арифметические операции в ACSL выполняются в типе integer
(или real
), то есть без циклического перехода. Таким образом, это канонический способ выразить отсутствие арифметического переполнения и тот, который используется RTE и Eva при отправке связанных сигналов тревоги.
Тем не менее, RTE вполне может выдавать утверждение о переполнении без знака, но это должно быть активировано явно с помощью параметра ядра -warn-unsigned-overflow
(см. руководство пользователя Frama-C , раздел 6.3. Причина, по которой этот параметр не активирован по умолчанию, заключается в том, что, в отличие, например, от подписанных переполнений, неподписанные переполнения имеют идеально определенная семантика в C.
Хорошо, я ненавижу задавать вопросы только для того, чтобы сам на них отвечать, но я потратил немного времени на изучение документации Frama-C после того, как нашел некоторые другие вопросы, которые были интересны в Stackoverflow. Я обратил внимание на особые типы integer
, real
и boolean
. В этом случае мою проблему можно решить, просто приведя unsigned int
к integer
:
/* Desired predicate: */
/*@
predicate valid_example_struct_one{L}(struct example_struct ex_struct) =
(integer) ex_struct.a * (integer) ex_struct.b <= (integer) UINT_MAX;
*/
/* Trivially always true predicate: */
/*@
predicate valid_example_struct_two{L}(struct example_struct ex_struct) =
ex_struct.a * ex_struct.b <= UINT_MAX;
*/
Похожие вопросы
Новые вопросы
frama-c
Frama-C - это набор инструментов с открытым исходным кодом, предназначенный для анализа исходного кода на языке C.