Current Implementation
Before describing the main problem, I will describe the current implementation.
The function havoc_oracle in flowInference.ml "havocs" any integer value if some reference points to it and the ownership of that reference is 0. ("Havoc" is to set True to an integer value refinement that some reference is pointing to)
Currently, even though the ownership of an array a itself is 0, the integer value representing the length of a, which path is denoted as a!len, is NOT necessarily havoced.
If there is a reference r that points to an array a and the ownership of r is 0, then the integer value representing the length of a, which path is denotated r->*!len, is havoced. The same is true if a reference points to a tuple and the tuple contains an array, and in similar cases.
Example
The following program is VERIFIED.
// VERIFIED
{
let n = (_: ~ > 0) in
let a = mkarray n in
let b = a in { // The ownership of `a` becomes 0.
b[0] <- 1;
// Even though `a` has ownership 0,
// the following assertion is VERIFIED.
assert(a.length = n)
}
}
However, the following one is UNVERIFIED.
// UNVERIFIED (unsafe)
{
let n = (_: ~ > 0) in
let r1 = mkref mkarray n in
let r2 = r1 in { // the ownership of `r1` becomes 0
// The following assertion is NOT verified.
// `r1->*!len` is havoced because the ownership of `r1` itself is 0,
// not because the ownership of the array which `r1` points to is 0.
// (In fact, the latter ownership is also 0
// by ownership well-formedness, though.)
assert(*r1.length = n);
r2 := mkarray _;
}
}
Problem
Next, I will explain the main problem with an example.
The following program raises an error.
{
let n = (_: ~ > 0) in
let a = mkarray n in
let r1 = mkref a in {
alias(*r1 = a);
}
}
The error message is:
Fatal error: exception Not_found
The error raises in the function havoc_oracle in flowInference.ml.
Why
- For each program point, the module
OwnershipInference records the ownerships that may change (and be havoced) by gen: GenMap.t.
gen: GenMap.t: Partial Map from (program point, path) to ownerships
- However, unchanged ownerships are not recorded.
havoc_oracle determines whether to havoc integer values using the ownership information recorded in gen.
- In
alias(*r1 = a), ownerships of a itself and the content of r1 are redistributed, but not that of r1 itself.
- The ownership of
r1 itself are NOT recorded at the program point of alias in gen.
havoc_oracle tries to decide whether to havoc r1->*!len at the program point of alias(, and a->!len similarly).
- As explained above, the ownership of
r1 itself determines it, not r1->*.
- However, information of
r1 itself is not recorded at this point (because it does not change in alias(*r1 = a)).
- Then,
GenMap.find _ gen raises Not_found when it searches for information of r1.
(* flowInference.ml *)
let rec havoc_oracle ctxt ml p =
...
let from_path p_ =
let o = OI.GenMap.find (ml, p_) ctxt.o_hints.OI.gen in (* The error occurs HERE *)
How to fix
There are several options to solve this problem:
- Use the results of ownership inference
- After ownership inference, we know the ownership of
r1 in alias(*r1 = a).
- This method may require many modifications.
- Havoc the integer value representing the length of an array
a if the ownership of a itself is 0.
- This is sound.
- However, fewer programs can be verified:
- For example, the first example will not be verified.
- This method requires the following modifications:
let rec havoc_oracle ctxt ml p =
...
match P.tail p with
| Some `Deref
| Some `Ind
- | Some `Elem -> from_path @@ P.parent p
+ | Some `Elem
+ | Some `Len -> from_path @@ P.parent p
...
let%lq split_oracle sl ctxt =
...
match (P.tail p1),(P.tail p2) with
...
| Some a,Some b ->
let () = assert (a = b) in
- if a = `Deref || a = `Ind || a = `Elem then
+ if a = `Deref || a = `Ind || a = `Elem || a = `Len then
from_path @@ P.parent p1
Current Implementation
Before describing the main problem, I will describe the current implementation.
The function
havoc_oracleinflowInference.ml"havocs" any integer value if some reference points to it and the ownership of that reference is 0. ("Havoc" is to setTrueto an integer value refinement that some reference is pointing to)Currently, even though the ownership of an array
aitself is 0, the integer value representing the length ofa, which path is denoted asa!len, is NOT necessarily havoced.If there is a reference
rthat points to an arrayaand the ownership ofris 0, then the integer value representing the length ofa, which path is denotatedr->*!len, is havoced. The same is true if a reference points to a tuple and the tuple contains an array, and in similar cases.Example
The following program is VERIFIED.
However, the following one is UNVERIFIED.
Problem
Next, I will explain the main problem with an example.
The following program raises an error.
The error message is:
The error raises in the function
havoc_oracleinflowInference.ml.Why
OwnershipInferencerecords the ownerships that may change (and be havoced) bygen: GenMap.t.gen: GenMap.t: Partial Map from(program point, path)to ownershipshavoc_oracledetermines whether to havoc integer values using the ownership information recorded ingen.alias(*r1 = a), ownerships ofaitself and the content ofr1are redistributed, but not that ofr1itself.r1itself are NOT recorded at the program point ofaliasingen.havoc_oracletries to decide whether to havocr1->*!lenat the program point ofalias(, anda->!lensimilarly).r1itself determines it, notr1->*.r1itself is not recorded at this point (because it does not change inalias(*r1 = a)).GenMap.find _ genraisesNot_foundwhen it searches for information ofr1.How to fix
There are several options to solve this problem:
r1inalias(*r1 = a).aif the ownership ofaitself is 0.let rec havoc_oracle ctxt ml p = ... match P.tail p with | Some `Deref | Some `Ind - | Some `Elem -> from_path @@ P.parent p + | Some `Elem + | Some `Len -> from_path @@ P.parent p ... let%lq split_oracle sl ctxt = ... match (P.tail p1),(P.tail p2) with ... | Some a,Some b -> let () = assert (a = b) in - if a = `Deref || a = `Ind || a = `Elem then + if a = `Deref || a = `Ind || a = `Elem || a = `Len then from_path @@ P.parent p1