Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect semantics for empty slice #53

Open
sanjit-bhat opened this issue Aug 22, 2023 · 4 comments
Open

Incorrect semantics for empty slice #53

sanjit-bhat opened this issue Aug 22, 2023 · 4 comments
Assignees

Comments

@sanjit-bhat
Copy link
Member

In Go, empty slices are different from nil slices. See this example.

However, GooseLang models empty slices as nil values.

Definition NewSlice (t: ty): val :=
λ: "sz",
if: "sz" = #0 then slice.nil
else let: "cap" := make_cap "sz" in
let: "p" := AllocN "cap" (zero_val t) in
(Var "p", Var "sz", Var "cap").

@sanjit-bhat
Copy link
Member Author

Concretely, in Perennial, I think we should be able to (faultily) prove this, whereas in Golang, this assertion fails.

func test() {
	slEmpt := make([]byte, 0)
	machine.Assert((slEmpt == nil) == true)
}

I'm not sure how to complete the proof. I got to WP impl.Assert ((slice.nil = slice.nil) = #true);; #() {{ v, Φ v }}. I think the slice.nil = slice.nil comparison should be a pure exec, but I'm struggling to get the system to recognize that.

@upamanyus
Copy link
Collaborator

Here's a way to prove it:

Lemma wp_test :
{{{
True
}}}
test #()
{{{
RET #(); True
}}}
.
Proof.
iIntros (Φ) "_ HΦ".
wp_lam. wp_pures.
rewrite /NewSlice.
rewrite /slice.nil.
wp_pures.
wp_pure1.
{ done. }
wp_apply wp_Assert.
2:{ wp_pures; by iApply "HΦ". }
done.
Qed.

@RalfJung
Copy link
Collaborator

Yeah, our NewSlice just returns null when the length is 0. I don't know if our memory even supports zero-sized allocations...

@upamanyus
Copy link
Collaborator

#72 (and its corresponding Goose changes) fixes this. Specifically, a nil gives (#null, #0, #0) while make([]T, 0) gives (#(Loc 1 0) +ₗ ArbitraryInt, #0, #0). The ArbitraryInt is there to model an arbitrary address, but it is technically only an offset within block 1. I couldn't think of a way to nondeterministically pick a block in the heap, but this should be good enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants