/// add axioms stating that if two strings are equal then their hash codes are
/// equals
/// \par parameters: function application with a string argument
/// \return a integer expression corresponding to the hash code of the string
exprt string_constraint_generatort::add_axioms_for_hash_code(
  const function_application_exprt &f)
{
  string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]);
  typet return_type=f.type();
  typet index_type=str.length().type();

  // initialisation of the missing pool variable
  std::map<irep_idt, string_exprt>::iterator it;
  for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++)
    if(hash.find(it->second)==hash.end())
      hash[it->second]=fresh_symbol("hash", return_type);

  // for each string s. either:
  //   c1: hash(str)=hash(s)
  //   c2: |str|!=|s|
  //   c3: (|str|==|s| &&exists i<|s|. s[i]!=str[i])

  // WARNING: the specification may be incomplete
  for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++)
  {
    symbol_exprt i=fresh_exist_index("index_hash", index_type);
    equal_exprt c1(hash[it->second], hash[str]);
    not_exprt c2(equal_exprt(it->second.length(), str.length()));
    and_exprt c3(
      equal_exprt(it->second.length(), str.length()),
      and_exprt(
        not_exprt(equal_exprt(str[i], it->second[i])),
        and_exprt(
          str.axiom_for_is_strictly_longer_than(i),
          axiom_for_is_positive_index(i))));
    axioms.push_back(or_exprt(c1, or_exprt(c2, c3)));
  }
  return hash[str];
}
Exemple #2
0
void equality_domaint::make_not_post_constraints(
  valuet &_value,
  exprt::operandst &cond_exprs)
{
  assert(*e_it<templ.size());
  cond_exprs.resize(1);
  if(check_dis)
  {
    cond_exprs[0]=get_post_not_disequ_constraint(*e_it);
    return;
  }
  const template_rowt &templ_row=templ[*e_it];
  if(templ_row.kind==IN)
  {
    cond_exprs[0]=true_exprt();
    return;
  }

  const var_pairt &vv=templ_row.var_pair;
  exprt c=
    and_exprt(
      templ_row.aux_expr,
      not_exprt(
        implies_exprt(
          templ_row.post_guard,
          equal_exprt(vv.first, vv.second))));
  rename(c);
  cond_exprs[0]=c;
}
Exemple #3
0
void summarizer_bwt::collect_postconditions(
  const function_namet &function_name,
  const local_SSAt &SSA, 
  const summaryt &summary,
  exprt::operandst &postconditions,
  bool sufficient)
{
  for(local_SSAt::nodest::const_iterator n_it = SSA.nodes.begin();
      n_it != SSA.nodes.end(); n_it++)
  {
    for(local_SSAt::nodet::assertionst::const_iterator 
	  a_it = n_it->assertions.begin();
	a_it != n_it->assertions.end(); a_it++)
    {
      postconditions.push_back(*a_it);
    }
  }
  /*  if(termination) 
  {
    if(!summary.termination_argument.is_nil()) 
      postconditions.push_back(summary.termination_argument);
      }*/

  exprt guard = SSA.guard_symbol(--SSA.goto_function.body.instructions.end());
  if(!sufficient) 
    postconditions.push_back(and_exprt(guard,summary.bw_postcondition));
  else
    postconditions.push_back(implies_exprt(guard,summary.bw_postcondition));
}
exprt string_constraint_generatort::add_axioms_for_last_index_of_string(
  const string_exprt &str,
  const string_exprt &substring,
  const exprt &from_index)
{
  const typet &index_type=str.length().type();
  symbol_exprt offset=fresh_exist_index("index_of", index_type);
  symbol_exprt contains=fresh_boolean("contains_substring");

  // We add axioms:
  // a1 : contains => |substring| >= length &&offset <= from_index
  // a2 : !contains => offset=-1
  // a3 : forall 0 <= witness<substring.length,
  //        contains => str[witness+offset]=substring[witness]

  implies_exprt a1(
    contains,
    and_exprt(
      str.axiom_for_is_longer_than(plus_exprt(substring.length(), offset)),
      binary_relation_exprt(offset, ID_le, from_index)));
  axioms.push_back(a1);

  implies_exprt a2(
    not_exprt(contains),
    equal_exprt(offset, from_integer(-1, index_type)));
  axioms.push_back(a2);

  symbol_exprt qvar=fresh_univ_index("QA_index_of_string", index_type);
  equal_exprt constr3(str[plus_exprt(qvar, offset)], substring[qvar]);
  string_constraintt a3(qvar, substring.length(), contains, constr3);
  axioms.push_back(a3);

  return offset;
}
Exemple #5
0
exprt local_SSAt::edge_guard(locationt from, locationt to) const
{
  if(from->is_goto())
  {
    // big question: taken or not taken?
    if(to==from->get_target())
      return and_exprt(guard_symbol(from), cond_symbol(from));
    else
      return and_exprt(guard_symbol(from), not_exprt(cond_symbol(from)));
  }
  else if(from->is_assume())
  {
    return and_exprt(guard_symbol(from), cond_symbol(from));
  }
  else
    return guard_symbol(from);
}
/// add axioms stating that the return value for two equal string should be the
/// same
/// \par parameters: function application with one string argument
/// \return a string expression
symbol_exprt string_constraint_generatort::add_axioms_for_intern(
  const function_application_exprt &f)
{
  string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]);
  const typet &return_type=f.type();
  typet index_type=str.length().type();

  // initialisation of the missing pool variable
  std::map<irep_idt, string_exprt>::iterator it;
  for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++)
    if(pool.find(it->second)==pool.end())
      pool[it->second]=fresh_symbol("pool", return_type);

  // intern(str)=s_0 || s_1 || ...
  // for each string s.
  //    intern(str)=intern(s) || |str|!=|s|
  //    || (|str|==|s| &&exists i<|s|. s[i]!=str[i])

  exprt disj=false_exprt();
  for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++)
    disj=or_exprt(
      disj, equal_exprt(pool[str], symbol_exprt(it->first, return_type)));

  axioms.push_back(disj);


  // WARNING: the specification may be incomplete or incorrect
  for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++)
    if(it->second!=str)
    {
      symbol_exprt i=fresh_exist_index("index_intern", index_type);
      axioms.push_back(
        or_exprt(
          equal_exprt(pool[it->second], pool[str]),
          or_exprt(
            not_exprt(str.axiom_for_has_same_length_as(it->second)),
            and_exprt(
              str.axiom_for_has_same_length_as(it->second),
              and_exprt(
                not_exprt(equal_exprt(str[i], it->second[i])),
                and_exprt(str.axiom_for_is_strictly_longer_than(i),
                          axiom_for_is_positive_index(i)))))));
    }

  return pool[str];
}
exprt string_constraint_generatort::add_axioms_for_last_index_of(
  const string_exprt &str, const exprt &c, const exprt &from_index)
{
  const refined_string_typet &ref_type=to_refined_string_type(str.type());
  const typet &index_type=ref_type.get_index_type();
  symbol_exprt index=fresh_exist_index("last_index_of", index_type);
  symbol_exprt contains=fresh_boolean("contains_in_last_index_of");

  // We add axioms:
  // a1 : -1 <= i <= from_index
  // a2 : (i=-1 <=> !contains)
  // a3 : (contains => i <= from_index &&s[i]=c)
  // a4 : forall n. i+1 <= n < from_index +1 &&contains => s[n]!=c
  // a5 : forall m. 0 <= m < from_index +1 &&!contains => s[m]!=c

  exprt index1=from_integer(1, index_type);
  exprt minus1=from_integer(-1, index_type);
  exprt from_index_plus_one=plus_exprt(from_index, index1);
  and_exprt a1(
    binary_relation_exprt(index, ID_ge, minus1),
    binary_relation_exprt(index, ID_lt, from_index_plus_one));
  axioms.push_back(a1);

  equal_exprt a2(not_exprt(contains), equal_exprt(index, minus1));
  axioms.push_back(a2);

  implies_exprt a3(
    contains,
    and_exprt(
      binary_relation_exprt(from_index, ID_ge, index),
      equal_exprt(str[index], c)));
  axioms.push_back(a3);

  symbol_exprt n=fresh_univ_index("QA_last_index_of", index_type);
  string_constraintt a4(
    n,
    plus_exprt(index, index1),
    from_index_plus_one,
    contains,
    not_exprt(equal_exprt(str[n], c)));
  axioms.push_back(a4);

  symbol_exprt m=fresh_univ_index("QA_last_index_of", index_type);
  string_constraintt a5(
    m,
    from_index_plus_one,
    not_exprt(contains),
    not_exprt(equal_exprt(str[m], c)));
  axioms.push_back(a5);

  return index;
}
Exemple #8
0
void predabs_domaint::make_not_post_constraints(
  const templ_valuet &value,
  exprt::operandst &cond_exprs)
{
  assert(value.size()==templ.size());
  cond_exprs.resize(templ.size());

  exprt::operandst c;
  for(std::size_t row=0; row<templ.size(); row++)
  {
    cond_exprs[row]=and_exprt(
      templ[row].aux_expr,
      not_exprt(get_row_post_constraint(row, value)));
  }
}
/// add axioms corresponding to the String.equalsIgnoreCase java function
/// \par parameters: function application with two string arguments
/// \return a Boolean expression
exprt string_constraint_generatort::add_axioms_for_equals_ignore_case(
  const function_application_exprt &f)
{
  assert(f.type()==bool_typet() || f.type().id()==ID_c_bool);

  symbol_exprt eq=fresh_boolean("equal_ignore_case");
  typecast_exprt tc_eq(eq, f.type());
  string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]);
  string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]);
  typet char_type=to_refined_string_type(s1.type()).get_char_type();
  exprt char_a=constant_char('a', char_type);
  exprt char_A=constant_char('A', char_type);
  exprt char_Z=constant_char('Z', char_type);
  typet index_type=s1.length().type();

  // We add axioms:
  // a1 : eq => |s1|=|s2|
  // a2 : forall qvar, 0<=qvar<|s1|,
  //  eq => char_equal_ignore_case(s1[qvar],s2[qvar]);
  // a3 : !eq => |s1|!=s2 || (0 <=witness<|s1| &&!char_equal_ignore_case)

  implies_exprt a1(eq, s1.axiom_for_has_same_length_as(s2));
  axioms.push_back(a1);

  symbol_exprt qvar=fresh_univ_index("QA_equal_ignore_case", index_type);
  exprt constr2=character_equals_ignore_case(
    s1[qvar], s2[qvar], char_a, char_A, char_Z);
  string_constraintt a2(qvar, s1.length(), eq, constr2);
  axioms.push_back(a2);

  symbol_exprt witness=fresh_exist_index(
    "witness_unequal_ignore_case", index_type);
  exprt zero=from_integer(0, witness.type());
  and_exprt bound_witness(
    binary_relation_exprt(witness, ID_lt, s1.length()),
    binary_relation_exprt(witness, ID_ge, zero));
  exprt witness_eq=character_equals_ignore_case(
    s1[witness], s2[witness], char_a, char_A, char_Z);
  not_exprt witness_diff(witness_eq);
  implies_exprt a3(
    not_exprt(eq),
    or_exprt(
      notequal_exprt(s1.length(), s2.length()),
      and_exprt(bound_witness, witness_diff)));
  axioms.push_back(a3);

  return tc_eq;
}
void heap_tpolyhedra_domaint::project_on_vars(
  domaint::valuet &value,
  const domaint::var_sett &vars,
  exprt &result)
{
  heap_tpolyhedra_valuet &v=static_cast<heap_tpolyhedra_valuet &>(value);

  exprt heap_result;
  heap_domain.project_on_vars(v.heap_value, vars, heap_result);
  exprt tpolyhedra_result;
  polyhedra_domain.project_on_vars(v.tpolyhedra_value, vars, tpolyhedra_result);

  result=heap_result;
  if(tpolyhedra_result!=true_exprt())
    result=and_exprt(result, tpolyhedra_result);
}
exprt string_constraint_generatort::add_axioms_for_index_of(
  const string_exprt &str, const exprt &c, const exprt &from_index)
{
  const typet &index_type=str.length().type();
  symbol_exprt index=fresh_exist_index("index_of", index_type);
  symbol_exprt contains=fresh_boolean("contains_in_index_of");

  // We add axioms:
  // a1 : -1 <= index<|str|
  // a2 : !contains <=> index=-1
  // a3 : contains => from_index<=index&&str[index]=c
  // a4 : forall n, from_index<=n<index. contains => str[n]!=c
  // a5 : forall m, from_index<=n<|str|. !contains => str[m]!=c

  exprt minus1=from_integer(-1, index_type);
  and_exprt a1(
    binary_relation_exprt(index, ID_ge, minus1),
    binary_relation_exprt(index, ID_lt, str.length()));
  axioms.push_back(a1);

  equal_exprt a2(not_exprt(contains), equal_exprt(index, minus1));
  axioms.push_back(a2);

  implies_exprt a3(
    contains,
    and_exprt(
      binary_relation_exprt(from_index, ID_le, index),
      equal_exprt(str[index], c)));
  axioms.push_back(a3);

  symbol_exprt n=fresh_univ_index("QA_index_of", index_type);
  string_constraintt a4(
    n, from_index, index, contains, not_exprt(equal_exprt(str[n], c)));
  axioms.push_back(a4);

  symbol_exprt m=fresh_univ_index("QA_index_of", index_type);
  string_constraintt a5(
    m,
    from_index,
    str.length(),
    not_exprt(contains),
    not_exprt(equal_exprt(str[m], c)));
  axioms.push_back(a5);

  return index;
}
Exemple #12
0
exprt equality_domaint::get_post_not_disequ_constraint(unsigned index)
{
  assert(index<templ.size());
  const template_rowt &templ_row=templ[index];
  if(templ_row.kind==IN)
    return true_exprt();

  const var_pairt &vv=templ_row.var_pair;
  exprt c=
    and_exprt(
      templ_row.aux_expr,
      not_exprt(
        implies_exprt(
          templ_row.post_guard,
          notequal_exprt(vv.first, vv.second))));
  rename(c);
  return c;
}
Exemple #13
0
const exprt qbf_squolem_coret::f_get_dnf(WitnessStack *wsp)
{
  Clause *p=wsp->posWits;

  if(!p) return exprt(ID_false, typet(ID_bool));

  exprt::operandst operands;

  while(p!=NULL)
  {
    exprt cube=and_exprt();

    for(unsigned i=0; i<p->size; i++)
    {
      const Literal &lit=p->literals[i];
      exprt subf = f_get(literalt(var(lit), !isPositive(lit)));
      if(find(cube.operands().begin(), cube.operands().end(), subf)==
         cube.operands().end())
        cube.move_to_operands(subf);

      simplify_extractbits(cube);
    }

    if(cube.operands().empty())
      cube=true_exprt();
    else if(cube.operands().size()==1)
    {
      const exprt tmp=cube.op0();
      cube=tmp;
    }

    #if 0
    std::cout << "CUBE: " << cube << std::endl;
    #endif

    operands.push_back(cube);

    p=p->next;
  }

  return or_exprt(operands);
}
Exemple #14
0
const exprt qbf_squolem_coret::f_get_cnf(WitnessStack *wsp)
{
  Clause *p=wsp->negWits;

  if(!p) return exprt(ID_true, typet(ID_bool));

  exprt::operandst operands;

  while(p!=NULL)
  {
    exprt clause=or_exprt();

    for(unsigned i=0; i<p->size; i++)
    {
      const Literal &lit=p->literals[i];
      exprt subf = f_get(literalt(var(lit), isPositive(lit))); // negated!
      if(find(clause.operands().begin(), clause.operands().end(), subf)==
         clause.operands().end())
        clause.move_to_operands(subf);
    }

    if(clause.operands().empty())
      clause=false_exprt();
    else if(clause.operands().size()==1)
    {
      const exprt tmp=clause.op0();
      clause=tmp;
    }

    #if 0
    std::cout << "CLAUSE: " << clause << std::endl;
    #endif

    operands.push_back(clause);

    p=p->next;
  }

  return and_exprt(operands);
}
Exemple #15
0
bool polynomial_acceleratort::accelerate(patht &loop,
    path_acceleratort &accelerator) {
  goto_programt::instructionst body;
  accelerator.clear();

  for (patht::iterator it = loop.begin();
       it != loop.end();
       ++it) {
    body.push_back(*(it->loc));
  }

  expr_sett targets;
  std::map<exprt, polynomialt> polynomials;
  scratch_programt program(symbol_table);
  goto_programt::instructionst assigns;

  utils.find_modified(body, targets);

#ifdef DEBUG
  std::cout << "Polynomial accelerating program:" << std::endl;

  for (goto_programt::instructionst::iterator it = body.begin();
       it != body.end();
       ++it) {
    program.output_instruction(ns, "scratch", std::cout, it);
  }

  std::cout << "Modified:" << std::endl;

  for (expr_sett::iterator it = targets.begin();
       it != targets.end();
       ++it) {
    std::cout << expr2c(*it, ns) << std::endl;
  }
#endif

  for (goto_programt::instructionst::iterator it = body.begin();
       it != body.end();
       ++it) {
    if (it->is_assign() || it->is_decl()) {
      assigns.push_back(*it);
    }
  }

  if (loop_counter.is_nil()) {
    symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter",
        unsignedbv_typet(POLY_WIDTH));
    loop_counter = loop_sym.symbol_expr();
  }

  for (expr_sett::iterator it = targets.begin();
       it != targets.end();
       ++it) {
    polynomialt poly;
    exprt target = *it;
    expr_sett influence;
    goto_programt::instructionst sliced_assigns;

    if (target.type() == bool_typet()) {
      // Hack: don't accelerate booleans.
      continue;
    }

    cone_of_influence(assigns, target, sliced_assigns, influence);

    if (influence.find(target) == influence.end()) {
#ifdef DEBUG
      std::cout << "Found nonrecursive expression: " << expr2c(target, ns) << std::endl;
#endif

      nonrecursive.insert(target);
      continue;
    }

    if (target.id() == ID_index ||
        target.id() == ID_dereference) {
      // We can't accelerate a recursive indirect access...
      accelerator.dirty_vars.insert(target);
      continue;
    }

    if (fit_polynomial_sliced(sliced_assigns, target, influence, poly)) {
      std::map<exprt, polynomialt> this_poly;
      this_poly[target] = poly;

      if (check_inductive(this_poly, assigns)) {
        polynomials.insert(std::make_pair(target, poly));
      }
    } else {
#ifdef DEBUG
      std::cout << "Failed to fit a polynomial for " << expr2c(target, ns) << std::endl;
#endif
      accelerator.dirty_vars.insert(*it);
    }
  }

  if (polynomials.empty()) {
    //return false;
  }

  /*
  if (!utils.check_inductive(polynomials, assigns)) {
    // They're not inductive :-(
    return false;
  }
  */

  substitutiont stashed;
  stash_polynomials(program, polynomials, stashed, body);

  exprt guard;
  exprt guard_last;

  bool path_is_monotone;
  
  try {
    path_is_monotone = utils.do_assumptions(polynomials, loop, guard);
  } catch (std::string s) {
    // Couldn't do WP.
    std::cout << "Assumptions error: " << s << std::endl;
    return false;
  }

  guard_last = guard;

  for (std::map<exprt, polynomialt>::iterator it = polynomials.begin();
       it != polynomials.end();
       ++it) {
    replace_expr(it->first, it->second.to_expr(), guard_last);
  }

  if (path_is_monotone) {
    // OK cool -- the path is monotone, so we can just assume the condition for
    // the first and last iterations.
    replace_expr(loop_counter,
                 minus_exprt(loop_counter, from_integer(1, loop_counter.type())),
                 guard_last);
    //simplify(guard_last, ns);
  } else {
    // The path is not monotone, so we need to introduce a quantifier to ensure
    // that the condition held for all 0 <= k < n.
    symbolt k_sym = utils.fresh_symbol("polynomial::k", unsignedbv_typet(POLY_WIDTH));
    exprt k = k_sym.symbol_expr();

    exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k),
                              binary_relation_exprt(k, "<", loop_counter));
    replace_expr(loop_counter, k, guard_last);

    implies_exprt implies(k_bound, guard_last);
    //simplify(implies, ns);

    exprt forall(ID_forall);
    forall.type() = bool_typet();
    forall.copy_to_operands(k);
    forall.copy_to_operands(implies);

    guard_last = forall;
  }

  // All our conditions are met -- we can finally build the accelerator!
  // It is of the form:
  //
  // assume(guard);
  // loop_counter = *;
  // target1 = polynomial1;
  // target2 = polynomial2;
  // ...
  // assume(guard);
  // assume(no overflows in previous code);

  program.add_instruction(ASSUME)->guard = guard;

  program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type()));

  for (std::map<exprt, polynomialt>::iterator it = polynomials.begin();
       it != polynomials.end();
       ++it) {
    program.assign(it->first, it->second.to_expr());
  }

  // Add in any array assignments we can do now.
  if (!utils.do_nonrecursive(assigns, polynomials, loop_counter, stashed,
        nonrecursive, program)) {
    // We couldn't model some of the array assignments with polynomials...
    // Unfortunately that means we just have to bail out.
#ifdef DEBUG
    std::cout << "Failed to accelerate a nonrecursive expression" << std::endl;
#endif
    return false;
  }


  program.add_instruction(ASSUME)->guard = guard_last;
  program.fix_types();

  if (path_is_monotone) {
    utils.ensure_no_overflows(program);
  }

  accelerator.pure_accelerator.instructions.swap(program.instructions);

  return true;
}
Exemple #16
0
bodyt termination_baset::get_body(
  goto_tracet::stepst::const_iterator &loop_begin,
  const goto_tracet &trace)
{
  bodyt result_body;
  exprt::operandst op;
  const goto_trace_stept &assertion=trace.steps.back();

  // let's get a loop number as well:
  assert(assertion.pc->guard.id()=="=>");
  std::string c_str = assertion.pc->guard.op0().get_string("identifier");
  std::string prefix = termination_prefix+
                       c_str.substr(c_str.rfind("_")+1) + "::";

  // find out what we actually need
  required_stepst required_steps;
  find_required_steps(trace, loop_begin, required_steps, prefix);

  /* We perform a new SSA-conversion. However, since we can only
     get a single path through the program, there are no joins and
     thus no phi-functions. We just increment counters. */

  std::map<irep_idt, unsigned> ssa_counters;
  replace_idt replace_id;

  // get the required body constraints
  for(goto_tracet::stepst::const_iterator step=loop_begin;
      step!=--trace.steps.end();
      step++)
  {
    last_path.push_back(step->pc);

    // required_stepst::const_iterator fit=required_steps.find(&(*step));
    // if(fit==required_steps.end()) continue;

    switch(step->pc->type)
    {
      case ASSIGN:
      {
        const code_assignt &code=to_code_assign(step->pc->code);
        find_symbols_sett w;
        find_symbols_w(code.lhs(), w);

        equal_exprt equality(code.lhs(), code.rhs());
        replace_id.replace(equality.rhs());

        // All the written ones get their SSA-ID updated
        for(find_symbols_sett::const_iterator it=w.begin();
            it!=w.end();
            it++)
        {
          // Are we writing a pre-variable?
          if(has_prefix(id2string(*it), prefix))
          {
            assert(code.rhs().id()==ID_symbol);
            const irep_idt &post_id=code.rhs().get(ID_identifier);
            const irep_idt &pre_id=code.lhs().get(ID_identifier);
            result_body.variable_map[post_id]=pre_id;

            // the RHS gets a #0 id
            irep_idt new_id=id2string(post_id)+"!0";
            replace_id.insert(post_id, new_id);
            equality.rhs().set(ID_identifier, new_id);
          }
          else
          {
            const irep_idt &old_id=*it;
            unsigned cur=++ssa_counters[old_id]; // 0 is never used

            // gets a new ID
            irep_idt new_id=id2string(old_id)+"!"+i2string(cur);
            replace_id.insert(old_id, new_id);
          }
        }

        replace_id.replace(equality.lhs());
        op.push_back(equality);
        break;
      }
      case ASSUME:
      case ASSERT:
      {
        if(!step->cond_expr.is_true() && !step->cond_expr.is_nil())
        {
          exprt guard=step->cond_expr; // That's SSA!
          remove_ssa_ids(guard);
//          exprt guard=step->pc->guard;

          find_symbols_sett syms;
          find_symbols(guard, syms);

          for(find_symbols_sett::const_iterator it=syms.begin();
              it!=syms.end();
              it++)
          {
            if(ssa_counters.find(*it)==ssa_counters.end())
            {
              irep_idt new_id=id2string(*it)+"!"+i2string(++ssa_counters[*it]);
              replace_id.insert(*it, new_id);
            }
          }

          replace_id.replace(guard);
          if(!step->cond_value) guard.negate();
          op.push_back(guard);
        }
        break;
      }
      case GOTO:
      {
        if(!step->cond_expr.is_nil())
        {
//          exprt guard=step->pc->guard;
          exprt guard=step->cond_expr;
          remove_ssa_ids(guard);

          find_symbols_sett syms;
          find_symbols(guard, syms);

          for(find_symbols_sett::const_iterator it=syms.begin();
              it!=syms.end();
              it++)
          {
            if(ssa_counters.find(*it)==ssa_counters.end())
            {
              ssa_counters[*it]=0;
              irep_idt new_id=id2string(*it)+"!"+i2string(0);
              replace_id.insert(*it, new_id);
            }
          }

          replace_id.replace(guard);
          if(!step->cond_value)
            guard.negate();
          op.push_back(guard);
        }
        break;
      }
      case DECL: /* nothing */ break;
	    case LOCATION: /* These can show up here? */ break;
      default:
        throw std::string("unexpected instruction type.");
    }
  }

  // the final result, which (again) contains SSA variables
  exprt &body_expr = result_body.body_relation;
  body_expr = and_exprt(op);

  if(result_body.variable_map.empty())
  {
    // used to be:
    // throw "BUG: No variables found; path missing.";
    // Though: No variable is ever saved, i.e., this loop
    // must be completely nondeterministic.
    warning("No pre-variables found; this "
            "loop is completely non-deterministic.");
    body_expr=false_exprt();
  }

  // The last SSA-occurrence of a variable is the
  // output variable and it gets its non-SSA name.
  replace_idt last_map;
  for(std::map<irep_idt, unsigned>::const_iterator it=ssa_counters.begin();
      it!=ssa_counters.end();
      it++)
  {
    const irep_idt &id=it->first;
    unsigned last=it->second;

    irep_idt last_name=id2string(id)+"!"+i2string(last);
    last_map.insert(last_name, id);
  }

  last_map.replace(body_expr);

  replace_nondet_sideeffects(body_expr);

  return result_body;
}
Exemple #17
0
void summarizer_bw_termt::do_summary_term(
  const function_namet &function_name,
  local_SSAt &SSA,
  const summaryt &old_summary,
  summaryt &summary,
  bool context_sensitive)
{
  status() << "Computing preconditions for termination" << eom;

  // solver
  incremental_solvert &solver=ssa_db.get_solver(function_name);
  solver.set_message_handler(get_message_handler());

  // templates for ranking functions
  template_generator_rankingt template_generator1(
    options, ssa_db, ssa_unwinder.get(function_name));
  template_generator1.set_message_handler(get_message_handler());
  template_generator1(solver.next_domain_number(), SSA, true);

  // templates for backward summary
  template_generator_summaryt template_generator2(
    options, ssa_db, ssa_unwinder.get(function_name));
  template_generator2.set_message_handler(get_message_handler());
  template_generator2(solver.next_domain_number(), SSA, false);

  exprt::operandst bindings;
  exprt::operandst postcond;
  // backward summaries
  ssa_inliner.get_summaries(SSA, false, postcond, bindings);
  collect_postconditions(function_name, SSA, summary, postcond, true);

  // prepare solver
  solver << SSA;
  solver.new_context();
  solver << SSA.get_enabling_exprs();
  solver << old_summary.fw_precondition;
  solver << old_summary.fw_invariant;
  solver << ssa_inliner.get_summaries(SSA); // forward summaries
  solver << conjunction(bindings); // bindings for backward summaries

#if 0
  // compute preconditions individually
  // TODO: this should be done more transparently
  for(unsigned i=0; i<postcond.size(); i++)
  {
    exprt::operandst postcond2;
    postcond2.push_back(postcond[i]);
    compute_precondition(
      SSA, summary, postcond2, solver, template_generator2, context_sensitive);
  }
  postcond.clear();
#endif

  if(template_generator1.all_vars().empty())
  {
    compute_precondition(
      SSA, summary, postcond, solver, template_generator2, context_sensitive);
    solver.pop_context();
    return;
  }

  summary.bw_precondition=false_exprt(); // initialize
  unsigned number_disjuncts=0;
  while(number_disjuncts++<MAX_PRECONDITION_DISJUNCTS)
  {
    // bootstrap preconditions
    exprt termination_argument;
    if(!bootstrap_preconditions(
         SSA,
         summary,
         solver,
         template_generator1,
         template_generator2,
         termination_argument))
    {
      break;
    }

    // compute precondition
    // compute for individual termination arguments separately
    // TODO: this should be done more transparently
    if(termination_argument.id()==ID_and)
    {
      for(unsigned i=0; i<termination_argument.operands().size(); i++)
      {
        postcond.push_back(termination_argument.operands()[i]);

        exprt precondition=
          compute_precondition(
            SSA,
            summary,
            postcond,
            solver,
            template_generator2,
            context_sensitive);

        // join results
        if(summary.termination_argument.is_nil())
        {
          summary.termination_argument=
            implies_exprt(precondition, termination_argument);
        }
        else
        {
          summary.termination_argument=
            and_exprt(
              summary.termination_argument,
              implies_exprt(precondition, termination_argument));
        }

        // TODO: this is a bit asymmetric:
        //  the first precondition is joined with all other sources
        //  of non-termination (calls, bw calling context)
        postcond.clear();
      }
    }
    else // do not split termination arguments
    {
      postcond.push_back(termination_argument);
      exprt precondition=
        compute_precondition(
          SSA,
          summary,
          postcond,
          solver,
          template_generator2,
          context_sensitive);

      // join results
      if(summary.termination_argument.is_nil())
      {
        summary.termination_argument=
          implies_exprt(precondition, termination_argument);
      }
      else
      {
        summary.termination_argument=
          and_exprt(
            summary.termination_argument,
            implies_exprt(precondition, termination_argument));
      }

      // TODO: this is a bit asymmetric:
      //  the first precondition is joined with all other sources
      //  of non-termination (calls, bw calling context)
      postcond.clear();
    }
  }

  solver.pop_context();
}
Exemple #18
0
void memory_model_sct::from_read(symex_target_equationt &equation)
{
  // from-read: (w', w) in ws and (w', r) in rf -> (r, w) in fr

  for(address_mapt::const_iterator
      a_it=address_map.begin();
      a_it!=address_map.end();
      a_it++)
  {
    const a_rect &a_rec=a_it->second;

    // This is quadratic in the number of writes per address.
    for(event_listt::const_iterator
        w_prime=a_rec.writes.begin();
        w_prime!=a_rec.writes.end();
        ++w_prime)
    {
      event_listt::const_iterator next=w_prime;
      ++next;

      for(event_listt::const_iterator w=next;
          w!=a_rec.writes.end();
          ++w)
      {
        exprt ws1, ws2;

        if(po(*w_prime, *w) &&
           !program_order_is_relaxed(*w_prime, *w))
        {
          ws1=true_exprt();
          ws2=false_exprt();
        }
        else if(po(*w, *w_prime) &&
                !program_order_is_relaxed(*w, *w_prime))
        {
          ws1=false_exprt();
          ws2=true_exprt();
        }
        else
        {
          ws1=before(*w_prime, *w);
          ws2=before(*w, *w_prime);
        }

        // smells like cubic
        for(choice_symbolst::const_iterator
            c_it=choice_symbols.begin();
            c_it!=choice_symbols.end();
            c_it++)
        {
          event_it r=c_it->first.first;
          exprt rf=c_it->second;
          exprt cond;
          cond.make_nil();

          if(c_it->first.second==*w_prime && !ws1.is_false())
          {
            exprt fr=before(r, *w);

            // the guard of w_prime follows from rf; with rfi
            // optimisation such as the previous write_symbol_primed
            // it would even be wrong to add this guard
            cond=
              implies_exprt(
                and_exprt(r->guard, (*w)->guard, ws1, rf),
                fr);
          }
          else if(c_it->first.second==*w && !ws2.is_false())
          {
            exprt fr=before(r, *w_prime);

            // the guard of w follows from rf; with rfi
            // optimisation such as the previous write_symbol_primed
            // it would even be wrong to add this guard
            cond=
              implies_exprt(
                and_exprt(r->guard, (*w_prime)->guard, ws2, rf),
                fr);
          }

          if(cond.is_not_nil())
            add_constraint(equation,
              cond, "fr", r->source);
        }

      }
    }
  }
}
Exemple #19
0
void goto_checkt::bounds_check(
  const index_exprt &expr,
  const guardt &guard)
{
  if(!enable_bounds_check)
    return;

  if(expr.find("bounds_check").is_not_nil() &&
     !expr.get_bool("bounds_check"))
    return;

  typet array_type=ns.follow(expr.array().type());

  if(array_type.id()==ID_pointer)
    return; // done by the pointer code
  else if(array_type.id()==ID_incomplete_array)
    throw "index got incomplete array";
  else if(array_type.id()!=ID_array && array_type.id()!=ID_vector)
    throw "bounds check expected array or vector type, got "
      +array_type.id_string();

  std::string name=array_name(expr.array());

  const exprt &index=expr.index();
  object_descriptor_exprt ode;
  ode.build(expr, ns);

  if(index.type().id()!=ID_unsignedbv)
  {
    // we undo typecasts to signedbv
    if(index.id()==ID_typecast &&
       index.operands().size()==1 &&
       index.op0().type().id()==ID_unsignedbv)
    {
      // ok
    }
    else
    {
      mp_integer i;

      if(!to_integer(index, i) && i>=0)
      {
        // ok
      }
      else
      {
        exprt effective_offset=ode.offset();

        if(ode.root_object().id()==ID_dereference)
        {
          exprt p_offset=pointer_offset(
            to_dereference_expr(ode.root_object()).pointer());
          assert(p_offset.type()==effective_offset.type());

          effective_offset=plus_exprt(p_offset, effective_offset);
        }

        exprt zero=gen_zero(ode.offset().type());
        assert(zero.is_not_nil());

        // the final offset must not be negative
        binary_relation_exprt inequality(effective_offset, ID_ge, zero);

        add_guarded_claim(
          inequality,
          name+" lower bound",
          "array bounds",
          expr.find_source_location(),
          expr,
          guard);
      }
    }
  }

  if(ode.root_object().id()==ID_dereference)
  {
    const exprt &pointer=
      to_dereference_expr(ode.root_object()).pointer();

    if_exprt size(
      dynamic_object(pointer),
      typecast_exprt(dynamic_size(ns), object_size(pointer).type()),
      object_size(pointer));

    plus_exprt effective_offset(ode.offset(), pointer_offset(pointer));

    assert(effective_offset.op0().type()==effective_offset.op1().type());
    assert(effective_offset.type()==size.type());

    binary_relation_exprt inequality(effective_offset, ID_lt, size);

    or_exprt precond(
      and_exprt(
        dynamic_object(pointer),
        not_exprt(malloc_object(pointer, ns))),
      inequality);

    add_guarded_claim(
      precond,
      name+" upper bound",
      "array bounds",
      expr.find_source_location(),
      expr,
      guard);

    return;
  }

  const exprt &size=array_type.id()==ID_array ?
                    to_array_type(array_type).size() :
                    to_vector_type(array_type).size();

  if(size.is_nil())
  {
    // Linking didn't complete, we don't have a size.
    // Not clear what to do.
  }
  else if(size.id()==ID_infinity)
  {
  }
  else if(size.is_zero() &&
          expr.array().id()==ID_member)
  {
    // a variable sized struct member
  }
  else
  {
    binary_relation_exprt inequality(index, ID_lt, size);

    // typecast size
    if(inequality.op1().type()!=inequality.op0().type())
      inequality.op1().make_typecast(inequality.op0().type());

    // typecast size
    if(inequality.op1().type()!=inequality.op0().type())
      inequality.op1().make_typecast(inequality.op0().type());

    add_guarded_claim(
      inequality,
      name+" upper bound",
      "array bounds",
      expr.find_source_location(),
      expr,
      guard);
  }
}
/// add axioms corresponding to the String.compareTo java function
/// \par parameters: function application with two string arguments
/// \return a integer expression
exprt string_constraint_generatort::add_axioms_for_compare_to(
  const function_application_exprt &f)
{
  string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]);
  string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]);
  const typet &return_type=f.type();
  symbol_exprt res=fresh_symbol("compare_to", return_type);
  typet index_type=s1.length().type();

  // In the lexicographic comparison, x is the first point where the two
  // strings differ.
  // We add axioms:
  // a1 : res==0 => |s1|=|s2|
  // a2 : forall i<|s1|. s1[i]==s2[i]
  // a3 : exists x.
  // res!=0 ==> x> 0 &&
  //   ((|s1| <= |s2| &&x<|s1|) || (|s1| >= |s2| &&x<|s2|)
  //   &&res=s1[x]-s2[x] )
  // || cond2:
  //   (|s1|<|s2| &&x=|s1|) || (|s1| > |s2| &&x=|s2|) &&res=|s1|-|s2|)
  // a4 : forall i<x. res!=0 => s1[i]=s2[i]

  assert(return_type.id()==ID_signedbv);

  equal_exprt res_null=equal_exprt(res, from_integer(0, return_type));
  implies_exprt a1(res_null, s1.axiom_for_has_same_length_as(s2));
  axioms.push_back(a1);

  symbol_exprt i=fresh_univ_index("QA_compare_to", index_type);
  string_constraintt a2(i, s1.length(), res_null, equal_exprt(s1[i], s2[i]));
  axioms.push_back(a2);

  symbol_exprt x=fresh_exist_index("index_compare_to", index_type);
  equal_exprt ret_char_diff(
    res,
    minus_exprt(
      typecast_exprt(s1[x], return_type),
      typecast_exprt(s2[x], return_type)));
  equal_exprt ret_length_diff(
    res,
    minus_exprt(
      typecast_exprt(s1.length(), return_type),
      typecast_exprt(s2.length(), return_type)));
  or_exprt guard1(
    and_exprt(s1.axiom_for_is_shorter_than(s2),
              s1.axiom_for_is_strictly_longer_than(x)),
    and_exprt(s1.axiom_for_is_longer_than(s2),
              s2.axiom_for_is_strictly_longer_than(x)));
  and_exprt cond1(ret_char_diff, guard1);
  or_exprt guard2(
    and_exprt(s2.axiom_for_is_strictly_longer_than(s1),
              s1.axiom_for_has_length(x)),
    and_exprt(s1.axiom_for_is_strictly_longer_than(s2),
              s2.axiom_for_has_length(x)));
  and_exprt cond2(ret_length_diff, guard2);

  implies_exprt a3(
    not_exprt(res_null),
    and_exprt(
      binary_relation_exprt(x, ID_ge, from_integer(0, return_type)),
      or_exprt(cond1, cond2)));
  axioms.push_back(a3);

  string_constraintt a4(i, x, not_exprt(res_null), equal_exprt(s1[i], s2[i]));
  axioms.push_back(a4);

  return res;
}
Exemple #21
0
void symex_target_equationt::convert_assertions(
  prop_convt &prop_conv)
{
  // we find out if there is only _one_ assertion,
  // which allows for a simpler formula

  unsigned number_of_assertions=count_assertions();

  if(number_of_assertions==0)
    return;

  if(number_of_assertions==1)
  {
    for(auto & it : SSA_steps)
    {
      if(it.is_assert())
      {
        prop_conv.set_to_false(it.cond_expr);
        it.cond_literal=const_literal(false);
        return; // prevent further assumptions!
      }
      else if(it.is_assume())
        prop_conv.set_to_true(it.cond_expr);
    }

    assert(false); // unreachable
  }

  // We do (NOT a1) OR (NOT a2) ...
  // where the a's are the assertions
  or_exprt::operandst disjuncts;
  disjuncts.reserve(number_of_assertions);

  exprt assumption=true_exprt();

  for(auto & it : SSA_steps)
  {
    if(it.is_assert())
    {
      implies_exprt implication(
        assumption,
        it.cond_expr);
      
      // do the conversion
      it.cond_literal=prop_conv.convert(implication);

      // store disjunct
      disjuncts.push_back(literal_exprt(!it.cond_literal));
    }
    else if(it.is_assume())
    {
      // the assumptions have been converted before
      // avoid deep nesting of ID_and expressions
      if(assumption.id()==ID_and)
        assumption.copy_to_operands(literal_exprt(it.cond_literal));
      else
        assumption=
          and_exprt(assumption, literal_exprt(it.cond_literal));
    }
  }

  // the below is 'true' if there are no assertions
  prop_conv.set_to_true(disjunction(disjuncts));
}
bool disjunctive_polynomial_accelerationt::accelerate(
    path_acceleratort &accelerator) {
  std::map<exprt, polynomialt> polynomials;
  scratch_programt program(symbol_table);

  accelerator.clear();

#ifdef DEBUG
  std::cout << "Polynomial accelerating program:" << std::endl;

  for (goto_programt::instructionst::iterator it = goto_program.instructions.begin();
       it != goto_program.instructions.end();
       ++it) {
    if (loop.find(it) != loop.end()) {
      goto_program.output_instruction(ns, "scratch", std::cout, it);
    }
  }

  std::cout << "Modified:" << std::endl;

  for (expr_sett::iterator it = modified.begin();
       it != modified.end();
       ++it) {
    std::cout << expr2c(*it, ns) << std::endl;
  }
#endif

  if (loop_counter.is_nil()) {
    symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter",
        unsigned_poly_type());
    loop_counter = loop_sym.symbol_expr();
  }

  patht &path = accelerator.path;
  path.clear();

  if (!find_path(path)) {
    // No more paths!
    return false;
  }

#if 0
  for (expr_sett::iterator it = modified.begin();
       it != modified.end();
       ++it) {
    polynomialt poly;
    exprt target = *it;

    if (it->type().id() == ID_bool) {
      // Hack: don't try to accelerate booleans.
      continue;
    }

    if (target.id() == ID_index ||
        target.id() == ID_dereference) {
      // We'll handle this later.
      continue;
    }

    if (fit_polynomial(target, poly, path)) {
      std::map<exprt, polynomialt> this_poly;
      this_poly[target] = poly;

      if (utils.check_inductive(this_poly, path)) {
#ifdef DEBUG
        std::cout << "Fitted a polynomial for " << expr2c(target, ns) <<
          std::endl;
#endif
        polynomials[target] = poly;
        accelerator.changed_vars.insert(target);
        break;
      }
    }
  }

  if (polynomials.empty()) {
    return false;
  }
#endif

  // Fit polynomials for the other variables.
  expr_sett dirty;
  utils.find_modified(accelerator.path, dirty);
  polynomial_acceleratort path_acceleration(symbol_table, goto_functions,
      loop_counter);
  goto_programt::instructionst assigns;

  for (patht::iterator it = accelerator.path.begin();
       it != accelerator.path.end();
       ++it) {
    if (it->loc->is_assign() || it->loc->is_decl()) {
      assigns.push_back(*(it->loc));
    }
  }

  for (expr_sett::iterator it = dirty.begin();
       it != dirty.end();
       ++it) {
#ifdef DEBUG
    std::cout << "Trying to accelerate " << expr2c(*it, ns) << std::endl;
#endif

    if (it->type().id() == ID_bool) {
      // Hack: don't try to accelerate booleans.
      accelerator.dirty_vars.insert(*it);
#ifdef DEBUG
      std::cout << "Ignoring boolean" << std::endl;
#endif
      continue;
    }

    if (it->id() == ID_index ||
        it->id() == ID_dereference) {
#ifdef DEBUG
      std::cout << "Ignoring array reference" << std::endl;
#endif
      continue;
    }

    if (accelerator.changed_vars.find(*it) != accelerator.changed_vars.end()) {
      // We've accelerated variable this already.
#ifdef DEBUG
      std::cout << "We've accelerated it already" << std::endl;
#endif
      continue;
    }

    // Hack: ignore variables that depend on array values..
    exprt array_rhs;

    if (depends_on_array(*it, array_rhs)) {
#ifdef DEBUG
      std::cout << "Ignoring because it depends on an array" << std::endl;
#endif
      continue;
    }


    polynomialt poly;
    exprt target(*it);

    if (path_acceleration.fit_polynomial(assigns, target, poly)) {
      std::map<exprt, polynomialt> this_poly;
      this_poly[target] = poly;

      if (utils.check_inductive(this_poly, accelerator.path)) {
        polynomials[target] = poly;
        accelerator.changed_vars.insert(target);
        continue;
      }
    }

#ifdef DEBUG
    std::cout << "Failed to accelerate " << expr2c(*it, ns) << std::endl;
#endif

    // We weren't able to accelerate this target...
    accelerator.dirty_vars.insert(target);
  }


  /*
  if (!utils.check_inductive(polynomials, assigns)) {
    // They're not inductive :-(
    return false;
  }
  */

  substitutiont stashed;
  utils.stash_polynomials(program, polynomials, stashed, path);

  exprt guard;
  bool path_is_monotone;

  try {
    path_is_monotone = utils.do_assumptions(polynomials, path, guard);
  } catch (std::string s) {
    // Couldn't do WP.
    std::cout << "Assumptions error: " << s << std::endl;
    return false;
  }

  exprt pre_guard(guard);

  for (std::map<exprt, polynomialt>::iterator it = polynomials.begin();
       it != polynomials.end();
       ++it) {
    replace_expr(it->first, it->second.to_expr(), guard);
  }

  if (path_is_monotone) {
    // OK cool -- the path is monotone, so we can just assume the condition for
    // the last iteration.
    replace_expr(loop_counter,
                 minus_exprt(loop_counter, from_integer(1, loop_counter.type())),
                 guard);
  } else {
    // The path is not monotone, so we need to introduce a quantifier to ensure
    // that the condition held for all 0 <= k < n.
    symbolt k_sym = utils.fresh_symbol("polynomial::k", unsigned_poly_type());
    exprt k = k_sym.symbol_expr();

    exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k),
                              binary_relation_exprt(k, "<", loop_counter));
    replace_expr(loop_counter, k, guard);

    simplify(guard, ns);

    implies_exprt implies(k_bound, guard);

    exprt forall(ID_forall);
    forall.type() = bool_typet();
    forall.copy_to_operands(k);
    forall.copy_to_operands(implies);

    guard = forall;
  }

  // All our conditions are met -- we can finally build the accelerator!
  // It is of the form:
  //
  // loop_counter = *;
  // target1 = polynomial1;
  // target2 = polynomial2;
  // ...
  // assume(guard);
  // assume(no overflows in previous code);

  program.add_instruction(ASSUME)->guard = pre_guard;
  program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type()));

  for (std::map<exprt, polynomialt>::iterator it = polynomials.begin();
       it != polynomials.end();
       ++it) {
    program.assign(it->first, it->second.to_expr());
    accelerator.changed_vars.insert(it->first);
  }

  // Add in any array assignments we can do now.
  if (!utils.do_arrays(assigns, polynomials, loop_counter, stashed, program)) {
    // We couldn't model some of the array assignments with polynomials...
    // Unfortunately that means we just have to bail out.
    return false;
  }

  program.add_instruction(ASSUME)->guard = guard;
  program.fix_types();

  if (path_is_monotone) {
    utils.ensure_no_overflows(program);
  }

  accelerator.pure_accelerator.instructions.swap(program.instructions);

  return true;
}
Exemple #23
0
void local_SSAt::assign_rec(
  const exprt &lhs,
  const exprt &rhs,
  const exprt &guard,
  locationt loc)
{
  const typet &type=ns.follow(lhs.type());

  if(is_symbol_struct_member(lhs, ns))
  {
    if(type.id()==ID_struct)
    {
      // need to split up

      const struct_typet &struct_type=to_struct_type(type);
      const struct_typet::componentst &components=struct_type.components();
      
      for(struct_typet::componentst::const_iterator
          it=components.begin();
          it!=components.end();
          it++)
      {
        member_exprt new_lhs(lhs, it->get_name(), it->type());
        member_exprt new_rhs(rhs, it->get_name(), it->type());
        assign_rec(new_lhs, new_rhs, guard, loc);
      }

      return;
    }

    ssa_objectt lhs_object(lhs, ns);
    
    const std::set<ssa_objectt> &assigned=
      assignments.get(loc);

    if(assigned.find(lhs_object)!=assigned.end())
    {
      exprt ssa_rhs=read_rhs(rhs, loc);

      const symbol_exprt ssa_symbol=name(lhs_object, OUT, loc);
      
      equal_exprt equality(ssa_symbol, ssa_rhs);
      nodes[loc].equalities.push_back(equality);
    }
  }
  else if(lhs.id()==ID_index)
  {
    const index_exprt &index_expr=to_index_expr(lhs);
    exprt ssa_array=index_expr.array();
    exprt new_rhs=with_exprt(ssa_array, index_expr.index(), rhs);
    assign_rec(index_expr.array(), new_rhs, guard, loc);
  }
  else if(lhs.id()==ID_member)
  {
    // These are non-flattened struct or union members.
    const member_exprt &member_expr=to_member_expr(lhs);
    const exprt &compound=member_expr.struct_op();
    const typet &compound_type=ns.follow(compound.type());

    if(compound_type.id()==ID_union)
    {
      union_exprt new_rhs(member_expr.get_component_name(), rhs, compound.type());
      assign_rec(member_expr.struct_op(), new_rhs, guard, loc);
    }
    else if(compound_type.id()==ID_struct)
    {
      exprt member_name(ID_member_name);
      member_name.set(ID_component_name, member_expr.get_component_name());
      with_exprt new_rhs(compound, member_name, rhs);
      assign_rec(compound, new_rhs, guard, loc);
    }
  }
  else if(lhs.id()==ID_complex_real)
  {
    assert(lhs.operands().size()==1);
    const exprt &op=lhs.op0();
    const complex_typet &complex_type=to_complex_type(op.type());
    exprt imag_op=unary_exprt(ID_complex_imag, op, complex_type.subtype());
    complex_exprt new_rhs(rhs, imag_op, complex_type);
    assign_rec(op, new_rhs, guard, loc);
  }
  else if(lhs.id()==ID_complex_imag)
  {
    assert(lhs.operands().size()==1);
    const exprt &op=lhs.op0();
    const complex_typet &complex_type=to_complex_type(op.type());
    exprt real_op=unary_exprt(ID_complex_real, op, complex_type.subtype());
    complex_exprt new_rhs(real_op, rhs, complex_type);
    assign_rec(op, new_rhs, guard, loc);
  }
  else if(lhs.id()==ID_if)
  {
    const if_exprt &if_expr=to_if_expr(lhs);
    assign_rec(if_expr.true_case(), rhs, and_exprt(guard, if_expr.cond()), loc);
    assign_rec(if_expr.false_case(), rhs, and_exprt(guard, not_exprt(if_expr.cond())), loc);
  }
  else if(lhs.id()==ID_byte_extract_little_endian ||
          lhs.id()==ID_byte_extract_big_endian)
  {
    const byte_extract_exprt &byte_extract_expr=to_byte_extract_expr(lhs);

    exprt new_lhs=byte_extract_expr.op();

    exprt new_rhs=byte_extract_exprt(
      byte_extract_expr.id(), rhs, byte_extract_expr.offset(), new_lhs.type());

    assign_rec(new_lhs, new_rhs, guard, loc);
  }
  else
    throw "UNKNOWN LHS: "+lhs.id_string();
}
Exemple #24
0
void goto_checkt::conversion_check(
  const exprt &expr,
  const guardt &guard)
{
  if(!enable_conversion_check)
    return;

  // First, check type.
  const typet &type=ns.follow(expr.type());

  if(type.id()!=ID_signedbv &&
     type.id()!=ID_unsignedbv)
    return;

  if(expr.id()==ID_typecast)
  {
    // conversion to signed int may overflow

    if(expr.operands().size()!=1)
      throw "typecast takes one operand";

    const typet &old_type=ns.follow(expr.op0().type());

    if(type.id()==ID_signedbv)
    {
      std::size_t new_width=to_signedbv_type(type).get_width();

      if(old_type.id()==ID_signedbv) // signed -> signed
      {
        std::size_t old_width=to_signedbv_type(old_type).get_width();
        if(new_width>=old_width) return; // always ok

        binary_relation_exprt no_overflow_upper(ID_le);
        no_overflow_upper.lhs()=expr.op0();
        no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type);

        binary_relation_exprt no_overflow_lower(ID_ge);
        no_overflow_lower.lhs()=expr.op0();
        no_overflow_lower.rhs()=from_integer(-power(2, new_width-1), old_type);

        add_guarded_claim(
          and_exprt(no_overflow_lower, no_overflow_upper),
          "arithmetic overflow on signed type conversion",
          "overflow",
          expr.find_source_location(),
          expr,
          guard);
      }
      else if(old_type.id()==ID_unsignedbv) // unsigned -> signed
      {
        std::size_t old_width=to_unsignedbv_type(old_type).get_width();
        if(new_width>=old_width+1) return; // always ok

        binary_relation_exprt no_overflow_upper(ID_le);
        no_overflow_upper.lhs()=expr.op0();
        no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type);

        add_guarded_claim(
          no_overflow_upper,
          "arithmetic overflow on unsigned to signed type conversion",
          "overflow",
          expr.find_source_location(),
          expr,
          guard);
      }
      else if(old_type.id()==ID_floatbv) // float -> signed
      {
        // Note that the fractional part is truncated!
        ieee_floatt upper(to_floatbv_type(old_type));
        upper.from_integer(power(2, new_width-1));
        binary_relation_exprt no_overflow_upper(ID_lt);
        no_overflow_upper.lhs()=expr.op0();
        no_overflow_upper.rhs()=upper.to_expr();

        ieee_floatt lower(to_floatbv_type(old_type));
        lower.from_integer(-power(2, new_width-1)-1);
        binary_relation_exprt no_overflow_lower(ID_gt);
        no_overflow_lower.lhs()=expr.op0();
        no_overflow_lower.rhs()=lower.to_expr();

        add_guarded_claim(
          and_exprt(no_overflow_lower, no_overflow_upper),
          "arithmetic overflow on float to signed integer type conversion",
          "overflow",
          expr.find_source_location(),
          expr,
          guard);
      }
    }
    else if(type.id()==ID_unsignedbv)
    {
      std::size_t new_width=to_unsignedbv_type(type).get_width();

      if(old_type.id()==ID_signedbv) // signed -> unsigned
      {
        std::size_t old_width=to_signedbv_type(old_type).get_width();

        if(new_width>=old_width-1)
        {
          // only need lower bound check
          binary_relation_exprt no_overflow_lower(ID_ge);
          no_overflow_lower.lhs()=expr.op0();
          no_overflow_lower.rhs()=from_integer(0, old_type);

          add_guarded_claim(
            no_overflow_lower,
            "arithmetic overflow on signed to unsigned type conversion",
            "overflow",
            expr.find_source_location(),
            expr,
            guard);
        }
        else
        {
          // need both
          binary_relation_exprt no_overflow_upper(ID_le);
          no_overflow_upper.lhs()=expr.op0();
          no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type);

          binary_relation_exprt no_overflow_lower(ID_ge);
          no_overflow_lower.lhs()=expr.op0();
          no_overflow_lower.rhs()=from_integer(0, old_type);

          add_guarded_claim(
            and_exprt(no_overflow_lower, no_overflow_upper),
            "arithmetic overflow on signed to unsigned type conversion",
            "overflow",
            expr.find_source_location(),
            expr,
            guard);
        }
      }
      else if(old_type.id()==ID_unsignedbv) // unsigned -> unsigned
      {
        std::size_t old_width=to_unsignedbv_type(old_type).get_width();
        if(new_width>=old_width) return; // always ok

        binary_relation_exprt no_overflow_upper(ID_le);
        no_overflow_upper.lhs()=expr.op0();
        no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type);

        add_guarded_claim(
          no_overflow_upper,
          "arithmetic overflow on unsigned to unsigned type conversion",
          "overflow",
          expr.find_source_location(),
          expr,
          guard);
      }
      else if(old_type.id()==ID_floatbv) // float -> unsigned
      {
        // Note that the fractional part is truncated!
        ieee_floatt upper(to_floatbv_type(old_type));
        upper.from_integer(power(2, new_width)-1);
        binary_relation_exprt no_overflow_upper(ID_lt);
        no_overflow_upper.lhs()=expr.op0();
        no_overflow_upper.rhs()=upper.to_expr();

        ieee_floatt lower(to_floatbv_type(old_type));
        lower.from_integer(-1);
        binary_relation_exprt no_overflow_lower(ID_gt);
        no_overflow_lower.lhs()=expr.op0();
        no_overflow_lower.rhs()=lower.to_expr();

        add_guarded_claim(
          and_exprt(no_overflow_lower, no_overflow_upper),
          "arithmetic overflow on float to unsigned integer type conversion",
          "overflow",
          expr.find_source_location(),
          expr,
          guard);
      }
    }
  }
}
Exemple #25
0
void local_SSAt::build_guard(locationt loc)
{
  const guard_mapt::entryt &entry=guard_map[loc];
  
  // anything to be built?
  if(!entry.has_guard) return;
  
  exprt::operandst sources;

  // the very first 'loc' trivially gets 'true' as source
  if(loc==goto_function.body.instructions.begin())
    sources.push_back(true_exprt());
    
  for(guard_mapt::incomingt::const_iterator
      i_it=entry.incoming.begin();
      i_it!=entry.incoming.end();
      i_it++)
  {
    const guard_mapt::edget &edge=*i_it;
    
    exprt source;
    
    // might be backwards branch taken edge
    if(edge.is_branch_taken() &&
       edge.from->is_backwards_goto())
    {
      // The loop selector indicates whether the path comes from
      // above (entering the loop) or below (iterating).
      // By convention, we use the loop select symbol for the location
      // of the backwards goto.
      symbol_exprt loop_select=
        name(guard_symbol(), LOOP_SELECT, edge.from);

      #if 0
      source=false_exprt();
      #else
      // need constraing for edge.cond
      source=loop_select;
      #endif
    }
    else
    {
      // the other cases are basically similar
      
      symbol_exprt gs=name(guard_symbol(), OUT, edge.guard_source);
      exprt cond;
      
      if(edge.is_branch_taken() ||
         edge.is_assume() ||
         edge.is_function_call())
        cond=cond_symbol(edge.from);
      else if(edge.is_branch_not_taken())
        cond=boolean_negate(cond_symbol(edge.from));
      else if(edge.is_successor())
        cond=true_exprt();
      else
        assert(false);

      source=and_exprt(gs, cond);
    }
    
    sources.push_back(source);
  }

  // the below produces 'false' if there is no source
  exprt rhs=disjunction(sources);
  
  equal_exprt equality(guard_symbol(loc), rhs);
  nodes[loc].equalities.push_back(equality);
}
Exemple #26
0
void goto_checkt::integer_overflow_check(
  const exprt &expr,
  const guardt &guard)
{
  if(!enable_signed_overflow_check &&
     !enable_unsigned_overflow_check)
    return;

  // First, check type.
  const typet &type=ns.follow(expr.type());

  if(type.id()==ID_signedbv && !enable_signed_overflow_check)
    return;

  if(type.id()==ID_unsignedbv && !enable_unsigned_overflow_check)
    return;

  // add overflow subgoal

  if(expr.id()==ID_div)
  {
    assert(expr.operands().size()==2);

    // undefined for signed division INT_MIN/-1
    if(type.id()==ID_signedbv)
    {
      equal_exprt int_min_eq(
        expr.op0(), to_signedbv_type(type).smallest_expr());

      equal_exprt minus_one_eq(
        expr.op1(), from_integer(-1, type));

      add_guarded_claim(
        not_exprt(and_exprt(int_min_eq, minus_one_eq)),
        "arithmetic overflow on signed division",
        "overflow",
        expr.find_source_location(),
        expr,
        guard);
    }

    return;
  }
  else if(expr.id()==ID_mod)
  {
    // these can't overflow
    return;
  }
  else if(expr.id()==ID_unary_minus)
  {
    if(type.id()==ID_signedbv)
    {
      // overflow on unary- can only happen with the smallest
      // representable number 100....0

      equal_exprt int_min_eq(
        expr.op0(), to_signedbv_type(type).smallest_expr());

      add_guarded_claim(
        not_exprt(int_min_eq),
        "arithmetic overflow on signed unary minus",
        "overflow",
        expr.find_source_location(),
        expr,
        guard);
    }

    return;
  }

  exprt overflow("overflow-"+expr.id_string(), bool_typet());
  overflow.operands()=expr.operands();

  if(expr.operands().size()>=3)
  {
    // The overflow checks are binary!
    // We break these up.

    for(unsigned i=1; i<expr.operands().size(); i++)
    {
      exprt tmp;

      if(i==1)
        tmp=expr.op0();
      else
      {
        tmp=expr;
        tmp.operands().resize(i);
      }

      overflow.operands().resize(2);
      overflow.op0()=tmp;
      overflow.op1()=expr.operands()[i];

      std::string kind=
        type.id()==ID_unsignedbv?"unsigned":"signed";

      add_guarded_claim(
        not_exprt(overflow),
        "arithmetic overflow on "+kind+" "+expr.id_string(),
        "overflow",
        expr.find_source_location(),
        expr,
        guard);
    }
  }
  else
  {
    std::string kind=
      type.id()==ID_unsignedbv?"unsigned":"signed";

    add_guarded_claim(
      not_exprt(overflow),
      "arithmetic overflow on "+kind+" "+expr.id_string(),
      "overflow",
      expr.find_source_location(),
      expr,
      guard);
  }
}
Exemple #27
0
void goto_checkt::nan_check(
  const exprt &expr,
  const guardt &guard)
{
  if(!enable_nan_check)
    return;

  // first, check type
  if(expr.type().id()!=ID_floatbv)
    return;

  if(expr.id()!=ID_plus &&
     expr.id()!=ID_mult &&
     expr.id()!=ID_div &&
     expr.id()!=ID_minus)
    return;

  // add NaN subgoal

  exprt isnan;

  if(expr.id()==ID_div)
  {
    assert(expr.operands().size()==2);

    // there a two ways to get a new NaN on division:
    // 0/0 = NaN and x/inf = NaN
    // (note that x/0 = +-inf for x!=0 and x!=inf)
    exprt zero_div_zero=and_exprt(
      ieee_float_equal_exprt(expr.op0(), gen_zero(expr.op0().type())),
      ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type())));

    exprt div_inf=unary_exprt(ID_isinf, expr.op1(), bool_typet());

    isnan=or_exprt(zero_div_zero, div_inf);
  }
  else if(expr.id()==ID_mult)
  {
    if(expr.operands().size()>=3)
      return nan_check(make_binary(expr), guard);

    assert(expr.operands().size()==2);

    // Inf * 0 is NaN
    exprt inf_times_zero=and_exprt(
      unary_exprt(ID_isinf, expr.op0(), bool_typet()),
      ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type())));

    exprt zero_times_inf=and_exprt(
      ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type())),
      unary_exprt(ID_isinf, expr.op0(), bool_typet()));

    isnan=or_exprt(inf_times_zero, zero_times_inf);
  }
  else if(expr.id()==ID_plus)
  {
    if(expr.operands().size()>=3)
      return nan_check(make_binary(expr), guard);

    assert(expr.operands().size()==2);

    // -inf + +inf = NaN and +inf + -inf = NaN,
    // i.e., signs differ
    ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type()));
    exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr();
    exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr();

    isnan=or_exprt(
      and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), plus_inf)),
      and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), minus_inf)));
  }
  else if(expr.id()==ID_minus)
  {
    assert(expr.operands().size()==2);
    // +inf - +inf = NaN and -inf - -inf = NaN,
    // i.e., signs match

    ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type()));
    exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr();
    exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr();

    isnan=or_exprt(
      and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), plus_inf)),
      and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), minus_inf)));
  }
  else
    assert(false);

  isnan.make_not();

  add_guarded_claim(
    isnan,
    "NaN on "+expr.id_string(),
    "NaN",
    expr.find_source_location(),
    expr,
    guard);
}