Beispiel #1
0
smt_astt
smt_convt::overflow_cast(const expr2tc &expr)
{
  // If in integer mode, this is completely pointless. Return false.
  if (int_encoding)
    return mk_smt_bool(false);

  const overflow_cast2t &ocast = to_overflow_cast2t(expr);
  unsigned int width = ocast.operand->type->get_width();
  unsigned int bits = ocast.bits;
  smt_sortt boolsort = boolean_sort;

  if (ocast.bits >= width || ocast.bits == 0) {
    std::cerr << "SMT conversion: overflow-typecast got wrong number of bits"
              << std::endl;
    abort();
  }

  // Basically: if it's positive in the first place, ensure all the top bits
  // are zero. If neg, then all the top are 1's /and/ the next bit, so that
  // it's considered negative in the next interpretation.

  constant_int2tc zero(ocast.operand->type, BigInt(0));
  lessthan2tc isnegexpr(ocast.operand, zero);
  smt_astt isneg = convert_ast(isnegexpr);
  smt_astt orig_val = convert_ast(ocast.operand);

  // Difference bits
  unsigned int pos_zero_bits = width - bits;
  unsigned int neg_one_bits = (width - bits) + 1;

  smt_sortt pos_zero_bits_sort =
    mk_sort(SMT_SORT_BV, pos_zero_bits, false);
  smt_sortt neg_one_bits_sort =
    mk_sort(SMT_SORT_BV, neg_one_bits, false);

  smt_astt pos_bits = mk_smt_bvint(BigInt(0), false, pos_zero_bits);
  smt_astt neg_bits = mk_smt_bvint(BigInt((1 << neg_one_bits) - 1),
                                         false, neg_one_bits);

  smt_astt pos_sel = mk_extract(orig_val, width - 1,
                                      width - pos_zero_bits,
                                      pos_zero_bits_sort);
  smt_astt neg_sel = mk_extract(orig_val, width - 1,
                                      width - neg_one_bits,
                                      neg_one_bits_sort);

  smt_astt pos_eq = mk_func_app(boolsort, SMT_FUNC_EQ, pos_bits, pos_sel);
  smt_astt neg_eq = mk_func_app(boolsort, SMT_FUNC_EQ, neg_bits, neg_sel);

  // isneg -> neg_eq, !isneg -> pos_eq
  smt_astt notisneg = mk_func_app(boolsort, SMT_FUNC_NOT, &isneg, 1);
  smt_astt c1 = mk_func_app(boolsort, SMT_FUNC_IMPLIES, isneg, neg_eq);
  smt_astt c2 = mk_func_app(boolsort, SMT_FUNC_IMPLIES, notisneg, pos_eq);

  smt_astt nooverflow = mk_func_app(boolsort, SMT_FUNC_AND, c1, c2);
  return mk_func_app(boolsort, SMT_FUNC_NOT, &nooverflow, 1);
}
Beispiel #2
0
smt_astt 
smt_convt::overflow_neg(const expr2tc &expr)
{
  // If in integer mode, this is completely pointless. Return false.
  if (int_encoding)
    return mk_smt_bool(false);

  // Single failure mode: MIN_INT can't be neg'd
  const overflow_neg2t &neg = to_overflow_neg2t(expr);
  unsigned int width = neg.operand->type->get_width();

  constant_int2tc min_int(neg.operand->type, BigInt(1 << (width - 1)));
  equality2tc val(neg.operand, min_int);
  return convert_ast(val);
}
Beispiel #3
0
smt_astt 
smt_convt::overflow_arith(const expr2tc &expr)
{
  // If in integer mode, this is completely pointless. Return false.
  if (int_encoding)
    return mk_smt_bool(false);

  const overflow2t &overflow = to_overflow2t(expr);
  const arith_2ops &opers = static_cast<const arith_2ops &>(*overflow.operand);
  assert(opers.side_1->type == opers.side_2->type);
  constant_int2tc zero(opers.side_1->type, BigInt(0));
  lessthan2tc op1neg(opers.side_1, zero);
  lessthan2tc op2neg(opers.side_2, zero);

  equality2tc op1iszero(opers.side_1, zero);
  equality2tc op2iszero(opers.side_2, zero);
  or2tc containszero(op1iszero, op2iszero);

  // Guess whether we're performing a signed or unsigned comparison.
  bool is_signed = (is_signedbv_type(opers.side_1) ||
                    is_signedbv_type(opers.side_2));

  if (is_add2t(overflow.operand)) {
    if (is_signed) {
      // Two cases: pos/pos, and neg/neg, which can over and underflow resp.
      // In pos/neg cases, no overflow or underflow is possible, for any value.
      constant_int2tc zero(opers.side_1->type, BigInt(0));

      lessthan2tc op1pos(zero, opers.side_1);
      lessthan2tc op2pos(zero, opers.side_2);
      and2tc both_pos(op1pos, op2pos);

      not2tc negop1(op1pos);
      not2tc negop2(op2pos);
      and2tc both_neg(negop1, negop2);

      implies2tc nooverflow(both_pos,
                            greaterthanequal2tc(overflow.operand, zero));
      implies2tc nounderflow(both_neg,
                            lessthanequal2tc(overflow.operand, zero));
      return convert_ast(not2tc(and2tc(nooverflow, nounderflow)));
    } else {
      // Just ensure the result is >= both operands.
      greaterthanequal2tc ge1(overflow.operand, opers.side_1);
      greaterthanequal2tc ge2(overflow.operand, opers.side_2);
      and2tc res(ge1, ge2);
      not2tc inv(res);
      return convert_ast(inv);
    }
  } else if (is_sub2t(overflow.operand)) {
    if (is_signed) {
      // Convert to be an addition
      neg2tc negop2(opers.side_2->type, opers.side_2);
      add2tc anadd(opers.side_1->type, opers.side_1, negop2);
      expr2tc add_overflows(new overflow2t(anadd));

      // Corner case: subtracting MIN_INT from many things overflows. The result
      // should always be positive.
      constant_int2tc zero(opers.side_1->type, BigInt(0));
      uint64_t topbit = 1ULL << (opers.side_1->type->get_width() - 1);
      constant_int2tc min_int(opers.side_1->type, BigInt(topbit));
      equality2tc is_min_int(min_int, opers.side_2);
      implies2tc imp(is_min_int, greaterthan2tc(overflow.operand, zero));
      return convert_ast(or2tc(add_overflows, is_min_int));
    } else {
      // Just ensure the result is >= the operands.
      lessthanequal2tc le1(overflow.operand, opers.side_1);
      lessthanequal2tc le2(overflow.operand, opers.side_2);
      and2tc res(le1, le2);
      not2tc inv(res);
      return convert_ast(inv);
    }
  } else {
    assert(is_mul2t(overflow.operand) && "unexpected overflow_arith operand");

    // Zero extend; multiply; Make a decision based on the top half.
    unsigned int sz = zero->type->get_width();
    smt_sortt boolsort = boolean_sort;
    smt_sortt normalsort = mk_sort(SMT_SORT_BV, sz, false);
    smt_sortt bigsort = mk_sort(SMT_SORT_BV, sz * 2, false);

    // All one bit vector is tricky, might be 64 bits wide for all we know.
    constant_int2tc allonesexpr(zero->type, BigInt((sz == 64)
                                                 ? 0xFFFFFFFFFFFFFFFFULL
                                                 : ((1ULL << sz) - 1)));
    smt_astt allonesvector = convert_ast(allonesexpr);

    smt_astt arg1_ext, arg2_ext;
    if (is_signed) {
      // sign extend top bits.
      arg1_ext = convert_ast(opers.side_1);
      arg1_ext = convert_sign_ext(arg1_ext, bigsort, sz - 1, sz);
      arg2_ext = convert_ast(opers.side_2);
      arg2_ext = convert_sign_ext(arg2_ext, bigsort, sz - 1, sz);
    } else {
      // Zero extend the top parts
      arg1_ext = convert_ast(opers.side_1);
      arg1_ext = convert_zero_ext(arg1_ext, bigsort, sz);
      arg2_ext = convert_ast(opers.side_2);
      arg2_ext = convert_zero_ext(arg2_ext, bigsort, sz);
    }

    smt_astt result = mk_func_app(bigsort, SMT_FUNC_BVMUL, arg1_ext, arg2_ext);

    // Extract top half.
    smt_astt toppart = mk_extract(result, (sz * 2) - 1, sz, normalsort);

    if (is_signed) {
      // It should either be zero or all one's; which depends on what
      // configuration of signs it had. If both pos / both neg, then the top
      // should all be zeros, otherwise all ones. Implement with xor.
      smt_astt op1neg_ast = convert_ast(op1neg);
      smt_astt op2neg_ast = convert_ast(op2neg);
      smt_astt allonescond =
        mk_func_app(boolsort, SMT_FUNC_XOR, op1neg_ast, op2neg_ast);
      smt_astt zerovector = convert_ast(zero);

      smt_astt initial_switch =
        mk_func_app(normalsort, SMT_FUNC_ITE, allonescond,
                    allonesvector, zerovector);

      // either value being zero means the top must be zero.
      smt_astt contains_zero_ast = convert_ast(containszero);
      smt_astt second_switch = mk_func_app(normalsort, SMT_FUNC_ITE,
                                           contains_zero_ast,
                                           zerovector,
                                           initial_switch);

      smt_astt is_eq =
        mk_func_app(boolsort, SMT_FUNC_EQ, second_switch, toppart);
      return mk_func_app(boolsort, SMT_FUNC_NOT, &is_eq, 1);
    } else {
      // It should be zero; if not, overflow
      smt_astt iseq =
        mk_func_app(boolsort, SMT_FUNC_EQ, toppart, convert_ast(zero));
      return mk_func_app(boolsort, SMT_FUNC_NOT, &iseq, 1);
    }
  }

  return NULL;
}
Beispiel #4
0
smt_astt 
smt_convt::convert_byte_update(const expr2tc &expr)
{
  const byte_update2t &data = to_byte_update2t(expr);

  assert(is_scalar_type(data.source_value) && "Byte update only works on "
         "scalar variables now");

  if (!is_constant_int2t(data.source_offset)) {
    expr2tc source = data.source_value;
    unsigned int src_width = source->type->get_width();
    if (!is_bv_type(source))
      source = typecast2tc(get_uint_type(src_width), source);

    expr2tc offs = data.source_offset;

    // Endian-ness: if we're in non-"native" endian-ness mode, then flip the
    // offset distance. The rest of these calculations will still apply.
    if (data.big_endian) {
      auto data_size = type_byte_size(*source->type);
      constant_int2tc data_size_expr(source->type, data_size - 1);
      sub2tc sub(source->type, data_size_expr, offs);
      offs = sub;
    }

    if (offs->type->get_width() != src_width)
      offs = typecast2tc(get_uint_type(src_width), offs);

    expr2tc update = data.update_value;
    if (update->type->get_width() != src_width)
      update = typecast2tc(get_uint_type(src_width), update);

    // The approach: mask, shift and or. XXX, byte order?
    // Massively inefficient.

    expr2tc eight = constant_int2tc(get_uint_type(src_width), BigInt(8));
    expr2tc effs = constant_int2tc(eight->type, BigInt(255));
    offs = mul2tc(eight->type, offs, eight);

    expr2tc shl = shl2tc(offs->type, effs, offs);
    expr2tc noteffs = bitnot2tc(effs->type, shl);
    source = bitand2tc(source->type, source, noteffs);

    expr2tc shl2 = shl2tc(offs->type, update, offs);
    return convert_ast(bitor2tc(offs->type, shl2, source));
  }

  // We are merging two values: an 8 bit update value, and a larger source
  // value that we will have to merge it into. Start off by collecting
  // information about the source values and their widths.
  assert(is_number_type(data.source_value->type) && "Byte update of unsupported data type");

  smt_astt value, src_value;
  unsigned int width_op0, width_op2, src_offset;

  value = convert_ast(data.update_value);
  src_value = convert_ast(data.source_value);

  width_op2 = data.update_value->type->get_width();
  width_op0 = data.source_value->type->get_width();
  src_offset = to_constant_int2t(data.source_offset).constant_value.to_ulong();

  // Flip location if we're in big-endian mode
  if (data.big_endian) {
    unsigned int data_size =
      type_byte_size(*data.source_value->type).to_ulong() - 1;
    src_offset = data_size - src_offset;
  }

  if (int_encoding) {
    std::cerr << "Can't byte update in integer mode; rerun in bitvector mode"
              << std::endl;
    abort();
  }

  // Assertion some of our assumptions, which broadly mean that we'll only work
  // on bytes that are going into non-byte words
  assert(width_op2 == 8 && "Can't byte update non-byte operations");
  assert(width_op2 != width_op0 && "Can't byte update bytes, sorry");

  smt_astt top, middle, bottom;

  // Build in three parts: the most significant bits, any in the middle, and
  // the bottom, of the reconstructed / merged output. There might not be a
  // middle if the update byte is at the top or the bottom.
  unsigned int top_of_update = (8 * src_offset) + 8;
  unsigned int bottom_of_update = (8 * src_offset);

  if (top_of_update == width_op0) {
    top = value;
  } else {
    smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - top_of_update, false);
    top = mk_extract(src_value, width_op0 - 1, top_of_update, s);
  }

  if (top == value) {
    middle = NULL;
  } else {
    middle = value;
  }

  if (src_offset == 0) {
    middle = NULL;
    bottom = value;
  } else {
    smt_sortt s = mk_sort(SMT_SORT_BV, bottom_of_update, false);
    bottom = mk_extract(src_value, bottom_of_update - 1, 0, s);
  }

  // Concatenate the top and bottom, and possible middle, together.
  smt_astt concat;

  if (middle != NULL) {
    smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - bottom_of_update, false);
    concat = mk_func_app(s, SMT_FUNC_CONCAT, top, middle);
  } else {
    concat = top;
  }

  return mk_func_app(src_value->sort, SMT_FUNC_CONCAT, concat, bottom);
}
Beispiel #5
0
smt_astt 
smt_convt::convert_byte_extract(const expr2tc &expr)
{
  const byte_extract2t &data = to_byte_extract2t(expr);

  assert(is_scalar_type(data.source_value) && "Byte extract now only works on "
         "scalar variables");
  if (!is_constant_int2t(data.source_offset)) {
    expr2tc source = data.source_value;
    unsigned int src_width = source->type->get_width();
    if (!is_bv_type(source)) {
      source = typecast2tc(get_uint_type(src_width), source);
    }

    // The approach: the argument is now a bitvector. Just shift it the
    // appropriate amount, according to the source offset, and select out the
    // bottom byte.
    expr2tc offs = data.source_offset;

    // Endian-ness: if we're in non-"native" endian-ness mode, then flip the
    // offset distance. The rest of these calculations will still apply.
    if (data.big_endian) {
      auto data_size = type_byte_size(*source->type);
      constant_int2tc data_size_expr(source->type, data_size - 1);
      sub2tc sub(source->type, data_size_expr, offs);
      offs = sub;
    }

    if (offs->type->get_width() != src_width)
      // Z3 requires these two arguments to be the same width
      offs = typecast2tc(source->type, data.source_offset);

    lshr2tc shr(source->type, source, offs);
    smt_astt ext = convert_ast(shr);
    smt_astt res = mk_extract(ext, 7, 0, convert_sort(get_uint8_type()));
    return res;
  }

  const constant_int2t &intref = to_constant_int2t(data.source_offset);

  unsigned width;
  width = data.source_value->type->get_width();

  uint64_t upper, lower;
  if (!data.big_endian) {
    upper = ((intref.constant_value.to_long() + 1) * 8) - 1; //((i+1)*w)-1;
    lower = intref.constant_value.to_long() * 8; //i*w;
  } else {
    uint64_t max = width - 1;
    upper = max - (intref.constant_value.to_long() * 8); //max-(i*w);
    lower = max - ((intref.constant_value.to_long() + 1) * 8 - 1); //max-((i+1)*w-1);
  }

  smt_astt source = convert_ast(data.source_value);;

  if (int_encoding) {
    std::cerr << "Refusing to byte extract in integer mode; re-run in "
                 "bitvector mode" << std::endl;
    abort();
  } else {
    if (is_bv_type(data.source_value)) {
      ;
    } else if (is_fixedbv_type(data.source_value)) {
      ;
    } else if (is_bool_type(data.source_value)) {
      // We cdan extract a byte from a bool -- zero or one.
      typecast2tc cast(get_uint8_type(), data.source_value);
      source = convert_ast(cast);
    } else {
      std::cerr << "Unrecognized type in operand to byte extract." << std::endl;
      data.dump();
      abort();
    }

    unsigned int sort_sz = data.source_value->type->get_width();
    if (sort_sz <= upper) {
      smt_sortt s = mk_sort(SMT_SORT_BV, 8, false);
      return mk_smt_symbol("out_of_bounds_byte_extract", s);
    } else {
      return mk_extract(source, upper, lower, convert_sort(expr->type));
    }
  }
}