Доказательства для кода, который полагается на переполнение целых чисел без знака?

Как я должен подходить к доказательству правильности кода, как показано ниже, который, чтобы избежать некоторой неэффективности, опирается на модульную арифметику?

#include <stdint.h>

uint32_t my_add(uint32_t a, uint32_t b) {
    uint32_t r = a + b;
    if (r < a)
        return UINT32_MAX;
    return r;
}

Я экспериментировал с моделью int в WP, но, если я правильно понял, эта модель настраивает семантику логических целых чисел в PO, а не формальные модели кода на C. Например, плагины WP и RTE по-прежнему требуют и вводят PO подтверждения переполнения для неподписанного добавления, указанного выше, при использовании модели int.

В таких случаях можно ли добавить аннотации, определяющие логическую модель для оператора или базового блока, чтобы я мог сказать Frama-C, как конкретный компилятор на самом деле интерпретирует оператор? Если это так, я мог бы использовать другие методы проверки для таких вещей, как поведение, определяемое, но часто вызывающее дефекты, такое как обход без знака, определяемое компилятором поведение, нестандартное поведение (встроенная сборка?) И т. Д., А затем доказать правильность окружающий код. Я представляю нечто похожее (но более мощное, чем) "исправление утверждения", используемое для информирования некоторых статических анализаторов о том, что определенные свойства сохраняются, когда они не могут получить свойства для себя.

Я работаю с Frama-C Fluorine-20130601, для справки, с alt-ergo 95.1.

2 ответа

Решение

Я работаю с Frama-C Fluorine-20130601

Рад видеть, что вы нашли способ использовать последнюю версию.

Вот некоторые случайные фрагменты информации, которые, хотя и не полностью отвечают на ваш вопрос, но не вписываются в комментарий Stackru:

Джесси имеет:

#pragma JessieIntegerModel(modulo)

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

Во фторе RTE не предупреждает о a + b по умолчанию:

$ frama-c -rte t.c -then -print
[kernel] preprocessing with "gcc -C -E -I.  t.c"
[rte] annotating function my_add
/* Generated by Frama-C */
typedef unsigned int uint32_t;
uint32_t my_add(uint32_t a, uint32_t b)
{
  uint32_t __retres;
  uint32_t r;
  r = a + b;
  if (r < a) {
    __retres = 4294967295U;
    goto return_label;
  }
  __retres = r;
  return_label: return __retres;
}

RTE может быть сделан, чтобы предупредить о неподписанном дополнении с опцией -warn-unsigned-overflow:

$ frama-c -warn-unsigned-overflow -rte t.c -then -print
[kernel] preprocessing with "gcc -C -E -I.  t.c"
[rte] annotating function my_add
/* Generated by Frama-C */
typedef unsigned int uint32_t;
uint32_t my_add(uint32_t a, uint32_t b)
{
  uint32_t __retres;
  uint32_t r;
  /*@ assert rte: unsigned_overflow: 0 ≤ a+b; */
  /*@ assert rte: unsigned_overflow: a+b ≤ 4294967295; */
  r = a + b;
  …

Но это прямо противоположно тому, что вы хотите, поэтому я не понимаю, почему вы это сделали.

Вы не предоставили точную командную строку, которую использовали. Я думаю это frama-c -wp -wp-rte file.c -pp-annot, В этом случае, действительно, генерируются все утверждения, которые RTE может излучать. Однако вы можете лучше контролировать это, дав команду frama-c сначала генерировать только те категории RTE, которые вас интересуют (будьте осторожны, так как они контролируются двумя типами опций: frama-c -rte-help и -warn-{signed,unsigned}-{overflow,downcast} определяется в ядре), а затем запустить wp на результат. Это сделано frama-c -rte -pp-annot file.c -then -wp По умолчанию rte не считает переполнение без знака ошибкой, поэтому с помощью приведенной выше командной строки я могу доказать, что ваша функция соответствует следующей спецификации:

/*@
  behavior no_overflow:
    assumes a + b <= UINT32_MAX;
    ensures \result == a+b;
  behavior saturate:
    assumes a+b > UINT32_MAX;
    ensures \result == UINT32_MAX;
 */
 uint32_t my_add(uint32_t a,uint32_t b);
Другие вопросы по тегам