Как упоминалось в комментарии anol, ни один из абстрактных доменов, доступных в Eva, не способен отслеживать отношение между n
и длиной блока памяти, возвращаемого malloc
. Следовательно, для всех практических целей избавиться от предупреждения в таких обстоятельствах для реального анализа будет невозможно. Вообще говоря, важно подготовить начальное состояние, которое приводит к точным границам для буфера, которым манипулируют на протяжении всей программы (в то время как содержимое может оставаться гораздо более абстрактным).
Тем не менее, для небольших экспериментов, и если вы не возражаете тратить (довольно много) процессорных циклов, можно немного схитрить, в основном инструктируя Еву рассматривать каждую возможную длину отдельно . Это делается с помощью нескольких аннотаций и параметров командной строки (только для Frama-C 19.0 Potassium).
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include "__fc_builtin.h"
extern char *foo(char *, char *);
int main() {
int n = Frama_C_interval(0, 255);
//@ split n;
uint8_t *test = malloc(n);
if (test != NULL) {
//@ loop unroll n;
for (int i=0; i<n; i++) {
Frama_C_show_each_test(n, i, test);
test[i]=Frama_C_interval(0, 255);
}
char* beg, *end;
beg = &test[0];
end = &test[0] + n;
foo(beg, end);
}
}
Запустите Frama-C с помощью
frama-c -eva file.c \
-eva-precision 7 \
-eva-split-limit 256 \
-eva-builtin malloc:Frama_C_malloc_fresh
В коде //@ split n
указывает, что Ева должна рассмотреть отдельно каждое возможное значение n
на данном этапе. Это соответствует -eva-split-limit 256
(по умолчанию Eva не будет разделяться, если выражение может иметь более 100 значений). //@ loop unroll n
попросите развернуть цикл n
раз вместо объединения результатов для всех шагов.
Для других параметров командной строки -eva-precision 7
устанавливает различные параметры, контролирующие точность Eva, в разумные значения. Она изменяется от 0
(менее точная, чем по умолчанию) до 11
(максимальная точность — не пытайтесь использовать ее более чем на дюжине строк). -eva-builtin malloc:Frama_C_malloc_fresh
инструктирует Eva создавать новый базовый адрес для любого обращения к malloc
, которое она встречает. В противном случае вы получите единую базу для всех длин, что в первую очередь сведет на нет цель разделения на n
.
person
Virgile
schedule
24.07.2019
n
, используемым в вызовеmalloc
, и циклом. Без возможности сохранить этот инвариант Ева не может сделать вывод, что размер, используемый для выделения динамического массива, совпадает с размером цикла. В настоящее время в Eva есть несколько слабых реляционных доменов, но я боюсь, что они не в состоянии поддерживать эту информацию. - person anol   schedule 23.07.2019