Lets say we have the following C code:
int my_main(int x){
if (x > 5){
x++;
if (x > 8){
x++;
if (x < 15){
//@(x >= 9 && x <= 14);
}
}
}
return 0;
}
I'd like to calculate using static analysis the bounds on the variable x at initialization which result in a satisfied predicate. In this example, the interval of x at the start of main should be [8, 12].
TL;DR: What would be the best way to calculate these ranges given an assertion somewhere in the code?
What I tried so far:
I think the best way to approach this is using a weakest precondition calculator. Iv'e tried toying around with the wp plugin of frama-c but since it is built for verification purposes, I am not sure how useful it is in this use case. When applying the plugin on the following code:
int main(void){
int n = 0;
int x;
if (x > 5){
x++;
if (x > 8){
x++;
if (x < 15){
n = x;
}
}
}
//@ assert p: n >= 9 && n <= 14;
return 0;
}
I get the following predicate sent to the alt-ergo solver:
goal main_assert_p:
forall i_1,i : int.
is_sint32(i) ->
is_sint32(i_1) ->
(((i < 6) -> (0 = i_1)) and
(**(6 <= i)** ->
(((i < 8) -> (0 = i_1)) and
(**(8 <= i)** ->
(((12 < i) -> (0 = i_1)) and (**(i <= 12)** -> (i_1 = (2 + i)))))))) ->
((9 <= i_1) and (i_1 <= 14))
If you look carefully, it is possible to identify the required interval on the input by following the bounds on the variable i which don't result in (i_1 = 0). Iv'e marked these bounds. This is not very robust, for example if the assertion changes to && n <= 13, the 'left side' of the implies predicate stays the same as none of the conditions changed. Also i'm not sure how useful this is in other scenarios, for example altering my assertion to a requires statement when calling a function, I can't understand the resulting predicate:
if (x < 15){
sum(x);
}
And adding a requires statement to the function:
//@requires (n >= 6 && n <= 11);
int sum(int n){
I get:
goal main_call_sum_pre:
forall i : int.
(6 <= i) ->
(8 <= i) ->
(i <= 12) ->
is_sint32(i) ->
is_sint32(1 + i) ->
is_sint32(2 + i) ->
((4 <= i) and (i <= 9))
assert
takes a Boolean expression and ifFALSE
, aborts the application with a message.assert
is generally a macro and in the non-debug version of your program, calls to these macros are removed during preprocessing.Your Boolean expression contains constants. If you replace those with variables, then you have your flexible assert.