Python 将C99代码翻译成Z3,细微细节
我遇到了一些我不太了解的微妙细节。我正在开发一个工具来删除死代码,假设以下示例:Python 将C99代码翻译成Z3,细微细节,python,z3,Python,Z3,我遇到了一些我不太了解的微妙细节。我正在开发一个工具来删除死代码,假设以下示例: int main(){ if(1==0){ neverexecutes(); } } 我将其转换为AST(),当遇到if条件1==0时,我使用以下方法将其转换为Z3: def evaluate_ast(self, node: c_ast.Node): """Translates a c_ast.Node to a z3 predicat
int main(){
if(1==0){
neverexecutes();
}
}
我将其转换为AST(),当遇到if条件1==0
时,我使用以下方法将其转换为Z3:
def evaluate_ast(self, node: c_ast.Node):
"""Translates a c_ast.Node to a z3 predicate."""
typ = type(node)
if typ == c_ast.BinaryOp:
leftnode = self.evaluate_ast(node.left)
rightnode = self.evaluate_ast(node.right)
if node.op == '&&':
return And(leftnode, rightnode)
elif node.op == '||':
return Or(leftnode, rightnode)
elif node.op == '==':
return leftnode == rightnode
elif node.op == '<':
return leftnode < rightnode
elif node.op == '<=':
return leftnode <= rightnode
elif node.op == '>':
return leftnode > rightnode
elif node.op == '>=':
return leftnode >= rightnode
elif node.op == '!=':
return leftnode != rightnode
elif node.op == '/':
return leftnode / rightnode
elif node.op == '+':
return leftnode + rightnode
elif typ == c_ast.Assignment and node.op == '=':
leftnode = self.evaluate_ast(node.lvalue)
rightnode = self.evaluate_ast(node.rvalue)
return leftnode == rightnode
(...)
它是有效的,我假设我对所有二进制运算符都有相同的问题。我错过了什么?只有False
的系统不应该是unsat
?我认为k!0
只是Z3中某个假值的翻译
我想这也比我的问题好一点:
>>> from z3 import *
>>> s = Solver()
>>> s.add(False)
>>> s.check()
unsat
>>> s.reset()
>>> s.add(1==0)
>>> s.check()
unsat
>>> s.reset()
>>> s.add(Bool(1==0))
>>> s.check()
sat
False
、1==0
和Bool(1==0)
之间的区别是什么?这里的问题是Bool
取一个名称并从中提取符号值。您需要改用BoolVal
。在这些情况下,出于调试目的,sexpr
方法是您的朋友:
>>从z3导入*
>>>s=解算器()
>>>s.add(1==0)
>>>打印(s.sexpr())
(断言错误)
以上是可以的,因为add
方法能够正确处理值。您可以将其包裹在BoolVal
周围,以获得相同的效果:
>>从z3导入*
>>>s=解算器()
>>>s.add(布尔瓦尔(1==0))
>>>打印(s.sexpr())
(断言错误)
但是看看如果你把它包装起来会发生什么:
>>从z3导入*
>>>s=解算器()
>>>s.add(Bool(1==0))
>>>打印(s.sexpr())
(声明funk!0()Bool)
(断言k!0)
这就是你问题的本质。(看起来z3正在使用一个内部名称k!0
,因为1==0
在这里不是有效的SMTLib名称。这增加了混淆。)
请注意,z3py对Int
/IntVal
,BitVec
/BitVecVal
,Real
/RealVal
等具有类似的功能,您必须谨慎使用
不幸的是,这是z3py的弱点之一:由于Python的非类型化性质,不同的函数试图解释您可以提供的各种输入,它们有时不一致,并且很难检测和调试此类问题。如果你怀疑打印出了什么东西,sexpr()是你最好的朋友。(例如,最近报告了一个类似的bug,随后修复了。)这很可能是自动强制转换的问题。尝试在调试器中单步执行,以查看这些值中的哪些实际被转换为Z3表达式。我的猜测是
Bool(1==0)
是一个指向对象的Python(非零)指针,Z3API不知道如何处理它,因此它创建了一个符号常量。是的,我就是问这个问题的同一个人:)除了指南之外,还有其他面向Python的建议吗?或者我应该专注于实现吗?这可能是你最好的选择。我也喜欢基本信息,但你现在可能已经远远超出了这个范围!祝你好运。
>>> from z3 import *
>>> s = Solver()
>>> s.add(False)
>>> s.check()
unsat
>>> s.reset()
>>> s.add(1==0)
>>> s.check()
unsat
>>> s.reset()
>>> s.add(Bool(1==0))
>>> s.check()
sat