diff --git a/crates/clarirs_py/src/ast/args.rs b/crates/clarirs_py/src/ast/args.rs index fee49df..ca1c4c8 100644 --- a/crates/clarirs_py/src/ast/args.rs +++ b/crates/clarirs_py/src/ast/args.rs @@ -95,9 +95,9 @@ impl ExtractPyArgs for BitVecOp<'static> { vec![BV::new(py, expr)?.into_any(), amount.to_object(py)] } BitVecOp::Extract(expr, end, start) => vec![ - BV::new(py, expr)?.into_any(), end.to_object(py), start.to_object(py), + BV::new(py, expr)?.into_any(), ], BitVecOp::Reverse(expr) => vec![BV::new(py, expr)?.into_any()], BitVecOp::FpToIEEEBV(expr) => vec![FP::new(py, expr)?.into_any()], diff --git a/crates/clarirs_py/src/ast/bv.rs b/crates/clarirs_py/src/ast/bv.rs index a942b1a..24f0cb0 100644 --- a/crates/clarirs_py/src/ast/bv.rs +++ b/crates/clarirs_py/src/ast/bv.rs @@ -137,7 +137,7 @@ impl BV { pub fn __add__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.add(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.add(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -148,7 +148,7 @@ impl BV { pub fn __sub__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.sub(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.sub(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -159,7 +159,7 @@ impl BV { pub fn __mul__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.mul(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.mul(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -170,7 +170,7 @@ impl BV { pub fn __truediv__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.udiv(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.udiv(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -181,7 +181,7 @@ impl BV { pub fn __floordiv__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.udiv(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.udiv(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -198,7 +198,7 @@ impl BV { // TODO: handle modulo BV::new( py, - &GLOBAL_CONTEXT.pow(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.pow(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -214,7 +214,7 @@ impl BV { pub fn __mod__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.urem(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.urem(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -225,21 +225,21 @@ impl BV { pub fn SDiv(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.sdiv(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.sdiv(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn SMod(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.srem(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.srem(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn __and__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.and(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.and(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -250,7 +250,7 @@ impl BV { pub fn __or__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.or(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.or(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -261,7 +261,7 @@ impl BV { pub fn __xor__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.xor(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.xor(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -272,7 +272,7 @@ impl BV { pub fn __lshift__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.shl(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.shl(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -283,7 +283,7 @@ impl BV { pub fn __rshift__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.ashr(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.ashr(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -294,7 +294,7 @@ impl BV { pub fn LShR(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.lshr(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.lshr(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -317,98 +317,98 @@ impl BV { pub fn __eq__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.eq_(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.eq_(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn __ne__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.neq(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.neq(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn __lt__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.ult(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.ult(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn __le__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.ule(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.ule(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn __gt__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.ugt(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.ugt(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn __ge__(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.uge(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.uge(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn ULT(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.ult(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.ult(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn ULE(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.ule(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.ule(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn UGT(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.ugt(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.ugt(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn UGE(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.uge(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.uge(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn SLT(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.slt(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.slt(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn SLE(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.sle(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.sle(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn SGT(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.sgt(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.sgt(&self.inner, &other.extract_like(py, self).get().inner)?, ) } pub fn SGE(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { Bool::new( py, - &GLOBAL_CONTEXT.sge(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.sge(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -427,7 +427,7 @@ impl BV { pub fn concat(&self, py: Python, other: CoerceBV) -> Result, ClaripyError> { BV::new( py, - &GLOBAL_CONTEXT.concat(&self.inner, &>::into(other))?, + &GLOBAL_CONTEXT.concat(&self.inner, &other.extract_like(py, self).get().inner)?, ) } @@ -509,35 +509,32 @@ pub fn BVV(py: Python, value: Bound, size: Option) -> Result, } macro_rules! binop { - ($name:ident, $context_method:ident, $return_type:ty, $lhs:ty, $rhs:ty) => { + ($name:ident, $context_method:ident, $ret:ty) => { #[pyfunction] - pub fn $name( - py: Python, - lhs: Bound<$lhs>, - rhs: Bound<$rhs>, - ) -> Result, ClaripyError> { - <$return_type>::new( + pub fn $name(py: Python, lhs: CoerceBV, rhs: CoerceBV) -> Result, ClaripyError> { + let (elhs, erhs) = CoerceBV::extract_pair(py, &lhs, &rhs); + <$ret>::new( py, - &GLOBAL_CONTEXT.$context_method(&lhs.get().inner, &rhs.get().inner)?, + &GLOBAL_CONTEXT.$context_method(&elhs.get().inner, &erhs.get().inner)?, ) } }; } -binop!(Add, add, BV, BV, BV); -binop!(Sub, sub, BV, BV, BV); -binop!(Mul, mul, BV, BV, BV); -binop!(UDiv, udiv, BV, BV, BV); -binop!(SDiv, sdiv, BV, BV, BV); -binop!(UMod, urem, BV, BV, BV); -binop!(SMod, srem, BV, BV, BV); -binop!(Pow, pow, BV, BV, BV); -binop!(ShL, shl, BV, BV, BV); -binop!(LShR, lshr, BV, BV, BV); -binop!(AShR, ashr, BV, BV, BV); -binop!(RotateLeft, rotate_left, BV, BV, BV); -binop!(RotateRight, rotate_right, BV, BV, BV); -binop!(Concat, concat, BV, BV, BV); +binop!(Add, add, BV); +binop!(Sub, sub, BV); +binop!(Mul, mul, BV); +binop!(UDiv, udiv, BV); +binop!(SDiv, sdiv, BV); +binop!(UMod, urem, BV); +binop!(SMod, srem, BV); +binop!(Pow, pow, BV); +binop!(ShL, shl, BV); +binop!(LShR, lshr, BV); +binop!(AShR, ashr, BV); +binop!(RotateLeft, rotate_left, BV); +binop!(RotateRight, rotate_right, BV); +binop!(Concat, concat, BV); #[pyfunction] pub fn Extract(py: Python, base: Bound, start: u32, end: u32) -> Result, ClaripyError> { @@ -559,29 +556,16 @@ pub fn Reverse(py: Python, base: Bound) -> Result, ClaripyError> { BV::new(py, &GLOBAL_CONTEXT.reverse(&base.get().inner)?) } -binop!(ULT, ult, Bool, BV, BV); -binop!(ULE, ule, Bool, BV, BV); -binop!(UGT, ugt, Bool, BV, BV); -binop!(UGE, uge, Bool, BV, BV); -binop!(SLT, slt, Bool, BV, BV); -binop!(SLE, sle, Bool, BV, BV); -binop!(SGT, sgt, Bool, BV, BV); -binop!(SGE, sge, Bool, BV, BV); -binop!(Eq_, eq_, Bool, BV, BV); -binop!(Neq, neq, Bool, BV, BV); - -#[pyfunction] -pub fn If( - py: Python, - cond: Bound, - then_: Bound, - else_: Bound, -) -> Result, ClaripyError> { - BV::new( - py, - &GLOBAL_CONTEXT.if_(&cond.get().inner, &then_.get().inner, &else_.get().inner)?, - ) -} +binop!(ULT, ult, Bool); +binop!(ULE, ule, Bool); +binop!(UGT, ugt, Bool); +binop!(UGE, uge, Bool); +binop!(SLT, slt, Bool); +binop!(SLE, sle, Bool); +binop!(SGT, sgt, Bool); +binop!(SGE, sge, Bool); +binop!(Eq_, eq_, Bool); +binop!(Neq, neq, Bool); pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> { m.add_class::()?; @@ -621,7 +605,7 @@ pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> { SGT, SGE, Eq_, - If, + super::If, ); Ok(()) diff --git a/crates/clarirs_py/src/ast/coerce.rs b/crates/clarirs_py/src/ast/coerce.rs index 7dd97f4..a617307 100644 --- a/crates/clarirs_py/src/ast/coerce.rs +++ b/crates/clarirs_py/src/ast/coerce.rs @@ -1,5 +1,7 @@ use std::str; +use clarirs_core::ast::bitvec::BitVecExt; + use crate::prelude::*; pub struct CoerceBool(pub Py); @@ -30,14 +32,56 @@ impl From for BoolAst<'static> { } } -pub struct CoerceBV(pub Py); +pub struct CoerceBV { + inner: Py, + coerced: bool, +} + +impl CoerceBV { + pub fn new(bv: Py) -> Self { + CoerceBV { + inner: bv, + coerced: false, + } + } + + pub fn new_coerced(bv: Py) -> Self { + CoerceBV { + inner: bv, + coerced: true, + } + } + + pub fn extract_like(&self, py: Python, like: &BV) -> Py { + let our_size = self.inner.get().inner.size(); + let like_size = like.inner.size(); + + if self.coerced && like_size != our_size { + if like_size > our_size { + self.inner.get().zero_extend(py, like_size).unwrap() + } else { + self.inner.get().Extract(py, like_size - 1, 0).unwrap() + } + } else { + self.inner.clone() + } + } + + pub fn extract_pair(py: Python, lhs: &CoerceBV, rhs: &CoerceBV) -> (Py, Py) { + match (lhs.coerced, rhs.coerced) { + (true, true) | (false, false) => (lhs.inner.clone(), rhs.inner.clone()), + (true, false) => (lhs.extract_like(py, rhs.inner.get()), rhs.inner.clone()), + (false, true) => (lhs.inner.clone(), rhs.extract_like(py, lhs.inner.get())), + } + } +} impl FromPyObject<'_> for CoerceBV { fn extract_bound(val: &Bound<'_, PyAny>) -> PyResult { if let Ok(bv_val) = val.downcast::() { - Ok(CoerceBV(bv_val.clone().unbind())) + Ok(CoerceBV::new(bv_val.clone().unbind())) } else if let Ok(bv_val) = val.extract::() { - Ok(CoerceBV( + Ok(CoerceBV::new_coerced( BV::new(val.py(), &GLOBAL_CONTEXT.bvv_prim(bv_val).unwrap()).unwrap(), )) } else { @@ -48,13 +92,13 @@ impl FromPyObject<'_> for CoerceBV { impl From for Py { fn from(val: CoerceBV) -> Self { - val.0 + val.inner } } impl From for BitVecAst<'static> { fn from(val: CoerceBV) -> Self { - val.0.get().inner.clone() + val.inner.get().inner.clone() } } diff --git a/crates/clarirs_py/src/ast/mod.rs b/crates/clarirs_py/src/ast/mod.rs index 68c5525..7cfe83d 100644 --- a/crates/clarirs_py/src/ast/mod.rs +++ b/crates/clarirs_py/src/ast/mod.rs @@ -44,7 +44,11 @@ macro_rules! define_binop { ($name:ident, $op:ident) => { #[pyfunction] #[allow(non_snake_case)] - pub fn $name(py: Python, a: Bound, b: Bound) -> Result, ClaripyError> { + pub fn $name( + py: Python, + a: Bound, + b: Bound, + ) -> Result, ClaripyError> { if let Ok(a_bool) = a.clone().into_any().downcast::() { if let Ok(b_bool) = b.clone().into_any().downcast::() { return Bool::new( @@ -61,8 +65,9 @@ macro_rules! define_binop { } else { panic!("mismatched types") } - } else if let Ok(a_bv) = a.clone().into_any().downcast::() { - if let Ok(b_bv) = b.clone().into_any().downcast::() { + } else if let Ok(a_bv) = a.clone().into_any().extract::() { + if let Ok(b_bv) = b.clone().into_any().extract::() { + let (a_bv, b_bv) = CoerceBV::extract_pair(py, &a_bv, &b_bv); return BV::new( py, &GLOBAL_CONTEXT.$op(&a_bv.get().inner, &b_bv.get().inner)?, @@ -93,16 +98,19 @@ define_binop!(Xor, xor); pub fn If( py: Python, cond: Bound, - then_: Bound, - else_: Bound, + then_: Bound, + else_: Bound, ) -> Result, ClaripyError> { - if let Ok(then_bv) = then_.clone().into_any().downcast::() { - if let Ok(else_bv) = else_.clone().into_any().downcast::() { - let then_bv = then_bv.get().inner.clone(); - let else_bv = else_bv.get().inner.clone(); + if let Ok(then_bv) = then_.clone().into_any().extract::() { + if let Ok(else_bv) = else_.clone().into_any().extract::() { + let (then_bv, else_bv) = CoerceBV::extract_pair(py, &then_bv, &else_bv); BV::new( py, - &GLOBAL_CONTEXT.if_(&cond.get().inner, &then_bv, &else_bv)?, + &GLOBAL_CONTEXT.if_( + &cond.get().inner, + &then_bv.get().inner, + &else_bv.get().inner, + )?, ) .map(|b| { b.into_any()