Beispiel #1
0
/*
 * Insert a looping path (usually an accelerator) into a goto-program,
 * beginning at loop_header and jumping back to loop_header via back_jump.
 * Stores the locations at which the looping path was added in inserted_path.
 *
 * THIS DESTROYS looping_path!!
 */
void acceleratet::insert_looping_path(
  goto_programt::targett &loop_header,
  goto_programt::targett &back_jump,
  goto_programt &looping_path,
  patht &inserted_path)
{
  goto_programt::targett loop_body=loop_header;
  ++loop_body;

  goto_programt::targett jump=program.insert_before(loop_body);
  jump->make_goto();
  jump->guard=side_effect_expr_nondett(bool_typet());
  jump->targets.push_back(loop_body);

  program.destructive_insert(loop_body, looping_path);

  jump=program.insert_before(loop_body);
  jump->make_goto();
  jump->guard=true_exprt();
  jump->targets.push_back(back_jump);

  for(goto_programt::targett t=loop_header;
      t!=loop_body;
      ++t)
  {
    inserted_path.push_back(path_nodet(t));
  }

  inserted_path.push_back(path_nodet(back_jump));
}
Beispiel #2
0
void string_instrumentationt::do_fscanf(
  goto_programt &dest,
  goto_programt::targett target,
  code_function_callt &call)
{
  const code_function_callt::argumentst &arguments=call.arguments();
  
  if(arguments.size()<2)
  {
    err_location(target->location);
    throw "fscanf expected to have two or more arguments";
  }
  
  goto_programt tmp;
  
  do_format_string_write(tmp, target, arguments, 1, 2, "fscanf");
  
  if(call.lhs().is_not_nil())
  {
    goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN);
    return_assignment->location=target->location;
      
    exprt rhs=side_effect_expr_nondett(call.lhs().type());
    rhs.location()=target->location;
      
    return_assignment->code=code_assignt(call.lhs(), rhs);
  }
  
  target->make_skip();
  dest.insert_before_swap(target, tmp);
}
Beispiel #3
0
void nondet_static(
  const namespacet &ns,
  goto_functionst &goto_functions,
  const irep_idt &fct_name)
{
  goto_functionst::function_mapt::iterator
    i_it=goto_functions.function_map.find(fct_name);
  assert(i_it!=goto_functions.function_map.end());

  goto_programt &init=i_it->second.body;

  Forall_goto_program_instructions(i_it, init)
  {
    const goto_programt::instructiont &instruction=*i_it;

    if(instruction.is_assign())
    {
      const symbol_exprt &sym=to_symbol_expr(
          to_code_assign(instruction.code).lhs());

      // is it a __CPROVER_* variable?
      if(has_prefix(id2string(sym.get_identifier()), CPROVER_PREFIX))
        continue;
        
      // static lifetime?
      if(!ns.lookup(sym.get_identifier()).is_static_lifetime)
        continue;

      // constant?
      if(sym.type().get_bool(ID_C_constant))
        continue;

      i_it=init.insert_before(++i_it);
      i_it->make_assignment();
      i_it->code=code_assignt(sym, side_effect_expr_nondett(sym.type()));
      i_it->location=instruction.location;
      i_it->function=instruction.function;
    }
    else if(instruction.is_function_call())
    {
      const code_function_callt &fct=to_code_function_call(instruction.code);
      const symbol_exprt &fsym=to_symbol_expr(fct.function());

      if(has_prefix(id2string(fsym.get_identifier()), "c::#ini#"))
        nondet_static(ns, goto_functions, fsym.get_identifier());
    }
  }
}
Beispiel #4
0
void string_instrumentationt::do_snprintf(
  goto_programt &dest,
  goto_programt::targett target,
  code_function_callt &call)
{
  const code_function_callt::argumentst &arguments=call.arguments();

  if(arguments.size()<3)
  {
    error().source_location=target->source_location;
    error() << "snprintf expected to have three or more arguments"
            << eom;
    throw 0;
  }

  goto_programt tmp;

  goto_programt::targett assertion=tmp.add_instruction();
  assertion->source_location=target->source_location;
  assertion->source_location.set_property_class("string");
  assertion->source_location.set_comment("snprintf buffer overflow");

  exprt bufsize=buffer_size(arguments[0]);
  assertion->make_assertion(
    binary_relation_exprt(bufsize, ID_ge, arguments[1]));

  do_format_string_read(tmp, target, arguments, 2, 3, "snprintf");

  if(call.lhs().is_not_nil())
  {
    goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN);
    return_assignment->source_location=target->source_location;

    exprt rhs=side_effect_expr_nondett(call.lhs().type());
    rhs.add_source_location()=target->source_location;

    return_assignment->code=code_assignt(call.lhs(), rhs);
  }

  target->make_skip();
  dest.insert_before_swap(target, tmp);
}
Beispiel #5
0
void havoc_loopst::build_havoc_code(
  const goto_programt::targett loop_head,
  const modifiest &modifies,
  goto_programt &dest)
{
  for(modifiest::const_iterator
      m_it=modifies.begin();
      m_it!=modifies.end();
      m_it++)
  {
    exprt lhs=*m_it;
    exprt rhs=side_effect_expr_nondett(lhs.type());

    goto_programt::targett t=dest.add_instruction(ASSIGN);
    t->function=loop_head->function;
    t->source_location=loop_head->source_location;
    t->code=code_assignt(lhs, rhs);
    t->code.add_source_location()=loop_head->source_location;
  }
}
void string_instrumentationt::do_sprintf(
  goto_programt &dest,
  goto_programt::targett target,
  code_function_callt &call)
{
  const code_function_callt::argumentst &arguments=call.arguments();
    
  if(arguments.size()<2)
  {
    error().source_location=target->source_location;
    error() << "sprintf expected to have two or more arguments" << eom;
    throw 0;
  }
  
  goto_programt tmp;
  
  goto_programt::targett assertion=tmp.add_instruction();  
  assertion->source_location=target->source_location;
  assertion->source_location.set_property_class("string");  
  assertion->source_location.set_comment("sprintf buffer overflow");
  
  // in the abstract model, we have to report a 
  // (possibly false) positive here
  assertion->make_assertion(false_exprt());
  
  do_format_string_read(tmp, target, arguments, 1, 2, "sprintf");
  
  if(call.lhs().is_not_nil())
  {
    goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN);
    return_assignment->source_location=target->source_location;
    
    exprt rhs=side_effect_expr_nondett(call.lhs().type());
    rhs.add_source_location()=target->source_location;
      
    return_assignment->code=code_assignt(call.lhs(), rhs);
  }
  
  target->make_skip();
  dest.insert_before_swap(target, tmp);
}
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;
}
Beispiel #8
0
void goto_checkt::goto_check(goto_functiont &goto_function)
{
  {
    const symbolt *init_symbol;
    if(!ns.lookup(CPROVER_PREFIX "initialize", init_symbol))
      mode=init_symbol->mode;
  }

  assertions.clear();

  local_bitvector_analysist local_bitvector_analysis_obj(goto_function);
  local_bitvector_analysis=&local_bitvector_analysis_obj;

  goto_programt &goto_program=goto_function.body;

  Forall_goto_program_instructions(it, goto_program)
  {
    t=it;
    goto_programt::instructiont &i=*it;

    new_code.clear();

    // we clear all recorded assertions if
    // 1) we want to generate all assertions or
    // 2) the instruction is a branch target
    if(retain_trivial ||
       i.is_target())
      assertions.clear();

    check(i.guard);

    // magic ERROR label?
    for(optionst::value_listt::const_iterator
        l_it=error_labels.begin();
        l_it!=error_labels.end();
        l_it++)
    {
      if(std::find(i.labels.begin(), i.labels.end(), *l_it)!=i.labels.end())
      {
        goto_program_instruction_typet type=
          enable_assert_to_assume?ASSUME:ASSERT;

        goto_programt::targett t=new_code.add_instruction(type);

        t->guard=false_exprt();
        t->source_location=i.source_location;
        t->source_location.set_property_class("error label");
        t->source_location.set_comment("error label "+*l_it);
        t->source_location.set("user-provided", true);
      }
    }

    if(i.is_other())
    {
      const irep_idt &statement=i.code.get(ID_statement);

      if(statement==ID_expression)
      {
        check(i.code);
      }
      else if(statement==ID_printf)
      {
        forall_operands(it, i.code)
          check(*it);
      }
    }
    else if(i.is_assign())
    {
      const code_assignt &code_assign=to_code_assign(i.code);

      check(code_assign.lhs());
      check(code_assign.rhs());

      // the LHS might invalidate any assertion
      invalidate(code_assign.lhs());
    }
    else if(i.is_function_call())
    {
      const code_function_callt &code_function_call=
        to_code_function_call(i.code);

      // for Java, need to check whether 'this' is null
      // on non-static method invocations
      if(mode==ID_java &&
         enable_pointer_check &&
         !code_function_call.arguments().empty() &&
         code_function_call.function().type().id()==ID_code &&
         to_code_type(code_function_call.function().type()).has_this())
      {
        exprt pointer=code_function_call.arguments()[0];

        local_bitvector_analysist::flagst flags=
          local_bitvector_analysis->get(t, pointer);

        if(flags.is_unknown() || flags.is_null())
        {
          notequal_exprt not_eq_null(pointer, gen_zero(pointer.type()));

          add_guarded_claim(
            not_eq_null,
            "this is null on method invokation",
            "pointer dereference",
            i.source_location,
            pointer,
            guardt());
        }
      }

      forall_operands(it, code_function_call)
        check(*it);

      // the call might invalidate any assertion
      assertions.clear();
    }
    else if(i.is_return())
    {
      if(i.code.operands().size()==1)
      {
        check(i.code.op0());
        // the return value invalidate any assertion
        invalidate(i.code.op0());
      }
    }
    else if(i.is_throw())
    {
      if(i.code.get_statement()==ID_expression &&
         i.code.operands().size()==1 &&
         i.code.op0().operands().size()==1)
      {
        // must not throw NULL

        exprt pointer=i.code.op0().op0();

        if(pointer.type().subtype().get(ID_identifier)!="java::java.lang.AssertionError")
        {
          notequal_exprt not_eq_null(pointer, gen_zero(pointer.type()));

          add_guarded_claim(
            not_eq_null,
            "throwing null",
            "pointer dereference",
            i.source_location,
            pointer,
            guardt());
        }
      }

      // this has no successor
      assertions.clear();
    }
    else if(i.is_assert())
    {
      if(i.source_location.get_bool("user-provided") &&
         i.source_location.get_property_class()!="error label" &&
         !enable_assertions)
        i.type=SKIP;
    }
    else if(i.is_assume())
    {
      if(!enable_assumptions)
        i.type=SKIP;
    }
    else if(i.is_dead())
    {
      if(enable_pointer_check)
      {
        assert(i.code.operands().size()==1);
        const symbol_exprt &variable=to_symbol_expr(i.code.op0());

        // is it dirty?
        if(local_bitvector_analysis->dirty(variable))
        {
          // need to mark the dead variable as dead
          goto_programt::targett t=new_code.add_instruction(ASSIGN);
          exprt address_of_expr=address_of_exprt(variable);
          exprt lhs=ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
          if(!base_type_eq(lhs.type(), address_of_expr.type(), ns))
            address_of_expr.make_typecast(lhs.type());
          exprt rhs=if_exprt(
            side_effect_expr_nondett(bool_typet()), address_of_expr, lhs, lhs.type());
          t->source_location=i.source_location;
          t->code=code_assignt(lhs, rhs);
          t->code.add_source_location()=i.source_location;
        }
      }
    }
    else if(i.is_end_function())
    {
      if(i.function==goto_functionst::entry_point() &&
         enable_memory_leak_check)
      {
        const symbolt &leak=ns.lookup(CPROVER_PREFIX "memory_leak");
        const symbol_exprt leak_expr=leak.symbol_expr();

        // add self-assignment to get helpful counterexample output
        goto_programt::targett t=new_code.add_instruction();
        t->make_assignment();
        t->code=code_assignt(leak_expr, leak_expr);

        source_locationt source_location;
        source_location.set_function(i.function);

        equal_exprt eq(leak_expr, gen_zero(ns.follow(leak.type)));
        add_guarded_claim(
          eq,
          "dynamically allocated memory never freed",
          "memory-leak",
          source_location,
          eq,
          guardt());
      }
    }

    for(goto_programt::instructionst::iterator
        i_it=new_code.instructions.begin();
        i_it!=new_code.instructions.end();
        i_it++)
    {
      if(i_it->source_location.is_nil())
      {
        i_it->source_location.id(irep_idt());

        if(it->source_location.get_file()!=irep_idt())
          i_it->source_location.set_file(it->source_location.get_file());

        if(it->source_location.get_line()!=irep_idt())
          i_it->source_location.set_line(it->source_location.get_line());

        if(it->source_location.get_function()!=irep_idt())
          i_it->source_location.set_function(it->source_location.get_function());

        if(it->source_location.get_column()!=irep_idt())
          i_it->source_location.set_column(it->source_location.get_column());
      }

      if(i_it->function==irep_idt()) i_it->function=it->function;
    }

    // insert new instructions -- make sure targets are not moved

    while(!new_code.instructions.empty())
    {
      goto_program.insert_before_swap(it, new_code.instructions.front());
      new_code.instructions.pop_front();
      it++;
    }
  }
Beispiel #9
0
void string_instrumentationt::do_strerror(
  goto_programt &dest,
  goto_programt::targett it,
  code_function_callt &call)
{
  if(call.lhs().is_nil())
  {
    it->make_skip();
    return;
  }

  irep_idt identifier_buf="c::__strerror_buffer";
  irep_idt identifier_size="c::__strerror_buffer_size";

  if(context.symbols.find(identifier_buf)==context.symbols.end())
  {
    symbolt new_symbol_size;
    new_symbol_size.base_name="__strerror_buffer_size";
    new_symbol_size.pretty_name=new_symbol_size.base_name;
    new_symbol_size.name=identifier_size;
    new_symbol_size.mode="C";
    new_symbol_size.type=uint_type();
    new_symbol_size.is_statevar=true;
    new_symbol_size.lvalue=true;
    new_symbol_size.static_lifetime=true;

    array_typet type;
    type.subtype()=char_type();
    type.size()=symbol_expr(new_symbol_size);
    symbolt new_symbol_buf;
    new_symbol_buf.mode="C";
    new_symbol_buf.type=type;
    new_symbol_buf.is_statevar=true;
    new_symbol_buf.lvalue=true;
    new_symbol_buf.static_lifetime=true;
    new_symbol_buf.base_name="__strerror_buffer";
    new_symbol_buf.pretty_name=new_symbol_buf.base_name;
    new_symbol_buf.name="c::"+id2string(new_symbol_buf.base_name);

    context.move(new_symbol_buf);
    context.move(new_symbol_size);
  }

  const symbolt &symbol_size=ns.lookup(identifier_size);
  const symbolt &symbol_buf=ns.lookup(identifier_buf);

  goto_programt tmp;

  {  
    goto_programt::targett assignment1=tmp.add_instruction(ASSIGN);
    exprt nondet_size=side_effect_expr_nondett(uint_type());

    assignment1->code=code_assignt(symbol_expr(symbol_size), nondet_size);
    assignment1->location=it->location;
    
    goto_programt::targett assumption1=tmp.add_instruction();

    assumption1->make_assumption(binary_relation_exprt(
      symbol_expr(symbol_size), "notequal",
      gen_zero(symbol_size.type)));

    assumption1->location=it->location;
  }

  // return a pointer to some magic buffer
  exprt index=exprt("index", char_type());
  index.copy_to_operands(symbol_expr(symbol_buf), gen_zero(uint_type()));

  exprt ptr=exprt("address_of", pointer_typet());
  ptr.type().subtype()=char_type();
  ptr.copy_to_operands(index);

  // make that zero-terminated
  {
    goto_programt::targett assignment2=tmp.add_instruction(ASSIGN);
    assignment2->code=code_assignt(is_zero_string(ptr, true), true_exprt());
    assignment2->location=it->location;
  }

  // assign address
  {
    goto_programt::targett assignment3=tmp.add_instruction(ASSIGN);
    exprt rhs=ptr;
    make_type(rhs, call.lhs().type());
    assignment3->code=code_assignt(call.lhs(), rhs);
    assignment3->location=it->location;
  }

  it->make_skip();
  dest.insert_before_swap(it, tmp);
}
Beispiel #10
0
void string_instrumentationt::do_format_string_write(
  goto_programt &dest,
  goto_programt::const_targett target,
  const code_function_callt::argumentst &arguments,
  unsigned format_string_inx,
  unsigned argument_start_inx,
  const std::string &function_name)
{
  const exprt &format_arg = arguments[format_string_inx];
    
  if(format_arg.id()=="address_of" &&
     format_arg.op0().id()=="index" &&
     format_arg.op0().op0().id()==ID_string_constant) // constant format
  {
    format_token_listt token_list;
    parse_format_string(format_arg.op0().op0(), token_list);
    
    unsigned args=0;
    
    for(format_token_listt::const_iterator it=token_list.begin();
        it!=token_list.end();
        it++)
    {
      if(find(it->flags.begin(), it->flags.end(), format_tokent::ASTERISK)!=
         it->flags.end()) 
        continue; // asterisk means `ignore this'
      
      switch(it->type)
      {
        case format_tokent::STRING:
        {
            
          const exprt &argument=arguments[argument_start_inx+args];
          const typet &arg_type=ns.follow(argument.type());
          
          goto_programt::targett assertion=dest.add_instruction();
          assertion->location=target->location;
          assertion->location.set("property", "string");
          std::string comment("format string buffer overflow in ");
          comment += function_name;
          assertion->location.set("comment", comment);
          
          if(it->field_width!=0)
          {
            exprt fwidth = from_integer(it->field_width, uint_type());
            exprt fw_1("+", uint_type());
            exprt one = gen_one(uint_type());
            fw_1.move_to_operands(fwidth);
            fw_1.move_to_operands(one); // +1 for 0-char
            
            exprt fw_lt_bs;
            
            if(arg_type.id()=="pointer")
              fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(argument));
            else
            {
              index_exprt index;
              index.array()=argument;
              index.index()=gen_zero(uint_type());
              address_of_exprt aof(index);
              fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(aof));
            }
            
            assertion->make_assertion(fw_lt_bs);
          }
          else
          {
            // this is a possible overflow.
            assertion->make_assertion(false_exprt());
          }
          
          // now kill the contents
          invalidate_buffer(dest, target, argument, arg_type, it->field_width);
          
          args++;
          break;
        }
        case format_tokent::TEXT:
        case format_tokent::UNKNOWN:
        {          
          // nothing
          break;
        }
        default: // everything else
        {
          const exprt &argument=arguments[argument_start_inx+args];
          const typet &arg_type=ns.follow(argument.type());
          
          goto_programt::targett assignment=dest.add_instruction(ASSIGN);
          assignment->location=target->location;
          
          exprt lhs("dereference", arg_type.subtype());
          lhs.copy_to_operands(argument);
          
          exprt rhs=side_effect_expr_nondett(lhs.type());
          rhs.location()=target->location;
           
          assignment->code=code_assignt(lhs, rhs);
          
          args++;
          break;
        }
      }
    }
  }
  else // non-const format string
  {    
    for(unsigned i=argument_start_inx; i<arguments.size(); i++)
    {    
      const typet &arg_type=ns.follow(arguments[i].type());
      
      // Note: is_string_type() is a `good guess' here. Actually
      // any of the pointers could point into an array. But it
      // would suck if we had to invalidate all variables.
      // Luckily this case isn't needed too often.
      if(is_string_type(arg_type))
      {
        goto_programt::targett assertion=dest.add_instruction();
        assertion->location=target->location;
        assertion->location.set("property", "string");
        std::string comment("format string buffer overflow in ");
        comment += function_name;
        assertion->location.set("comment", comment);

        // as we don't know any field width for the %s that 
        // should be here during runtime, we just report a 
        // possibly false positive
        assertion->make_assertion(false_exprt());
        
        invalidate_buffer(dest, target, arguments[i], arg_type, 0);
      }
      else
      {
        goto_programt::targett assignment = dest.add_instruction(ASSIGN);
        assignment->location=target->location;
        
        exprt lhs("dereference", arg_type.subtype());
        lhs.copy_to_operands(arguments[i]);
        
        exprt rhs=side_effect_expr_nondett(lhs.type());
        rhs.location()=target->location;
         
        assignment->code=code_assignt(lhs, rhs);
      }
    }
  }
}
Beispiel #11
0
void string_instrumentationt::do_strerror(
  goto_programt &dest,
  goto_programt::targett it,
  code_function_callt &call)
{
  if(call.lhs().is_nil())
  {
    it->make_skip();
    return;
  }

  irep_idt identifier_buf="__strerror_buffer";
  irep_idt identifier_size="__strerror_buffer_size";

  if(symbol_table.symbols.find(identifier_buf)==symbol_table.symbols.end())
  {
    symbolt new_symbol_size;
    new_symbol_size.base_name="__strerror_buffer_size";
    new_symbol_size.pretty_name=new_symbol_size.base_name;
    new_symbol_size.name=identifier_size;
    new_symbol_size.mode=ID_C;
    new_symbol_size.type=size_type();
    new_symbol_size.is_state_var=true;
    new_symbol_size.is_lvalue=true;
    new_symbol_size.is_static_lifetime=true;

    array_typet type;
    type.subtype()=char_type();
    type.size()=new_symbol_size.symbol_expr();
    symbolt new_symbol_buf;
    new_symbol_buf.mode=ID_C;
    new_symbol_buf.type=type;
    new_symbol_buf.is_state_var=true;
    new_symbol_buf.is_lvalue=true;
    new_symbol_buf.is_static_lifetime=true;
    new_symbol_buf.base_name="__strerror_buffer";
    new_symbol_buf.pretty_name=new_symbol_buf.base_name;
    new_symbol_buf.name=new_symbol_buf.base_name;

    symbol_table.move(new_symbol_buf);
    symbol_table.move(new_symbol_size);
  }

  const symbolt &symbol_size=ns.lookup(identifier_size);
  const symbolt &symbol_buf=ns.lookup(identifier_buf);

  goto_programt tmp;

  {
    goto_programt::targett assignment1=tmp.add_instruction(ASSIGN);
    exprt nondet_size=side_effect_expr_nondett(size_type());

    assignment1->code=code_assignt(symbol_size.symbol_expr(), nondet_size);
    assignment1->source_location=it->source_location;

    goto_programt::targett assumption1=tmp.add_instruction();

    assumption1->make_assumption(
      binary_relation_exprt(
        symbol_size.symbol_expr(),
        ID_notequal,
        from_integer(0, symbol_size.type)));

    assumption1->source_location=it->source_location;
  }

  // return a pointer to some magic buffer
  index_exprt index(
    symbol_buf.symbol_expr(),
    from_integer(0, index_type()),
    char_type());

  address_of_exprt ptr(index);

  // make that zero-terminated
  {
    goto_programt::targett assignment2=tmp.add_instruction(ASSIGN);
    assignment2->code=code_assignt(is_zero_string(ptr, true), true_exprt());
    assignment2->source_location=it->source_location;
  }

  // assign address
  {
    goto_programt::targett assignment3=tmp.add_instruction(ASSIGN);
    exprt rhs=ptr;
    make_type(rhs, call.lhs().type());
    assignment3->code=code_assignt(call.lhs(), rhs);
    assignment3->source_location=it->source_location;
  }

  it->make_skip();
  dest.insert_before_swap(it, tmp);
}
void goto_convertt::do_scanf(
  const exprt &lhs,
  const exprt &function,
  const exprt::operandst &arguments,
  goto_programt &dest)
{
  const irep_idt &f_id=function.get(ID_identifier);

  if(f_id==CPROVER_PREFIX "scanf")
  {
    if(arguments.size()<1)
    {
      err_location(function);
      error() << "scanf takes at least one argument" << eom;
      throw 0;
    }
    
    irep_idt format_string;
    
    if(!get_string_constant(arguments[0], format_string))
    {
      // use our model
      format_token_listt token_list=parse_format_string(id2string(format_string));
        
      std::size_t argument_number=1;
      
      for(const auto & t : token_list)
      {
        typet type=get_type(t);
      
        if(type.is_not_nil())
        {
          if(argument_number<arguments.size())
          {
            exprt ptr=
              typecast_exprt(arguments[argument_number], pointer_type(type));
            argument_number++;

            // make it nondet for now
            exprt lhs=dereference_exprt(ptr, type);
            exprt rhs=side_effect_expr_nondett(type);
            code_assignt assign(lhs, rhs);
            assign.add_source_location()=function.source_location();
            copy(assign, ASSIGN, dest);
          }
        }
      }
    }
    else
    {
      // we'll just do nothing
      code_function_callt function_call;
      function_call.lhs()=lhs;
      function_call.function()=function;
      function_call.arguments()=arguments;
      function_call.add_source_location()=function.source_location();

      copy(function_call, FUNCTION_CALL, dest);
    }
  }
  else
    assert(false);
}
void goto_convertt::do_function_call_symbol(
  const exprt &lhs,
  const symbol_exprt &function,
  const exprt::operandst &arguments,
  goto_programt &dest)
{
  if(function.get_bool("#invalid_object"))
    return; // ignore

  // lookup symbol
  const irep_idt &identifier=function.get_identifier();

  const symbolt *symbol;
  if(ns.lookup(identifier, symbol))
  {
    err_location(function);
    throw "error: function `"+id2string(identifier)+"' not found";
  }

  if(symbol->type.id()!=ID_code)
  {
    err_location(function);
    throw "error: function `"+id2string(identifier)+"' type mismatch: expected code";
  }
  
  if(identifier==CPROVER_PREFIX "assume" ||
     identifier=="__VERIFIER_assume")
  {
    if(arguments.size()!=1)
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have one argument";
    }

    goto_programt::targett t=dest.add_instruction(ASSUME);
    t->guard=arguments.front();
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    
    // let's double-check the type of the argument
    if(t->guard.type().id()!=ID_bool)
      t->guard.make_typecast(bool_typet());

    if(lhs.is_not_nil())
    {
      err_location(function);
      throw id2string(identifier)+" expected not to have LHS";
    }
  }
  else if(identifier=="__VERIFIER_error")
  {
    if(!arguments.empty())
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have no arguments";
    }

    goto_programt::targett t=dest.add_instruction(ASSERT);
    t->guard=false_exprt();
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    t->source_location.set_property_class(ID_assertion);

    if(lhs.is_not_nil())
    {
      err_location(function);
      throw id2string(identifier)+" expected not to have LHS";
    }
  }
  else if(has_prefix(id2string(identifier), "java::java.lang.AssertionError.<init>:"))
  {
    // insert function call anyway
    code_function_callt function_call;
    function_call.lhs()=lhs;
    function_call.function()=function;
    function_call.arguments()=arguments;
    function_call.add_source_location()=function.source_location();

    copy(function_call, FUNCTION_CALL, dest);

    if(arguments.size()!=1 && arguments.size()!=2)
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have one or two arguments";
    }

    goto_programt::targett t=dest.add_instruction(ASSERT);
    t->guard=false_exprt();
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    t->source_location.set_property_class(ID_assertion);    
    t->source_location.set_comment("assertion at "+function.source_location().as_string());
  }
  else if(identifier=="assert" &&
          !ns.lookup(identifier).location.get_function().empty())
  {
    if(arguments.size()!=1)
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have one argument";
    }

    goto_programt::targett t=dest.add_instruction(ASSERT);
    t->guard=arguments.front();
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    t->source_location.set_property_class(ID_assertion);
    t->source_location.set_comment("assertion "+id2string(from_expr(ns, "", t->guard)));
    
    // let's double-check the type of the argument
    if(t->guard.type().id()!=ID_bool)
      t->guard.make_typecast(bool_typet());

    if(lhs.is_not_nil())
    {
      err_location(function);
      throw id2string(identifier)+" expected not to have LHS";
    }
  }
  else if(identifier==CPROVER_PREFIX "assert")
  {
    if(arguments.size()!=2)
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have two arguments";
    }
    
    const irep_idt description=
      get_string_constant(arguments[1]);

    goto_programt::targett t=dest.add_instruction(ASSERT);
    t->guard=arguments[0];
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    t->source_location.set_property_class(ID_assertion);
    t->source_location.set_comment(description);
    
    // let's double-check the type of the argument
    if(t->guard.type().id()!=ID_bool)
      t->guard.make_typecast(bool_typet());

    if(lhs.is_not_nil())
    {
      err_location(function);
      throw id2string(identifier)+" expected not to have LHS";
    }
  }
  else if(identifier==CPROVER_PREFIX "printf")
  {
    do_printf(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "scanf")
  {
    do_scanf(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "input" ||
          identifier=="__CPROVER::input")
  {
    do_input(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "output" ||
          identifier=="__CPROVER::output")
  {
    do_output(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "atomic_begin" ||
          identifier=="__CPROVER::atomic_begin" ||
          identifier=="__VERIFIER_atomic_begin")
  {
    do_atomic_begin(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "atomic_end" ||
          identifier=="__CPROVER::atomic_end" ||
          identifier=="__VERIFIER_atomic_end")
  {
    do_atomic_end(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "prob_biased_coin")
  {
    do_prob_coin(lhs, function, arguments, dest);
  }
  else if(has_prefix(id2string(identifier), CPROVER_PREFIX "prob_uniform_"))
  {
    do_prob_uniform(lhs, function, arguments, dest);
  }
  else if(has_prefix(id2string(identifier), "nondet_") ||
          has_prefix(id2string(identifier), "__VERIFIER_nondet_"))
  {
    // make it a side effect if there is an LHS
    if(lhs.is_nil()) return;
    
    exprt rhs;
    
    // We need to special-case for _Bool, which
    // can only be 0 or 1.
    if(lhs.type().id()==ID_c_bool)
    {
      rhs=side_effect_expr_nondett(bool_typet());
      rhs.add_source_location()=function.source_location();
      rhs.set(ID_C_identifier, identifier);
      rhs=typecast_exprt(rhs, lhs.type());
    } 
    else
    {
      rhs=side_effect_expr_nondett(lhs.type());
      rhs.add_source_location()=function.source_location();
      rhs.set(ID_C_identifier, identifier);
    }

    code_assignt assignment(lhs, rhs);
    assignment.add_source_location()=function.source_location();
    copy(assignment, ASSIGN, dest);
  }
  else if(has_prefix(id2string(identifier), CPROVER_PREFIX "uninterpreted_"))
  {
    // make it a side effect if there is an LHS
    if(lhs.is_nil()) return;

    function_application_exprt rhs;
    rhs.type()=lhs.type();
    rhs.add_source_location()=function.source_location();
    rhs.function()=function;
    rhs.arguments()=arguments;

    code_assignt assignment(lhs, rhs);
    assignment.add_source_location()=function.source_location();
    copy(assignment, ASSIGN, dest);
  }
  else if(has_prefix(id2string(identifier), CPROVER_PREFIX "array_set"))
  {
    do_array_set(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "array_equal" ||
          identifier=="__CPROVER::array_equal")
  {
    do_array_equal(lhs, function, arguments, dest);
  }
  else if(identifier==CPROVER_PREFIX "array_copy" ||
          identifier=="__CPROVER::array_equal")
  {
    do_array_copy(lhs, function, arguments, dest);
  }
  else if(identifier=="printf")
  /*
          identifier=="fprintf" ||
          identifier=="sprintf" ||
          identifier=="snprintf")
  */
  {
    do_printf(lhs, function, arguments, dest);
  }
  else if(identifier=="__assert_fail" ||
          identifier=="_assert" ||
          identifier=="__assert_c99" ||
          identifier=="_wassert")
  {
    // __assert_fail is Linux
    // These take four arguments:
    // "expression", "file.c", line, __func__
    // klibc has __assert_fail with 3 arguments
    // "expression", "file.c", line

    // MingW has
    // void _assert (const char*, const char*, int);
    // with three arguments:
    // "expression", "file.c", line

    // This has been seen in Solaris 11.
    // Signature:
    // void __assert_c99(const char *desc, const char *file, int line, const char *func);

    // _wassert is Windows. The arguments are
    // L"expression", L"file.c", line

    if(arguments.size()!=4 &&
       arguments.size()!=3)
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have four arguments";
    }
    
    const irep_idt description=
      "assertion "+id2string(get_string_constant(arguments[0]));

    goto_programt::targett t=dest.add_instruction(ASSERT);
    t->guard=false_exprt();
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    t->source_location.set_property_class(ID_assertion);
    t->source_location.set_comment(description);
    // we ignore any LHS
  }
  else if(identifier=="__assert_rtn" ||
          identifier=="__assert")
  {
    // __assert_rtn has been seen on MacOS;
    // __assert is FreeBSD and Solaris 11.
    // These take four arguments:
    // __func__, "file.c", line, "expression"
    // On Solaris 11, it's three arguments:
    // "expression", "file", line
    
    irep_idt description;
    
    if(arguments.size()==4)
    {
      description=
        "assertion "+id2string(get_string_constant(arguments[3]));
    }
    else if(arguments.size()==3)
    {
      description=
        "assertion "+id2string(get_string_constant(arguments[1]));
    }
    else
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have four arguments";
    }

    goto_programt::targett t=dest.add_instruction(ASSERT);
    t->guard=false_exprt();
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    t->source_location.set_property_class(ID_assertion);
    t->source_location.set_comment(description);
    // we ignore any LHS
  }
  else if(identifier=="__assert_func")
  {
    // __assert_func is newlib (used by, e.g., cygwin)
    // These take four arguments:
    // "file.c", line, __func__, "expression"
    if(arguments.size()!=4)
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have four arguments";
    }

    const irep_idt description=
      "assertion "+id2string(get_string_constant(arguments[3]));

    goto_programt::targett t=dest.add_instruction(ASSERT);
    t->guard=false_exprt();
    t->source_location=function.source_location();
    t->source_location.set("user-provided", true);
    t->source_location.set_property_class(ID_assertion);
    t->source_location.set_comment(description);
    // we ignore any LHS
  }
  else if(identifier==CPROVER_PREFIX "fence")
  {
    if(arguments.size()<1)
    {
      err_location(function);
      throw "`"+id2string(identifier)+"' expected to have at least one argument";
    }

    goto_programt::targett t=dest.add_instruction(OTHER);
    t->source_location=function.source_location();
    t->code.set(ID_statement, ID_fence);

    forall_expr(it, arguments)
    {
      const irep_idt kind=get_string_constant(*it);
      t->code.set(kind, true);
    }
  }
  else if(identifier=="__builtin_prefetch")
Beispiel #14
0
  Forall_goto_program_instructions(i_it, goto_program)
  {
    if(i_it->is_function_call())
    {
      code_function_callt &function_call=to_code_function_call(i_it->code);

      code_typet old_type=to_code_type(function_call.function().type());

      // Do we return anything?
      if(old_type.return_type()!=empty_typet())
      {
        // replace "lhs=f(...)" by
        // "f(...); lhs=f#return_value; DEAD f#return_value;"
        assert(function_call.function().id()==ID_symbol);

        const irep_idt function_id=
          to_symbol_expr(function_call.function()).get_identifier();

        // see if we have a body
        goto_functionst::function_mapt::const_iterator
          f_it=goto_functions.function_map.find(function_id);

        if(f_it==goto_functions.function_map.end())
          throw
            "failed to find function `"+id2string(function_id)+
            "' in function map";

        // fix the type
        to_code_type(function_call.function().type()).return_type()=
          empty_typet();

        if(function_call.lhs().is_not_nil())
        {
          exprt rhs;

          if(f_it->second.body_available())
          {
            symbol_exprt return_value;
            return_value.type()=function_call.lhs().type();
            return_value.set_identifier(
              id2string(function_id)+RETURN_VALUE_SUFFIX);
            rhs=return_value;
          }
          else
          {
            rhs=side_effect_expr_nondett(function_call.lhs().type());
          }

          goto_programt::targett t_a=goto_program.insert_after(i_it);
          t_a->make_assignment();
          t_a->source_location=i_it->source_location;
          t_a->code=code_assignt(function_call.lhs(), rhs);
          t_a->function=i_it->function;

          // fry the previous assignment
          function_call.lhs().make_nil();

          if(f_it->second.body_available())
          {
            goto_programt::targett t_d=goto_program.insert_after(t_a);
            t_d->make_dead();
            t_d->source_location=i_it->source_location;
            t_d->code=code_deadt(rhs);
            t_d->function=i_it->function;
          }
        }
      }
    }
  }
Beispiel #15
0
void goto_inlinet::parameter_assignments(
  const source_locationt &source_location,
  const irep_idt &function_name,
  const code_typet &code_type,
  const exprt::operandst &arguments,
  goto_programt &dest)
{
  // iterates over the operands
  exprt::operandst::const_iterator it1=arguments.begin();

  const code_typet::parameterst &parameter_types=
    code_type.parameters();
  
  // iterates over the types of the parameters
  for(code_typet::parameterst::const_iterator
      it2=parameter_types.begin();
      it2!=parameter_types.end();
      it2++)
  {
    const code_typet::parametert &parameter=*it2;

    // this is the type the n-th argument should be
    const typet &par_type=ns.follow(parameter.type());

    const irep_idt &identifier=parameter.get_identifier();

    if(identifier==irep_idt())
    {
      error().source_location=source_location;
      error() << "no identifier for function parameter" << eom;
      throw 0;
    }

    {
      const symbolt &symbol=ns.lookup(identifier);

      goto_programt::targett decl=dest.add_instruction();
      decl->make_decl();
      decl->code=code_declt(symbol.symbol_expr());
      decl->code.add_source_location()=source_location;
      decl->source_location=source_location;
      decl->function=function_name; 
    }

    // this is the actual parameter
    exprt actual;

    // if you run out of actual arguments there was a mismatch
    if(it1==arguments.end())
    {
      warning().source_location=source_location;
      warning() << "call to `" << function_name << "': "
                << "not enough arguments, "
                << "inserting non-deterministic value" << eom;

      actual=side_effect_expr_nondett(par_type);
    }
    else
      actual=*it1;

    // nil means "don't assign"
    if(actual.is_nil())
    {    
    }
    else
    {
      // it should be the same exact type as the parameter,
      // subject to some exceptions
      if(!base_type_eq(par_type, actual.type(), ns))
      {
        const typet &f_partype = ns.follow(par_type);
        const typet &f_acttype = ns.follow(actual.type());
        
        // we are willing to do some conversion
        if((f_partype.id()==ID_pointer &&
            f_acttype.id()==ID_pointer) ||
           (f_partype.id()==ID_pointer &&
            f_acttype.id()==ID_array &&
            f_partype.subtype()==f_acttype.subtype()))
        {
          actual.make_typecast(par_type);
        }
        else if((f_partype.id()==ID_signedbv ||
                 f_partype.id()==ID_unsignedbv ||
                 f_partype.id()==ID_bool) &&
                (f_acttype.id()==ID_signedbv ||
                 f_acttype.id()==ID_unsignedbv ||
                 f_acttype.id()==ID_bool))  
        {
          actual.make_typecast(par_type);
        }
        else
        {
          error().source_location=actual.find_source_location();

          error() << "function call: argument `" << identifier
                  << "' type mismatch: argument is `"
                  // << from_type(ns, identifier, actual.type())
                  << actual.type().pretty()
                  << "', parameter is `"
                  << from_type(ns, identifier, par_type)
                  << "'" << eom;
          throw 0;
        }
      }

      // adds an assignment of the actual parameter to the formal parameter
      code_assignt assignment(symbol_exprt(identifier, par_type), actual);
      assignment.add_source_location()=source_location;

      dest.add_instruction(ASSIGN);
      dest.instructions.back().source_location=source_location;
      dest.instructions.back().code.swap(assignment);
      dest.instructions.back().function=function_name;      
    }

    if(it1!=arguments.end())
      ++it1;
  }

  if(it1!=arguments.end())
  {
    // too many arguments -- we just ignore that, no harm done
  }
}
Beispiel #16
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;
}
Beispiel #17
0
void string_instrumentationt::invalidate_buffer(
  goto_programt &dest,
  goto_programt::const_targett target,
  const exprt &buffer,
  const typet &buf_type,
  const mp_integer &limit)
{
  irep_idt cntr_id="string_instrumentation::$counter";
  
  if(context.symbols.find(cntr_id)==context.symbols.end())
  {
    symbolt new_symbol;
    new_symbol.base_name="$counter";
    new_symbol.pretty_name=new_symbol.base_name;
    new_symbol.name=cntr_id;
    new_symbol.mode="C";
    new_symbol.type=uint_type();
    new_symbol.is_statevar=true;
    new_symbol.lvalue=true;
    new_symbol.static_lifetime=true;
    
    context.move(new_symbol);
  }
  
  const symbolt &cntr_sym=ns.lookup(cntr_id);
  
  // create a loop that runs over the buffer
  // and invalidates every element
  
  goto_programt::targett init=dest.add_instruction(ASSIGN);
  init->location=target->location;  
  init->code=code_assignt(symbol_expr(cntr_sym), gen_zero(cntr_sym.type));
  
  goto_programt::targett check=dest.add_instruction();
  check->location=target->location;  
  
  goto_programt::targett invalidate=dest.add_instruction(ASSIGN);
  invalidate->location=target->location;  
  
  goto_programt::targett increment=dest.add_instruction(ASSIGN);
  increment->location=target->location;  
  
  exprt plus("+", uint_type());
  plus.copy_to_operands(symbol_expr(cntr_sym));
  plus.copy_to_operands(gen_one(uint_type()));
  
  increment->code=code_assignt(symbol_expr(cntr_sym), plus);
  
  goto_programt::targett back=dest.add_instruction();
  back->location=target->location;  
  back->make_goto(check);
  back->guard=true_exprt();
  
  goto_programt::targett exit=dest.add_instruction();
  exit->location=target->location;  
  exit->make_skip();  
  
  exprt cnt_bs, bufp;
  
  if(buf_type.id()=="pointer")
    bufp = buffer;
  else
  {
    index_exprt index;
    index.array()=buffer;
    index.index()=gen_zero(uint_type());
    index.type()=buf_type.subtype();
    bufp = address_of_exprt(index);
  }
  
  exprt deref("dereference", buf_type.subtype());
  exprt b_plus_i("+", bufp.type());
  b_plus_i.copy_to_operands(bufp);
  b_plus_i.copy_to_operands(symbol_expr(cntr_sym));
  deref.copy_to_operands(b_plus_i);
  
  check->make_goto(exit);
  
  if(limit==0)
    check->guard=
          binary_relation_exprt(symbol_expr(cntr_sym), ">=", 
                                buffer_size(bufp));
  else
    check->guard=
          binary_relation_exprt(symbol_expr(cntr_sym), ">", 
                                from_integer(limit, uint_type()));
  
  exprt nondet=side_effect_expr_nondett(buf_type.subtype());
  invalidate->code=code_assignt(deref, nondet);
}