Я работаю над пятым бета-модулем основ программного обеспечения, который охватывает проверяемые C. Я нахожусь на последней части, которая связана с операциями на карте ha sh (что требует операций со связанным списком).
https://www.cs.princeton.edu/~appel/vc/vc-0.9.5/Verif_hash.html
Я немного застрял на body_incr_list
.
Проверяемый код:
void incr_list (struct cell **r0, char *s) {
struct cell *p, **r;
for(r=r0; ; r=&p->next) {
p = *r;
if (!p) { *r = new_cell(s,1,NULL); return; }
if (strcmp(p->key, s)==0) {p->count++; return;}
}
}
Это делает пару новых вещей ... указатель указателей и тот факт, что p равно нулю, идущему в l oop, но тогда гарантированно будет иметь значение, если оно зацикливается. Модуль SPE c дает следующее:
Definition incr_list_spec : ident × funspec :=
DECLARE _incr_list
WITH r0: val, al: list (list byte × Z), s: val,
sigma : list byte, gv: globals
PRE [ _r0 OF tptr (tptr tcell), _s OF tptr tschar ]
PROP (list_get sigma al < Int.max_unsigned)
LOCAL (temp _r0 r0; temp _s s; gvars gv)
SEP (listboxrep al r0; cstring Ews sigma s; mem_mgr gv)
POST [ tvoid ]
PROP ( ) LOCAL ()
SEP (listboxrep (list_incr sigma al) r0;
cstring Ews sigma s; mem_mgr gv).
Все упражнение зависит от правильного инварианта l oop. Это была моя попытка
forward_loop (EX al':list (list byte * Z), EX r0': val,
PROP ()
LOCAL (temp _r r0'; temp _r0 r0; temp _s s; gvars gv)
SEP (
listboxrep al' r0';
cstring Ews sigma s;
mem_mgr gv;
listboxrep al' r0' -* (ALL sigma:list byte, listrep (list_incr sigma []) nullval -* listboxrep (list_incr sigma al) r0)
)).
С этим я могу добиться определенного c прогресса, но я застрял на обработке: прямо сейчас в предложении SEP у меня есть listboxrep al' r0'
, но для того, чтобы пройти строку
p = *r;
, мне нужно развернуть его в data_at Ews (tptr tcell) p r0' * listrep al' p
. Опять же, это не большая проблема, но в случае, когда p имеет значение NULL и создает новую ячейку (*r = new_cell(s,1,NULL); return;
), я получаю доказательную цель, которую я не знаю, можно ли ее решить.
потому что data_at Ews (tptr tcell) p r0'
преобразуется в data_at Ews (tptr tcell) vret r0'
, но у нас все еще есть listrep al' p
, а не listrep al' vret
. Хотя в этом случае al ', вероятно, будет [], что означает, что у нас есть listrep [] p
, хотя я не совсем уверен, что с этим можно сделать. Если я выполню это до конца, я приду к следующему выводу:
(list_cell sigma 1 (Vint (Int.repr 0)) vret *
data_at Ews (tptr tcell) vret r0' *
((EX p : val, data_at Ews (tptr tcell) p r0' * (!! (p = nullval) && emp)) -*
(ALL sigma0 : list byte,
(EX y : val, list_cell sigma0 1 y nullval * (!! (y = nullval) && emp)) -*
listboxrep (list_incr sigma0 al) r0)))%logic
|-- listboxrep (list_incr sigma al) r0
Это заставляет меня думать, что мой инвариант неверен ... например, если я пытаюсь установить p в
EX p : val, data_at Ews (tptr tcell) p r0' * (!! (p = nullval) && emp)
Тогда, конечно, это должно быть нулевое значение. Но значение, которое у нас есть, это data_at Ews (tptr tcell) vret r0'
...
Так что я не знаю. Я почти уверен, что мне нужно уточнить свой инвариант, но не знаю, как это сделать! Буду признателен за любые указатели.