goblint / analyzer

Static analysis framework for C
https://goblint.in.tum.de
MIT License
160 stars 72 forks source link

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

Closed karoliineh closed 1 week ago

karoliineh commented 2 weeks ago

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.

michael-schwarz commented 2 weeks ago

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 commented 2 weeks ago

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 commented 2 weeks ago

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: https://github.com/goblint/analyzer/blob/4812b07e58b7c854e2fc4c25763101cb73800e69/src/cdomain/value/cdomains/valueDomain.ml#L476-L487 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.

sim642 commented 1 week ago

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