-
Notifications
You must be signed in to change notification settings - Fork 12
Range check via Cprover assert #91
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is going in the right direction but needs some cleanup and some rethinking of how we pass around ranges before it can go in.
There is also no test attached to this.
gnat2goto/driver/tree_walk.adb
Outdated
function Uint_To_Integer (Number : Uint) return Integer | ||
is | ||
begin | ||
return Integer (UI_To_Int (Number)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This restricts us to 32 bit bounds (Int
is basically a 32 bit signed integer). We need to find a better way around this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hannes-steffenhagen-diffblue I've added one commit that addresses that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xbauch could you reference the commit please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit is gone now, but basically we went from Int to Uint (which is of arbitrary size). It is now in separate package range_check
.
gnat2goto/driver/tree_walk.adb
Outdated
function Do_Assert (N : Node_Id; Assertion : Irep; Description : Irep) | ||
return Irep; | ||
|
||
function Do_Range_Assert (N : Node_Id; Value : Irep; Value_Type : Irep) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 3 functions actually generate code, but they're using the naming scheme of the functions that handle an AST node. I think we need to come up with less confusing names for these.
gnat2goto/driver/tree_walk.adb
Outdated
@@ -928,8 +1029,10 @@ package body Tree_Walk is | |||
end if; | |||
return R : constant Irep := New_Irep (I_Bounded_Signedbv_Type) do | |||
Set_Width (R, Get_Width (Resolved_Underlying)); | |||
Set_Lower_Bound (R, Do_Constant (Low_Bound (Range_Expr))); | |||
Set_Upper_Bound (R, Do_Constant (High_Bound (Range_Expr))); | |||
Set_Lower_Bound (R, Uint_To_Integer (Intval (Low_Bound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't think it makes much sense for these to be properties on the type; For dynamic bounds at least we'll need to carry around the bounds in variables/hidden parameters anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is keeping us from using unbounded signedbv types for the bounds here by the way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hannes-steffenhagen-diffblue I'm not sure what is going to be the best approach for dynamic bounds. As of now, the bounds are Uint
s (as per the last commit) and the Irep
properties are Integer
. Having any other numeric type inside Irep
s would require changing the schemes, and the generating Python script.
e651ce3
to
0daa8bf
Compare
@hannes-steffenhagen-diffblue I've renamed the 3 functions that create code (to |
gnat2goto/driver/tree_walk.adb
Outdated
(Index_Type => Natural, | ||
Element_Type => Uint); | ||
|
||
Integer_Bounds_Table : Integer_Bounds_Vector.Vector; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ I think I'd be more comfortable if the above were in a separate package, also if the key had its own type (so we'd cast on access, but for here could keep the key something that is distinct from an integer). The latter just to prevent accidental misuse, the former because this package is already very crowded as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to a separate package and declared a new type Bound_Type
.
gnat2goto/driver/tree_walk.adb
Outdated
function Make_Sym_Range_Expression (I : Irep) return Irep | ||
with Pre => Kind (I) = I_Symbol_Expr, | ||
Post => Kind (Make_Sym_Range_Expression'Result) in Class_Expr; | ||
function Make_Sym_Range_Expression (I : Irep; Val_Type : Irep) return Irep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is called Sym_Range_Expression
but we no longer demand the parameter to be a symbol?
gnat2goto/driver/tree_walk.adb
Outdated
declare | ||
Cast_RHS : constant Irep := New_Irep (I_Op_Typecast); | ||
begin | ||
Set_Op0 (Cast_RHS, RHS); | ||
Set_Type (Cast_RHS, Get_Type (LHS)); | ||
Set_Range_Check (Cast_RHS, True); | ||
Set_Rhs (R, Cast_RHS); | ||
Set_Rhs (R, Make_Range_Assert_Expr (N, Cast_RHS, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the range checks should happen before the typecast, in case of a cast into a smaller type? Then again, what happens when casting to a larger type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swapped. I guess casting to a larger type should simply pass the range check.
gnat2goto/driver/tree_walk.adb
Outdated
Value => Sym_Type); | ||
Set_Value (I => Lower_Bound, | ||
Value => Load_Bound_In_Hex (Get_Lower_Bound (Sym_Type), | ||
Pos (Get_Width (Sym_Type)))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the width of the type isn't large enough to hold the value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't that mean that the bound cannot be stored in a variable of that type?
@@ -1 +1,3 @@ | |||
VERIFICATION SUCCESSFUL | |||
[assertion.1] Range Check: FAILURE | |||
[assertion.2] Range Check: FAILURE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd probably be better to have a test where both failure and successes happen, and that's also testing some things like casting into a larger or smaller type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've extended the existing test with a few more cases, making the range check pass as well. I'm not sure it cover all reasonable cases.
c00213b
to
2b05e8a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some preliminary comments, not quite done reviewing yet
gnat2goto/driver/tree_walk.adb
Outdated
|
||
function Build_Assert_Function return Symbol | ||
is | ||
Func_Type : constant Irep := New_Irep (I_Code_Type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ All the ireps in here should have the source location of N
attached to them, I don't think this necessarily needs to be done now though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undone, only Class_Expr
ireps can have source location.
|
||
declare | ||
R : constant Irep := New_Irep (I_Code_Assign); | ||
begin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change from the return
to the declare
form? AFAICT they're equivalent right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return
was getting uncomfortably long, other than that I also think they are equivalent.
(Intval (N), Pos (Constant_Width))); | ||
else | ||
Set_Value (Ret, UI_Image (Input => Intval (N), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bit is unrelated to the range checks right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, I might have introduced it because the ranges were integer literals and this function did not handle them correctly. Maybe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xbauch this really needs some comments.
This change was prompted by something - please tell us the reason behind the 'else'.
If this is one of those 'this works' kind of things that is hazy - please tell us what didn't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sonodtt I will find out and describe it in the code. It will take a bit longer though.
4d08f4b
to
fc32b97
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to work now, I still have some (mostly nitpicky) concerns left though
@@ -29,6 +29,15 @@ package GOTO_Utils is | |||
function Symbol_Expr (Sym : Symbol) return Irep | |||
with Post => Kind (Symbol_Expr'Result) = I_Symbol_Expr; | |||
|
|||
function Create_Fun_Parameter (Fun_Name : String; Param_Name : String; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should have at least a one line comment explaining what this function does, same with pretty much all the other new functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
gnat2goto/driver/goto_utils.adb
Outdated
Identifier => Unintern (Func_Param_Id)); | ||
begin | ||
A_Symbol_Table.Insert (Func_Param_Id, Value_Symbol); | ||
Set_Type (Value_Arg, Param_Type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the I_Type
parameter of Make_Code_Parameter
to set this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
gnat2goto/driver/goto_utils.adb
Outdated
A_Symbol_Table.Insert (Func_Param_Id, Value_Symbol); | ||
Set_Type (Value_Arg, Param_Type); | ||
Set_Identifier (Value_Arg, Unintern (Func_Param_Id)); | ||
Set_Base_Name (Value_Arg, "value"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above two are already set by Make_Code_Parameter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
gnat2goto/driver/tree_walk.adb
Outdated
New_Symbol.Mode := Intern ("C"); | ||
New_Symbol.Value := Value; | ||
|
||
if not (Global_Symbol_Table.Contains (Key => Intern (Name))) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The else
keys in this instance seems like it'd be an error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nit pick - I lean towards renaming this 'Add_To_Symbol_Table'.
Really happy that we start to have more utility functions - I think of them as good documentation (and they add robustness).
Might be helpful to add a comment w.r. to in which scenario Name and Basename should differ?
(or it will get used that one time it should not)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
gnat2goto/driver/tree_walk.adb
Outdated
package body Tree_Walk is | ||
|
||
procedure Add_Entity_Substitution (E : Entity_Id; Subst : Irep); | ||
|
||
procedure Append_Declare_And_Init | ||
(Symbol : Irep; Value : Irep; Block : Irep; Source_Loc : Source_Ptr); | ||
|
||
function Add_To_Table (Name : String; Symbol_Type : Irep; Value : Irep) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use a slightly clearer name. Maybe New_Symbol_Table_Entry
or something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
gnat2goto/driver/tree_walk.adb
Outdated
Func_Args : constant Irep := New_Irep (I_Parameter_List); | ||
Func_Name : constant String := | ||
Fresh_Var_Name ("range_check"); | ||
Body_Block : constant Irep := New_Irep (I_Code_Block); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ I'd prefer Make_XXX
functions in place of these
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Func_Args => Func_Params (?)
( we do have argument vs parameter list and append_parameter vs append_argument)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
function Make_Range_Assert_Expr (N : Node_Id; Value : Irep; | ||
Value_Type : Irep) | ||
return Irep | ||
is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use a comment showing (in pseudocode) what kind of code is being generated here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -1575,25 +1788,12 @@ package body Tree_Walk is | |||
Sym_Nondet : constant Irep := | |||
Fresh_Var_Symbol_Expr (Type_Irep, Func_Str); | |||
SE_Call_Expr : constant Irep := | |||
New_Irep (I_Side_Effect_Expr_Function_Call); | |||
Make_Assume_Expr (N, Make_Range_Expression (Sym_Nondet, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ It might make sense to put the definition of Make_Assume_Expr
and Make_Assert_Call
in a separate commit, although I'd see that as pretty optional
gnat2goto/driver/tree_walk.adb
Outdated
New_Symbol.Mode := Intern ("C"); | ||
New_Symbol.Value := Value; | ||
|
||
if not (Global_Symbol_Table.Contains (Key => Intern (Name))) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nit pick - I lean towards renaming this 'Add_To_Symbol_Table'.
Really happy that we start to have more utility functions - I think of them as good documentation (and they add robustness).
Might be helpful to add a comment w.r. to in which scenario Name and Basename should differ?
(or it will get used that one time it should not)
gnat2goto/driver/tree_walk.adb
Outdated
Func_Args : constant Irep := New_Irep (I_Parameter_List); | ||
Func_Name : constant String := | ||
Fresh_Var_Name ("range_check"); | ||
Body_Block : constant Irep := New_Irep (I_Code_Block); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Func_Args => Func_Params (?)
( we do have argument vs parameter list and append_parameter vs append_argument)
gnat2goto/driver/tree_walk.adb
Outdated
|
||
Set_Parameters (Func_Type, Func_Args); | ||
Set_Return_Type (Func_Type, Actual_Type); | ||
Set_Ellipsis (Func_Type, False); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering if we know why 'Set_Ellipsis' is required and has value False
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was among the things we thought might fix the parameter-assignment problem. It wasn't, but I think it denotes the use of parameter packs. There should be none, hence false.
function Make_Assert_Call (N : Node_Id; Assertion : Irep; | ||
Description : Irep) | ||
return Irep is | ||
SE_Call_Expr : constant Irep := |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'SE_Call_Expr' - in particular the SE. This is no longer a side effect call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Added a commit that follows the comment suggestions (separate now to ease review). Will squash/reorder commits once approved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
728c065
to
e25a0cb
Compare
Needs a rebase, but otherwise LGTM |
Introduces range check bounds stored in a vector and loaded explicitly when building the assertion for checking the range.
Automates creation of function parameters (including appending to arg list).
Slight refactor of the methods for working with assume/assert.
e25a0cb
to
f442210
Compare
No description provided.