Как рассуждать о доступе к массиву в VST?
У меня проблема с проверкой тривиальной функции доступа к массиву (файл arr.c):
int get(int* arr, int key)
{
return arr[key];
}
который переводится clightgen arr.c
к (файл arr.v):
...
Definition f_get := {|
fn_return := tint;
fn_callconv := cc_default;
fn_params := ((_arr, (tptr tint)) :: (_key, tint) :: nil);
fn_vars := nil;
fn_temps := nil;
fn_body :=
(Sreturn (Some (Ederef
(Ebinop Oadd (Etempvar _arr (tptr tint))
(Etempvar _key tint) (tptr tint)) tint)))
|}.
...
Вот начало доказательства (verify_arr.v):
Require Import floyd.proofauto.
Require Import arr.
Local Open Scope logic.
Local Open Scope Z.
Definition get_spec :=
DECLARE _get
WITH sh : share, k : Z, arr : Z->val, vk : val, varr : val
PRE [_key OF tint, _arr OF (tptr tint)]
PROP (0 <= k < 100; forall i, 0 <= i < 100 -> is_int (arr i))
LOCAL (`(eq vk) (eval_id _key);
`(eq varr) (eval_id _arr);
`isptr (eval_id _arr))
SEP (`(array_at tint sh arr
0 100) (eval_id _arr))
POST [tint] `(array_at tint sh arr
0 100 varr) &&
local(`(eq (arr k)) retval).
Definition Vprog : varspecs := nil.
Definition Gprog : funspecs := get_spec :: nil.
Lemma body_get: semax_body Vprog Gprog f_get get_spec.
Proof.
start_function.
name karg _key.
name arrarg _arr.
forward.
После выполнения forward
(последняя строка в verify_arr.v) У меня есть следующая цель:
array_at tint sh arr 0 100 arrarg
|-- !!(False /\ False /\ arr k = Vundef) &&
array_at tint sh arr 0 100 arrarg
Что подразумевает False
так что не могу доказать это. Однако, c-реализация тривиальна, и доказательство только началось.
Теперь к вопросу:
Что не так со спецификацией, почему она добралась до недоказуемой цели?
VST версия:
Definition svn_rev := "6834P".
Definition release := "1.5".
Definition date := "2014-10-02".
Версия CompCert: 2.4
Coq версия:
The Coq Proof Assistant, version 8.4pl3 (January 2014)
compiled on Jan 19 2014 23:14:16 with OCaml 4.01.0
1 ответ
В "стандартном" Verifiable-C ссылки на память не могут появляться в выражениях, кроме как на верхнем уровне в выражении загрузки:
x = a[e]; or x = *(e.field); (same as x = e->field;)
где е - любое выражение, которое не имеет доступа к памяти.
Или оператор магазина: [e1] = e2; или e1->field = e2; где e1 и e2 не имеют доступа к памяти.
Ссылка на память не должна встречаться в операторе возврата. Вам нужно будет учитывать вашу программу следующим образом:
int x;
x = arr[key];
return x;
и затем продолжайте с доказательством.
Мы рассматриваем расширения, то есть "нестандартную" Verifiable C, в которой ссылки на память могут быть вложены в выражения в других контекстах; но совсем не ясно, что это хороший способ рассуждать о программах. Это будет стоить эксперимента.
Причина, по которой вы получаете "False" в своем предварительном условии, заключается в том, что выражение arr[key] не проверяет тип как допустимое выражение, поскольку оно содержит ссылку на память. Мы должны работать над улучшением обратной связи с сообщениями об ошибках в таких ситуациях.