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

Unsound address set must-not-equality check in base #822

Closed
3 tasks
sim642 opened this issue Aug 11, 2022 · 3 comments · Fixed by #967
Closed
3 tasks

Unsound address set must-not-equality check in base #822

sim642 opened this issue Aug 11, 2022 · 3 comments · Fixed by #967
Assignees
Milestone

Comments

@sim642
Copy link
Member

sim642 commented Aug 11, 2022

The use of AD.meet to check address set must-not-equality:

| Eq ->
`Int (if AD.is_bot (AD.meet p1 p2) then ID.of_int ik BI.zero else match eq p1 p2 with Some x when x -> ID.of_int ik BI.one | _ -> bool_top ik)
| Ne ->
`Int (if AD.is_bot (AD.meet p1 p2) then ID.of_int ik BI.one else match eq p1 p2 with Some x when x -> ID.of_int ik BI.zero | _ -> bool_top ik)

is unsound in at least the following cases:

For both programs we report that the assert definitely fails, but when compiled and run, it succeeds.

Using meet would only work if addresses were represented in their canonical form using a byte offset from the variable.

@jerhard
Copy link
Member

jerhard commented Aug 11, 2022

The unsoundness of comparing addresses with a struct field and an index as offsets is also exhibited for non-zero offsets:

struct str a;
char* ca = (char*) &a;
void *ptr = &ca[4];
void *ptr2 = &a.c;
int z = 1;
// Alginment of struct fields, and thus result of the equality check here is implementation defined.
if(ptr == ptr2){
z = 1;
} else {
z = 2;
}
// Aaccording to the C standard (section 6.2.8 in the C11 standard),
// the alignment of fields in structs is implementation defined.
// When compiling with GCC, the following check as an assert happens to hold.
__goblint_check(z==1); //UNKNOWN!

The alignment of fields within objects is implementation defined, thus one generally cannot produce definite answers when comparing integer offsets with field offsets on structs.

@sim642
Copy link
Member Author

sim642 commented Sep 2, 2022

Since #809 makes this problem even more urgent, we probably need a quicker fix than completely refactoring lvalue representations to carry a canonical form or whatnot. A simpler implementation for just AD.may_equal a1 a2 would be to pairwise check all lvalues from a1 and a2, and check their may equality. That could be implemented by calculating the canonical offset numerically, a la Cil.bitsOffset and checking those integers for may equality. The only problem is that Cil.bitsOffset works only with constant indices, but we'll have abstract ones, so it'll have to be partially reimplemented in Goblint. However, CIL can still provide us with the byte/bit offsets of struct fields (using Machdep), so it shouldn't be too difficult.

@sim642
Copy link
Member Author

sim642 commented Sep 22, 2022

A remark from Zulip on optimizing the pairwise may alias checking. Checking all pairs is overly wasteful because addresses may only alias if their varinfos (without offsets) are equal, so it suffices to do pairwise checking within each varinfo.

The projective bucketing from #809 doesn't directly allow that because the ProjectiveSet buckets are per varinfo and representative offset. However, that could be replaced with a two nested ProjectiveSets: outer split by varinfo only and inner split by representative offset in each varinfo. Then may alias checking can be performed pairwise within each outer bucket, but over all the elements in the corresponding inner buckets.
Currently ProjectiveSet completely abstracts away the map structure, so an additional special function (maybe bucket_exists2?) would have to be implemented to do that.

@jerhard jerhard self-assigned this Jan 16, 2023
@sim642 sim642 added this to the v2.2.0 milestone Mar 27, 2023
sim642 added a commit to sim642/opam-repository that referenced this issue Sep 13, 2023
CHANGES:

* Add `setjmp`/`longjmp` analysis (goblint/analyzer#887, goblint/analyzer#970, goblint/analyzer#1015, goblint/analyzer#1019).
* Refactor race analysis to lazy distribution (goblint/analyzer#1084, goblint/analyzer#1089, goblint/analyzer#1136, goblint/analyzer#1016).
* Add thread-unsafe library function call analysis (goblint/analyzer#723, goblint/analyzer#1082).
* Add mutex type analysis and mutex API analysis (goblint/analyzer#800, goblint/analyzer#839, goblint/analyzer#1073).
* Add interval set domain and string literals domain (goblint/analyzer#901, goblint/analyzer#966, goblint/analyzer#994, goblint/analyzer#1048).
* Add affine equalities analysis (goblint/analyzer#592).
* Add use-after-free analysis (goblint/analyzer#1050, goblint/analyzer#1114).
* Add dead code elimination transformation (goblint/analyzer#850, goblint/analyzer#979).
* Add taint analysis for partial contexts (goblint/analyzer#553, goblint/analyzer#952).
* Add YAML witness validation via unassume (goblint/analyzer#796, goblint/analyzer#977, goblint/analyzer#1044, goblint/analyzer#1045, goblint/analyzer#1124).
* Add incremental analysis rename detection (goblint/analyzer#774, goblint/analyzer#777).
* Fix address sets unsoundness (goblint/analyzer#822, goblint/analyzer#967, goblint/analyzer#564, goblint/analyzer#1032, goblint/analyzer#998, goblint/analyzer#1031).
* Fix thread escape analysis unsoundness (goblint/analyzer#939, goblint/analyzer#984, goblint/analyzer#1074, goblint/analyzer#1078).
* Fix many incremental analysis issues (goblint/analyzer#627, goblint/analyzer#836, goblint/analyzer#835, goblint/analyzer#841, goblint/analyzer#932, goblint/analyzer#678, goblint/analyzer#942, goblint/analyzer#949, goblint/analyzer#950, goblint/analyzer#957, goblint/analyzer#955, goblint/analyzer#954, goblint/analyzer#960, goblint/analyzer#959, goblint/analyzer#1004, goblint/analyzer#558, goblint/analyzer#1010, goblint/analyzer#1091).
* Fix server mode for abstract debugging (goblint/analyzer#983, goblint/analyzer#990, goblint/analyzer#997, goblint/analyzer#1000, goblint/analyzer#1001, goblint/analyzer#1013, goblint/analyzer#1018, goblint/analyzer#1017, goblint/analyzer#1026, goblint/analyzer#1027).
* Add documentation for configuration JSON schema and OCaml API (goblint/analyzer#999, goblint/analyzer#1054, goblint/analyzer#1055, goblint/analyzer#1053).
* Add many library function specifications (goblint/analyzer#962, goblint/analyzer#996, goblint/analyzer#1028, goblint/analyzer#1079, goblint/analyzer#1121, goblint/analyzer#1135, goblint/analyzer#1138).
* Add OCaml 5.0 support (goblint/analyzer#1003, goblint/analyzer#945, goblint/analyzer#1162).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants