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

Binary operations on pointers should not generate overflow warnings in SV-COMP #1511

Merged
merged 8 commits into from
Jun 25, 2024

Conversation

karoliineh
Copy link
Member

Looking into the no-overflow tasks, there were many tasks (array-memsafety/cstr..-alloca-..) where the signed integer overflow warnings came from pointer arithmetic. For example:

char* nondetArea = (char*) __builtin_alloca (length1 * sizeof(char));
char* nondetString = (char*) __builtin_alloca (length2 * sizeof(char));

char *(cstrcpy)(char *s1, const char *s2)
 {
     char *dst = s1;
     const char *src = s2;
     while ((*dst++ = *src++) != '\0') // [Warning][Integer > Overflow][CWE-190] Signed integer overflow 
         ;
     return s1;
 }

cstrcpy(nondetArea,nondetString);

This PR turns off producing the overflow warnings when IntDomain values are used for pointer arithmetic.

@karoliineh karoliineh added sv-comp SV-COMP (analyses, results), witnesses precision labels Jun 13, 2024
@karoliineh karoliineh added this to the SV-COMP 2025 milestone Jun 13, 2024
@michael-schwarz
Copy link
Member

michael-schwarz commented Jun 13, 2024

Thanks for looking into it!

I started wondering whether this is actually true in general? I would intuitively think some snippet such as this would be Undefined Behavior?

int* ptr = (int*) 0;

while(1) {
   ptr += MAX_INT;
}

I think if the offset is within the bounds of the objects, it should be safe for sure, otherwise I don't know.

If the standard indeed mandates that such computations are not UB, we still need to be careful, as we keep the abstract type pointer even after a cast to int iiirc, and

int x;
int* ptr = &x;

long l = (long) ptr; // Goblint iirc has abstract state with:   l -> {&x}

while(1) {
   l += MAX_INT; //UB!
}

is UB for sure!

@sim642
Copy link
Member

sim642 commented Jun 13, 2024

I started wondering whether this is actually true in general? I would intuitively think some snippet such as this would be Undefined Behavior?

int* ptr = (int*) 0;

while(1) {
   ptr += MAX_INT;
}

I think if the offset is within the bounds of the objects, it should be safe for sure, otherwise I don't know.

N1570 6.5.6.8 says:

[...] If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

So it is UB, although I'm not sure if it could be called "integer overflow". Not for SV-COMP flagging for sure.
As to Goblint warning output, if we want something, we should probably call it differently anyway ("pointer overflow" or whatnot).
Although our current overflow warnings from pointer offset calculations don't soundly even reflect that: it's just about overflow from the index itself, without considering possible addresses (as integers) of the pointer itself. If the pointer itself has value MAX_INT (which it won't on any sensible system, but I guess the standard doesn't forbid), then even p + 2 would "pointer overflow" (p + 1 is fine according to the quote even!). But currently we just compute the address &p[2] and don't output such warning.

@sim642
Copy link
Member

sim642 commented Jun 19, 2024

If the standard indeed mandates that such computations are not UB, we still need to be careful, as we keep the abstract type pointer even after a cast to int iiirc, and

int x;
int* ptr = &x;

long l = (long) ptr; // Goblint iirc has abstract state with:   l -> {&x}

while(1) {
   l += MAX_INT; //UB!
}

is UB for sure!

We don't do such thing on master even. The code for cast has this for casting v to integer:

let v' = match t with
| TInt (ik,_) ->
Int (ID.cast_to ?torg ik (match v with
| Int x -> x
| Address x -> AD.to_int x
| Float x -> FD.to_int ik x
(*| Struct x when Structs.cardinal x > 0 ->
let some = List.hd (Structs.keys x) in
let first = List.hd some.fcomp.cfields in
(match Structs.get x first with Int x -> x | _ -> raise CastError)*)
| _ -> log_top __POS__; ID.top_of ik
))

The result is always an integer abstraction.

Also, the only non-UB cast of pointer to integer would be to some unsigned integer type anyway, so I don't see this being an issue.

Even if this were the case, we wouldn't be soundly warning about it on master anyway. l + 2 (where l has been cast from a pointer) may also overflow and our current behavior just adds an index offset 2 without emitting any warnings.

@karoliineh karoliineh marked this pull request as ready for review June 19, 2024 13:13
@sim642
Copy link
Member

sim642 commented Jun 19, 2024

On sv-benchmarks with no-overflow property, this gives 53 new correct results with 60s timeout. Nothing becomes unsound.

@sim642 sim642 added the documentation Documentation, comments label Jun 25, 2024
@sim642 sim642 merged commit 810debe into master Jun 25, 2024
19 checks passed
@sim642 sim642 deleted the no-overflows-on-pointers branch June 25, 2024 18:58
sim642 added a commit to sim642/opam-repository that referenced this pull request Aug 2, 2024
CHANGES:

* Remove unmaintained analyses: spec, file (goblint/analyzer#1281).
* Add linear two-variable equalities analysis (goblint/analyzer#1297, goblint/analyzer#1412, goblint/analyzer#1466).
* Add callstring, loopfree callstring and context gas analyses (goblint/analyzer#1038, goblint/analyzer#1340, goblint/analyzer#1379, goblint/analyzer#1427, goblint/analyzer#1439).
* Add non-relational thread-modular value analyses with thread IDs (goblint/analyzer#1366, goblint/analyzer#1398, goblint/analyzer#1399).
* Add NULL byte array domain (goblint/analyzer#1076).
* Fix spurious overflow warnings from internal evaluations (goblint/analyzer#1406, goblint/analyzer#1411, goblint/analyzer#1511).
* Refactor non-definite mutex handling to fix unsoundness (goblint/analyzer#1430, goblint/analyzer#1500, goblint/analyzer#1503, goblint/analyzer#1409).
* Fix non-relational thread-modular value analysis unsoundness with ambiguous points-to sets (goblint/analyzer#1457, goblint/analyzer#1458).
* Fix mutex type analysis unsoundness and enable it by default (goblint/analyzer#1414, goblint/analyzer#1416, goblint/analyzer#1510).
* Add points-to set refinement on mutex path splitting (goblint/analyzer#1287, goblint/analyzer#1343, goblint/analyzer#1374, goblint/analyzer#1396, goblint/analyzer#1407).
* Improve narrowing operators (goblint/analyzer#1502, goblint/analyzer#1540, goblint/analyzer#1543).
* Extract automatic configuration tuning for soundness (goblint/analyzer#1369).
* Fix many locations in witnesses (goblint/analyzer#1355, goblint/analyzer#1372, goblint/analyzer#1400, goblint/analyzer#1403).
* Improve output readability (goblint/analyzer#1294, goblint/analyzer#1312, goblint/analyzer#1405, goblint/analyzer#1497).
* Refactor logging (goblint/analyzer#1117).
* Modernize all library function specifications (goblint/analyzer#1029, goblint/analyzer#688, goblint/analyzer#1174, goblint/analyzer#1289, goblint/analyzer#1447, goblint/analyzer#1487).
* Remove OCaml 4.10, 4.11, 4.12 and 4.13 support (goblint/analyzer#1448).
michael-schwarz added a commit that referenced this pull request Aug 4, 2024
avsm pushed a commit to avsm/opam-repository that referenced this pull request Sep 5, 2024
CHANGES:

* Remove unmaintained analyses: spec, file (goblint/analyzer#1281).
* Add linear two-variable equalities analysis (goblint/analyzer#1297, goblint/analyzer#1412, goblint/analyzer#1466).
* Add callstring, loopfree callstring and context gas analyses (goblint/analyzer#1038, goblint/analyzer#1340, goblint/analyzer#1379, goblint/analyzer#1427, goblint/analyzer#1439).
* Add non-relational thread-modular value analyses with thread IDs (goblint/analyzer#1366, goblint/analyzer#1398, goblint/analyzer#1399).
* Add NULL byte array domain (goblint/analyzer#1076).
* Fix spurious overflow warnings from internal evaluations (goblint/analyzer#1406, goblint/analyzer#1411, goblint/analyzer#1511).
* Refactor non-definite mutex handling to fix unsoundness (goblint/analyzer#1430, goblint/analyzer#1500, goblint/analyzer#1503, goblint/analyzer#1409).
* Fix non-relational thread-modular value analysis unsoundness with ambiguous points-to sets (goblint/analyzer#1457, goblint/analyzer#1458).
* Fix mutex type analysis unsoundness and enable it by default (goblint/analyzer#1414, goblint/analyzer#1416, goblint/analyzer#1510).
* Add points-to set refinement on mutex path splitting (goblint/analyzer#1287, goblint/analyzer#1343, goblint/analyzer#1374, goblint/analyzer#1396, goblint/analyzer#1407).
* Improve narrowing operators (goblint/analyzer#1502, goblint/analyzer#1540, goblint/analyzer#1543).
* Extract automatic configuration tuning for soundness (goblint/analyzer#1369).
* Fix many locations in witnesses (goblint/analyzer#1355, goblint/analyzer#1372, goblint/analyzer#1400, goblint/analyzer#1403).
* Improve output readability (goblint/analyzer#1294, goblint/analyzer#1312, goblint/analyzer#1405, goblint/analyzer#1497).
* Refactor logging (goblint/analyzer#1117).
* Modernize all library function specifications (goblint/analyzer#1029, goblint/analyzer#688, goblint/analyzer#1174, goblint/analyzer#1289, goblint/analyzer#1447, goblint/analyzer#1487).
* Remove OCaml 4.10, 4.11, 4.12 and 4.13 support (goblint/analyzer#1448).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Documentation, comments precision sv-comp SV-COMP (analyses, results), witnesses
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants