RecordFlux icon indicating copy to clipboard operation
RecordFlux copied to clipboard

Using Boolean value as condition causes exception in Z3

Open jklmnn opened this issue 3 years ago • 2 comments

Using a boolean variable or field as a condition value as follows:

package Test is

   type Tag is (Tag_A, Tag_B) with Size => 8;

   type Message (Has_Tag : Boolean) is
      message
         Tag_1 : Tag
            then Tag_2
               if Has_Tag
            then null
               if Has_Tag = False;
         Tag_2 : Tag;
      end message;

end Test;

Causes the following error:

Parsing test.rflx
Processing Test                                                                                                       

------------------------------ RecordFlux Bug ------------------------------
RecordFlux 0.6.0-pre
RecordFlux-parser 0.7.0                                                                                               
attrs 20.3.0
icontract 2.5.0                                                                                                       
pydotplus 2.0.2
z3-solver 4.8.10.0                                                                                                                                                                                                                          
                                                           
Optimized: True
                                                           
Command: /.../RecordFlux/venv/bin/rflx check test.rflx

Traceback (most recent call last):                                                                                                                                                                                                          
  File "/.../RecordFlux/rflx/cli.py", line 120, in main                                                                                                                                                                       
    args.func(args)                                                                                                                                                                                                                         
  File "/.../RecordFlux/rflx/cli.py", line 161, in check                                                                                                                                                                      
    parse(args.files, args.no_verification, args.workers)                                                                                                                                                                                   
  File "/.../RecordFlux/rflx/cli.py", line 208, in parse                                                                                                                                                                      
    model = parser.create_model()                                                                                                                                                                                                           
  File "/.../RecordFlux/rflx/specification/parser.py", line 1543, in create_model                                                                                                                                             
    self.__evaluate_specification(error, spec_node.spec, spec_node.filename)                                                                                                                                                                
  File "/.../RecordFlux/rflx/specification/parser.py", line 1591, in __evaluate_specification                                                                                                                                 
    new_type = handlers[t.f_definition.kind_name](                                                                    
  File "/.../RecordFlux/rflx/specification/parser.py", line 804, in create_message                      
    result = create_proven_message(                                                                                   
  File "/.../RecordFlux/rflx/specification/parser.py", line 1288, in create_proven_message              
    proven_message = unproven_message.proven(                                                                         
  File "/.../RecordFlux/rflx/model/message.py", line 1844, in proven 
    return Message(                                                                                                   
  File "/.../RecordFlux/rflx/model/message.py", line 749, in __init__                                   
    self.verify()                                                                                                     
  File "/.../RecordFlux/rflx/model/message.py", line 755, in verify                                     
    self.__verify_expression_types()                
  File "/.../RecordFlux/rflx/model/message.py", line 1060, in __verify_expression_types                 
    proof = self.__prove_path_property(expr.TRUE, p)                                                                  
  File "/.../RecordFlux/rflx/model/message.py", line 1729, in __prove_path_property                     
    return prop.check([*self.type_constraints(prop), *conditions, *sizes])
  File "/.../RecordFlux/rflx/expression.py", line 261, in check                                         
    return Proof(self, facts)                                                                                         
  File "/.../RecordFlux/rflx/expression.py", line 58, in __init__                                       
    solver.add(f.z3expr())                                                                                            
  File "/.../RecordFlux/venv/lib/python3.9/site-packages/z3/z3.py", line 6613, in add                   
    self.assert_exprs(*args)                                                                                                                                                                                                                
  File "/.../RecordFlux/venv/lib/python3.9/site-packages/z3/z3.py", line 6602, in assert_exprs          
    Z3_solver_assert(self.ctx.ref(), self.solver, arg.as_ast())
  File "/.../RecordFlux/venv/lib/python3.9/site-packages/z3/z3core.py", line 3754, in Z3_solver_assert
    _elems.Check(a0)                                      
  File "/.../RecordFlux/venv/lib/python3.9/site-packages/z3/z3core.py", line 1414, in Check
    raise self.Exception(self.get_error_message(ctx, err))
z3.z3types.Z3Exception: b'invalid argument'                                                                           

----------------------------------------------------------------------------

jklmnn avatar Sep 22 '21 09:09 jklmnn

Looks related to #611

senier avatar Aug 25 '22 09:08 senier

I noticed an architectural problem when setting the types. In message.py:Message.verify the function self._verify_expression_types does two things: It checks that no path contains any contradictions and that all variables are defined in that order. If no types are set this seems to work. With the changes introduced with this issue the types are not only set for conditions but also for type constraints. This causes a mismatch when the types of the conditions are not set which will then cause a Z3 exception. This is generally the case when a variable is not defined.

I think the proper fix to that problem is to move the check if all variables are set before the path condition check and abort checking the message when a variable is not defined. While this seems to conflict with the approach to gather as many errors as possible before aborting I think we cannot make any assumptions about the remaining message if it contains an unset variable.

jklmnn avatar Oct 17 '22 13:10 jklmnn