Z3 在使用数组定义变量时,是否有方法指定变量的域?
我的程序从smt2文件中读取约束,所有变量都定义为数组。比如说Z3 在使用数组定义变量时,是否有方法指定变量的域?,z3,smt,Z3,Smt,我的程序从smt2文件中读取约束,所有变量都定义为数组。比如说 (declare-fun x () (Array (_ BitVec 32) (_ BitVec 8) ) ) (declare-fun y () (Array (_ BitVec 32) (_ BitVec 8) ) ) (assert (bvslt (concat (select x (_ bv3 32) ) (concat (select x (_ bv2 32) ) (concat (select x (_ b
(declare-fun x () (Array (_ BitVec 32) (_ BitVec 8) ) )
(declare-fun y () (Array (_ BitVec 32) (_ BitVec 8) ) )
(assert (bvslt (concat (select x (_ bv3 32) ) (concat (select x (_ bv2 32) ) (concat (select x (_ bv1 32) ) (select x (_ bv0 32) ) ) ) ) (concat (select y (_ bv3 32) ) (concat (select y (_ bv2 32) ) (concat (select y (_ bv1 32) ) (select y (_ bv0 32) ) ) ) ) ) )
(check-sat)
(exit)
省略了其他一些约束。有时,解算器会将x的值设置为:
(store (store (store ((as const (Array (_ BitVec 32) (_ BitVec 8))) #xfe)
#x00000002
#x00)
#x00000001
#xff)
#x00000003
#x80)
根据定义,数组的每个元素都是十六进制值,因此该值应为0x8000fffe。这个值超出了C++中整数的上限。当我把它转换回int时,它是一个负值。所以我猜Z3将数组定义的所有变量都视为无符号int。
例如,如果约束为x>y,则解算器可能会给出
x=0x8000fffe
及
y=0x00000001。这些值在无符号比较中满足约束,但在进行有符号比较时,x为负,y为正,因此是错误的。我想知道在将数字定义为数组时,是否有方法告诉解算器这些数字是有符号的
添加于2019年9月14日22:26:43
我有两个smt2文件,一个是
(set-logic QF_AUFBV )
(declare-fun x () (Array (_ BitVec 32) (_ BitVec 8) ) )
(declare-fun y () (Array (_ BitVec 32) (_ BitVec 8) ) )
(assert (bvslt (concat (select x (_ bv3 32) ) (concat (select x (_ bv2 32) ) (concat (select x (_ bv1 32) ) (select x (_ bv0 32) ) ) ) ) (concat (select y (_ bv3 32) ) (concat (select y (_ bv2 32) ) (concat (select y (_ bv1 32) ) (select y (_ bv0 32) ) ) ) ) ) )
(check-sat)
(exit)
该约束仅为x(set-logic QF_AUFBV )
(declare-fun x () (Array (_ BitVec 32) (_ BitVec 8) ) )
(declare-fun y () (Array (_ BitVec 32) (_ BitVec 8) ) )
(assert (let ( (?B1 (concat (select y (_ bv3 32) ) (concat (select y (_ bv2 32) ) (concat (select y (_ bv1 32) ) (select y (_ bv0 32) ) ) ) ) ) (?B2 (concat (select x (_ bv3 32) ) (concat (select x (_ bv2 32) ) (concat (select x (_ bv1 32) ) (select x (_ bv0 32) ) ) ) ) ) ) (let ( (?B3 (bvsub ?B1 ?B2 ) ) ) (and (and (and (and (and (= false (= (_ bv0 32) ?B2 ) ) (= false (= (_ bv0 32) ?B1 ) ) ) (= false (bvslt ?B1 ?B2 ) ) ) (= false (= (_ bv0 32) ?B3 ) ) ) (= false (bvslt ?B3 ?B2 ) ) ) (= (_ bv0 32) (bvsub ?B3 ?B2 ) ) ) ) ) )
(check-sat)
(exit)
那是
[(! (0 == x)),
(! (0 == y)),
(! ( y < x)),
(! (0 ==( y - x))),
(! (( y - x) < x)),
(0 ==(( y - x) - x)) ]
所以x=0x8000fffe,y=0x0001fffc。转换为十进制,x=2147549180,y=131068。所以y-x-x是-4294967296,不是小数点0。解算器认为它是满意的,因为4294967296是
1 00000000 00000000 00000000 00000000
在二进制中,“1”是第33位,将被删除。因此-4294967296在内存中被视为0x00。这就是我问这个问题的原因。X和y应该是整数,所以0x8000fffe是-0x0000fffe,也就是-65534。y是131068。y-x-x显然不是0。所以就整数而言,这些值不满足约束。表达式y-x-x似乎是按无符号规则计算的。位向量没有符号
SMTLib中没有有符号或无符号位向量的概念。一个位向量只是一个位序列,没有任何附加的关于如何将其视为数字的语义
然而,区分符号性的是操作。这就是为什么您有bvslt
和bult
;例如,对于有符号和无符号小于比较。您可能希望在此处阅读逻辑描述:
长话短说,所有的解算器告诉你的是,结果包含这些位;如何将其解释为无符号字或有符号2的补码完全取决于您。请注意,这完全符合机器算法在硬件中的实现方式,在硬件中,您只需拥有包含位序列的寄存器。是指令根据他们可能选择的惯例来处理这些值
我希望这是清楚的;请随意询问具体案例;发布完整的程序也总是很有帮助的,只要它们从细节中抽象出来,并描述你想要做的事情
另请参见前面的问题,该问题将更为详细:
避免溢流/底流
您可以要求z3在位向量运算期间避免溢出/下溢。然而,这将需要为您想要执行的每个操作添加额外的断言,因此可能会变得相当混乱。(另外,看起来您希望使用Klee;我不确定Klee是否允许您从一开始就使用它。)本文详细介绍了该技术:
特别是,您需要通读第5.1节:作者描述了如何“注释”每个算术运算,并断言它不会显式溢出。例如,如果您想确保添加不会溢出;首先将位向量从32位扩展到33位;进行加法运算,并检查结果的33位是否为1
。为了避免溢出,只需编写一个断言,说明位不能是1
。下面是一个例子:
; Two 32-bit variables
(declare-fun x () (_ BitVec 32))
(declare-fun y () (_ BitVec 32))
; Zero-Extend them to 33-bits
(define-fun x33 () (_ BitVec 33) (concat #b0 x))
(define-fun y33 () (_ BitVec 33) (concat #b0 y))
; Add them
(define-fun extendedAdd () (_ BitVec 33) (bvadd x33 y33))
; Get the sign bit
(define-fun signBit () (_ BitVec 1) ((_ extract 32 32) extendedAdd))
; Assert that the addition won't overflow:
(assert (= signBit #b0))
; Regular addition result:
(define-fun addResult () (_ BitVec 32) ((_ extract 31 0) extendedAdd))
; Now you can use addResult as the result of x+y; and you'll
; be assured that this addition will never overflow
(check-sat)
(get-model)
您还必须在每次操作中检查下溢。进一步增加了复杂性
正如你所看到的,这可能会变得非常棘手,乘法的规则实际上相当棘手。为了简化此过程,z3实际上提供了用于乘法溢出检查的内置原语,称为:
:仅当有符号乘法未溢出时为Truebvsul\u noovfl
:仅当有符号乘法未下溢时为Truebvsul\u noudfl
:仅当无符号乘法未溢出时为Truebvumul\u noovfl
或者您可以切换并使用
Int
type,它永远不会溢出!但是,当然,你不再对实际运行的程序建模,而是对实际整数值进行推理;这可能是可以接受的,取决于您的问题域。谢谢您的回复!我编辑了我的问题并添加了一个示例。你能看一下吗?谢谢这里的解算器非常正确。与bvsub
/bvadd
等操作一起使用时的32位向量。;遵循常规的模运算规则。如果希望解算器将值视为实际整数,则应将其指定为整数,而不是位向量。请参见此处:对于这种情况,x==5和y==10个工作满足约束。有没有办法让解算器在执行算术运算时生成不会溢出的值?这当然是可能的;不幸的是,虽然没那么容易。请参阅我的扩展答案。
; Two 32-bit variables
(declare-fun x () (_ BitVec 32))
(declare-fun y () (_ BitVec 32))
; Zero-Extend them to 33-bits
(define-fun x33 () (_ BitVec 33) (concat #b0 x))
(define-fun y33 () (_ BitVec 33) (concat #b0 y))
; Add them
(define-fun extendedAdd () (_ BitVec 33) (bvadd x33 y33))
; Get the sign bit
(define-fun signBit () (_ BitVec 1) ((_ extract 32 32) extendedAdd))
; Assert that the addition won't overflow:
(assert (= signBit #b0))
; Regular addition result:
(define-fun addResult () (_ BitVec 32) ((_ extract 31 0) extendedAdd))
; Now you can use addResult as the result of x+y; and you'll
; be assured that this addition will never overflow
(check-sat)
(get-model)