Example #1
0
void havoc_loopst::get_modifies(
  const loopt &loop,
  modifiest &modifies)
{
  for(loopt::const_iterator
      i_it=loop.begin(); i_it!=loop.end(); i_it++)
  {
    const goto_programt::instructiont &instruction=**i_it;

    if(instruction.is_assign())
    {
      const exprt &lhs=to_code_assign(instruction.code).lhs();
      function_modifies.get_modifies_lhs(local_may_alias, *i_it, lhs, modifies);
    }
    else if(instruction.is_function_call())
    {
      const code_function_callt &code_function_call=
        to_code_function_call(instruction.code);
      const exprt &lhs=code_function_call.lhs();

      // return value assignment
      if(lhs.is_not_nil())
        function_modifies.get_modifies_lhs(
          local_may_alias, *i_it, lhs, modifies);

      function_modifies(code_function_call.function(), modifies);
    }
  }
}
Example #2
0
void local_SSAt::build_transfer(locationt loc)
{
  if(loc->is_assign())
  {
    const code_assignt &code_assign=to_code_assign(loc->code);

    exprt deref_lhs=dereference(code_assign.lhs(), loc);
    exprt deref_rhs=dereference(code_assign.rhs(), loc);

    assign_rec(deref_lhs, deref_rhs, true_exprt(), loc);
  }
  else if(loc->is_function_call())
  {
    const code_function_callt &code_function_call=
      to_code_function_call(loc->code);
      
    const exprt &lhs=code_function_call.lhs();
      
    if(lhs.is_not_nil())
    {
      exprt deref_lhs=dereference(lhs, loc);
    
      // generate a symbol for rhs
      irep_idt identifier="ssa::return_value"+i2string(loc->location_number);
      symbol_exprt rhs(identifier, code_function_call.lhs().type());
      
      assign_rec(deref_lhs, rhs, true_exprt(), loc);
    }
  }
}
Example #3
0
void function_modifiest::get_modifies(
  const local_may_aliast &local_may_alias,
  const goto_programt::const_targett i_it,
  modifiest &modifies)
{
  const goto_programt::instructiont &instruction=*i_it;

  if(instruction.is_assign())
  {
    const exprt &lhs=to_code_assign(instruction.code).lhs();
    get_modifies_lhs(local_may_alias, i_it, lhs, modifies);
  }
  else if(instruction.is_function_call())
  {
    const code_function_callt &code_function_call=
      to_code_function_call(instruction.code);
    const exprt &lhs=code_function_call.lhs();

    // return value assignment
    if(lhs.is_not_nil())
      get_modifies_lhs(local_may_alias, i_it, lhs, modifies);

    get_modifies_function(
      code_function_call.function(), modifies);
  }
}
bool remove_virtual_functionst::remove_virtual_functions(
  goto_programt &goto_program)
{
  bool did_something=false;

  Forall_goto_program_instructions(target, goto_program)
    if(target->is_function_call())
    {
      const code_function_callt &code=
        to_code_function_call(target->code);

      if(code.function().id()==ID_virtual_function)
      {
        remove_virtual_function(goto_program, target);
        did_something=true;
      }
    }

  if(did_something)
  {
    goto_program.update();
  }

  return did_something;
}
Example #5
0
void thread_exit_instrumentation(goto_functionst &goto_functions)
{
  // we'll look for START THREAD
  std::set<irep_idt> thread_fkts;

  forall_goto_functions(f_it, goto_functions)
  {
    if(has_start_thread(f_it->second.body))
    {
      // now look for functions called

      for(const auto &instruction : f_it->second.body.instructions)
        if(instruction.is_function_call())
        {
          const exprt &function=to_code_function_call(instruction.code).function();
          if(function.id()==ID_symbol)
            thread_fkts.insert(to_symbol_expr(function).get_identifier());
        }
    }
  }

  // now instrument
  for(const auto &fkt : thread_fkts)
  {
    thread_exit_instrumentation(goto_functions.function_map[fkt].body);
  }
}
Example #6
0
void concurrency_instrumentationt::instrument(
  goto_programt &goto_program,
  const is_threadedt &is_threaded)
{
  for(goto_programt::instructionst::iterator
      it=goto_program.instructions.begin();
      it!=goto_program.instructions.end();
      it++)
  {
    if(it->is_assign())
    {
      code_assignt &code=to_code_assign(it->code);
      instrument(code.rhs());
    }
    else if(it->is_assume() || it->is_assert() || it->is_goto())
      instrument(it->guard);
    else if(it->is_function_call())
    {
      code_function_callt &code=to_code_function_call(it->code);
      instrument(code.function());

      //instrument(code.lhs(), LHS);
      Forall_expr(it, code.arguments())
        instrument(*it);
    }
  }
}
Example #7
0
goto_programt::const_targett termination_baset::find_next_loop(
  goto_programt::const_targett current,
  const goto_programt &program,
  std::list<goto_programt::const_targett> &recursion_stack) const
{
  /* The program contains only termination-assertions, i.e.,
     we look only for assertions. */

  current++;

  while(current!=program.instructions.end())
  {
    switch(current->type)
    {
      case ASSERT:
          return current;
      case FUNCTION_CALL:
        {
          const code_function_callt &code=to_code_function_call(current->code);
          const irep_idt &fid=code.function().get("identifier");

          goto_functionst::function_mapt::const_iterator fit=
              goto_functions.function_map.find(fid);

          if(fit==goto_functions.function_map.end() ||
             fit->second.body.instructions.empty())
            current++; // ignore the call
          else
          {
            if(std::find(recursion_stack.begin(),
                         recursion_stack.end(),
                         current) == recursion_stack.end())
            {
              recursion_stack.push_back(current);
              current=fit->second.body.instructions.begin();
            }
            else
              current++; // no recursion necessary
          }
        }
        break;
      case END_FUNCTION:
        if(!recursion_stack.empty())
        {
          current=recursion_stack.back();
          recursion_stack.pop_back();
        }
        current++;
        break;
      default:
        current++;
    }
  }

  assert(recursion_stack.empty());

  // no more assertions
  return program.instructions.end();
}
Example #8
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;
          
          symbol_exprt return_value;
          return_value.type()=function_call.lhs().type();
          return_value.set_identifier(id2string(function_id)+RETURN_VALUE_SUFFIX);
          rhs=return_value;

          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;
          }
        }
      }
    }
  }
void java_bytecode_typecheckt::typecheck_code(codet &code)
{
  const irep_idt &statement=code.get_statement();

  if(statement==ID_assign)
  {
    code_assignt &code_assign=to_code_assign(code);
    typecheck_expr(code_assign.lhs());
    typecheck_expr(code_assign.rhs());

    if(code_assign.lhs().type()!=code_assign.rhs().type())
      code_assign.rhs().make_typecast(code_assign.lhs().type());
  }
  else if(statement==ID_block)
  {
    Forall_operands(it, code)
      typecheck_code(to_code(*it));
  }
  else if(statement==ID_label)
  {
    code_labelt &code_label=to_code_label(code);
    typecheck_code(code_label.code());
  }
  else if(statement==ID_goto)
  {
  }
  else if(statement==ID_ifthenelse)
  {
    code_ifthenelset &code_ifthenelse=to_code_ifthenelse(code);
    typecheck_expr(code_ifthenelse.cond());
    typecheck_code(code_ifthenelse.then_case());
    if(code_ifthenelse.else_case().is_not_nil())
      typecheck_code(code_ifthenelse.else_case());
  }
  else if(statement==ID_switch)
  {
    code_switcht &code_switch = to_code_switch(code);
    typecheck_expr(code_switch.value());
  }
  else if(statement==ID_return)
  {
    if(code.operands().size()==1)
      typecheck_expr(code.op0());
  }
  else if(statement==ID_function_call)
  {
    code_function_callt &code_function_call=to_code_function_call(code);
    typecheck_expr(code_function_call.lhs());
    typecheck_expr(code_function_call.function());

    for(code_function_callt::argumentst::iterator
        a_it=code_function_call.arguments().begin();
        a_it!=code_function_call.arguments().end();
        a_it++)
      typecheck_expr(*a_it);
  }
}
Example #10
0
void goto_program_dereferencet::dereference_instruction(
  goto_programt::targett target,
  bool checks_only)
{
  current_target=target;
  #if 0
  valid_local_variables=&target->local_variables;
  #endif
  goto_programt::instructiont &i=*target;

  dereference_expr(i.guard, checks_only, value_set_dereferencet::READ);

  if(i.is_assign())
  {
    if(i.code.operands().size()!=2)
      throw "assignment expects two operands";

    dereference_expr(i.code.op0(), checks_only, value_set_dereferencet::WRITE);
    dereference_expr(i.code.op1(), checks_only, value_set_dereferencet::READ);
  }
  else if(i.is_function_call())
  {
    code_function_callt &function_call=to_code_function_call(to_code(i.code));
    
    if(function_call.lhs().is_not_nil())
      dereference_expr(function_call.lhs(), checks_only, value_set_dereferencet::WRITE);
    
    dereference_expr(function_call.function(), checks_only, value_set_dereferencet::READ);
    dereference_expr(function_call.op2(), checks_only, value_set_dereferencet::READ);
  }
  else if(i.is_return())
  {
    Forall_operands(it, i.code)
      dereference_expr(*it, checks_only, value_set_dereferencet::READ);
  }
  else if(i.is_other())
  {
    const irep_idt &statement=i.code.get(ID_statement);

    if(statement==ID_expression)
    {
      if(i.code.operands().size()!=1)
        throw "expression expects one operand";

      dereference_expr(i.code.op0(), checks_only, value_set_dereferencet::READ);
    }
    else if(statement==ID_printf)
    {
      Forall_operands(it, i.code)
        dereference_expr(*it, checks_only, value_set_dereferencet::READ);
    }
  }
}
Example #11
0
void jsil_typecheckt::typecheck_try_catch(code_try_catcht &code)
{
  // A special case of try catch with one catch clause
  if(code.operands().size()!=3)
    throw "try_catch expected to have three operands";

  // function call
  typecheck_function_call(to_code_function_call(code.try_code()));

  // catch decl is not used, but is required by goto-programs

  typecheck_code(code.get_catch_code(0));
}
Example #12
0
void string_instrumentationt::do_function_call(
  goto_programt &dest,
  goto_programt::targett target)
{
  code_function_callt &call=
    to_code_function_call(target->code);
  exprt &function=call.function();
  //const exprt &lhs=call.lhs();
  
  if(function.id()=="symbol")
  {
    const irep_idt &identifier=
      to_symbol_expr(function).get_identifier();

    if(identifier=="c::strcoll")
    {
    }
    else if(identifier=="c::strncmp")
      do_strncmp(dest, target, call);
    else if(identifier=="c::strxfrm")
    {
    }
    else if(identifier=="c::strchr")
      do_strchr(dest, target, call);
    else if(identifier=="c::strcspn")
    {
    }
    else if(identifier=="c::strpbrk")
    {
    }
    else if(identifier=="c::strrchr")
      do_strrchr(dest, target, call);
    else if(identifier=="c::strspn")
    {
    }
    else if(identifier=="c::strerror")
      do_strerror(dest, target, call);
    else if(identifier=="c::strstr")
      do_strstr(dest, target, call);
    else if(identifier=="c::strtok")
      do_strtok(dest, target, call);
    else if(identifier=="c::sprintf")
      do_sprintf(dest, target, call);
    else if(identifier=="c::snprintf")
      do_snprintf(dest, target, call);
    else if(identifier=="c::fscanf")
      do_fscanf(dest, target, call);
    
    dest.update();
  }
}
Example #13
0
void interval_domaint::transform(
  locationt from,
  locationt to,
  ai_baset &ai,
  const namespacet &ns)
{
  const goto_programt::instructiont &instruction=*from;
  switch(instruction.type)
  {
  case DECL:
    havoc_rec(to_code_decl(instruction.code).symbol());
    break;

  case DEAD:
    havoc_rec(to_code_dead(instruction.code).symbol());
    break;

  case ASSIGN:
    assign(to_code_assign(instruction.code));
    break;

  case GOTO:
    {
      locationt next=from;
      next++;
      if(next==to)
        assume(not_exprt(instruction.guard), ns);
      else
        assume(instruction.guard, ns);
    }
    break;

  case ASSUME:
    assume(instruction.guard, ns);
    break;

  case FUNCTION_CALL:
    {
      const code_function_callt &code_function_call=
        to_code_function_call(instruction.code);
      if(code_function_call.lhs().is_not_nil())
        havoc_rec(code_function_call.lhs());
    }
    break;

  default:
    {
    }
  }
}
Example #14
0
void remove_return(goto_programt &body, const goto_programt::targett pos)
{
  code_function_callt &call=to_code_function_call(pos->code);
  const irep_idt &id=to_symbol_expr(call.function()).get_identifier();
  const typet &type=call.lhs().type();
  const source_locationt &loc=pos->source_location;
  const irep_idt &func=pos->function;
  const goto_programt::targett assign=body.insert_after(pos);
  assign->make_assignment();
  assign->source_location=loc;
  assign->code=code_assignt(call.lhs(), get_ret_val_var(id, type));
  assign->function=func;
  call.lhs().make_nil();
}
Example #15
0
std::string expr2javat::convert_code(
  const codet &src,
  unsigned indent)
{
  const irep_idt &statement=src.get(ID_statement);

  if(statement==ID_java_new ||
     statement==ID_java_new_array)
    return convert_java_new(src,indent);

  if(statement==ID_function_call)
    return convert_code_function_call(to_code_function_call(src), indent);

  return expr2ct::convert_code(src, indent);
}
Example #16
0
bool is_nondet(goto_programt::const_targett target,
    goto_programt::const_targett end)
{
  const goto_programt::instructiont &instr=*target;
  switch (instr.type)
  {
  case goto_program_instruction_typet::DECL:
  {
    goto_programt::const_targett next=std::next(target);
    if (next == end) return true;
    if (goto_program_instruction_typet::FUNCTION_CALL == next->type)
    {
      if (to_code_function_call(next->code).lhs().is_not_nil()) return false;
      else ++next;
    }
    const goto_programt::instructiont next_instr=*next;
    if (goto_program_instruction_typet::ASSIGN != next_instr.type) return true;
    const irep_idt id(get_affected_variable(instr));
    if (id != get_affected_variable(next_instr)) return true;
    return contains(to_code_assign(next_instr.code).rhs(), id);
  }
  case goto_program_instruction_typet::ASSIGN:
  {
    const exprt &rhs=to_code_assign(instr.code).rhs();
    if (ID_side_effect != rhs.id()) return false;
    return ID_nondet == to_side_effect_expr(rhs).get_statement();
  }
  case goto_program_instruction_typet::FUNCTION_CALL:
  {
    const code_function_callt &call=to_code_function_call(instr.code);
    if (call.lhs().is_not_nil()) return false;
  }
  default:
    return false;
  }
}
Example #17
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());
    }
  }
}
Example #18
0
exprt static_analysis_baset::get_return_lhs(locationt to)
{
  // get predecessor of "to"

  to--;

  if(to->is_end_function())
    return static_cast<const exprt &>(get_nil_irep());
  
  // must be the function call
  assert(to->is_function_call());

  const code_function_callt &code=
    to_code_function_call(to->code);
  
  return code.lhs();
}
Example #19
0
exprt flow_insensitive_abstract_domain_baset::get_return_lhs(locationt to) const
{
  // get predecessor of "to"

  to--;

  if(to->is_end_function())
    return static_cast<const exprt &>(get_nil_irep());

  // must be the function call
  assert(to->is_function_call());

  const code_function_callt &code=
    to_code_function_call(to_code(to->code));

  return code.lhs();
}
Example #20
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);

      // add x=y for f(y) where x is the parameter

      assert(function_call.function().id()==ID_symbol);

      const irep_idt &identifier=
        to_symbol_expr(function_call.function()).get_identifier();

      // see if we have it
      const namespacet ns(symbol_table);
      const symbolt &function_symbol=ns.lookup(identifier);
      const code_typet &code_type=to_code_type(function_symbol.type);

      goto_programt tmp;

      for(std::size_t nr=0; nr<code_type.parameters().size(); nr++)
      {
        irep_idt p_identifier=code_type.parameters()[nr].get_identifier();

        if(p_identifier.empty()) continue;

        if(nr<function_call.arguments().size())
        {
          goto_programt::targett t=tmp.add_instruction();
          t->make_assignment();
          t->source_location=i_it->source_location;
          const symbolt &lhs_symbol=ns.lookup(p_identifier);
          symbol_exprt lhs=lhs_symbol.symbol_expr();
          exprt rhs=function_call.arguments()[nr];
          if(rhs.type()!=lhs.type()) rhs.make_typecast(lhs.type());
          t->code=code_assignt(lhs, rhs);
          t->function=i_it->function;
        }
      }

      std::size_t count=tmp.instructions.size();
      goto_program.insert_before_swap(i_it, tmp);

      for(; count!=0; count--) i_it++;
    }
  }
bool value_set_domain_fivrnst::transform(
  const namespacet &ns,
  locationt from_l,
  locationt to_l)
{
  value_set.set_from(from_l->function, from_l->location_number);
  value_set.set_to(to_l->function, to_l->location_number);

  #if 0
  std::cout << "Transforming: " <<
    from_l->function << " " << from_l->location_number << " to " <<
    to_l->function << " " << to_l->location_number << '\n';
  #endif

  switch(from_l->type)
  {
  case END_FUNCTION:
    value_set.do_end_function(get_return_lhs(to_l), ns);
    break;

  case RETURN:
  case OTHER:
  case ASSIGN:
    value_set.apply_code(from_l->code, ns);
    break;

  case FUNCTION_CALL:
    {
      const code_function_callt &code=
        to_code_function_call(from_l->code);

      value_set.do_function_call(to_l->function, code.arguments(), ns);
      break;
    }

  default:
    {
    }
  }

  return value_set.handover();
}
Example #22
0
void jsil_typecheckt::typecheck_code(codet &code)
{
  const irep_idt &statement=code.get_statement();

  if(statement==ID_function_call)
    typecheck_function_call(to_code_function_call(code));
  else if(statement==ID_return)
    typecheck_return(to_code_return(code));
  else if(statement==ID_expression)
  {
    if(code.operands().size()!=1)
      throw "expression statement expected to have one operand";

    typecheck_expr(code.op0());
  }
  else if(statement==ID_label)
  {
    typecheck_code(to_code_label(code).code());
    // TODO: produce defined label set
  }
  else if(statement==ID_block)
    typecheck_block(code);
  else if(statement==ID_ifthenelse)
    typecheck_ifthenelse(to_code_ifthenelse(code));
  else if(statement==ID_goto)
  {
    // TODO: produce used label set
  }
  else if(statement==ID_assign)
    typecheck_assign(to_code_assign(code));
  else if(statement==ID_try_catch)
    typecheck_try_catch(to_code_try_catch(code));
  else if(statement==ID_skip)
  {
  }
  else
  {
    err_location(code);
    error() << "unexpected statement: " << statement << eom;
    throw 0;
  }
}
Example #23
0
void value_set_domain_fivrnst::transform(
  locationt from_l,
    locationt to_l,
    ai_baset &ai,
    const namespacet &ns)
{   
  value_set.set_from(from_l->function, from_l->location_number);
  value_set.set_to(to_l->function, to_l->location_number);
  
  #if 0 
  std::cout << "Transforming: " << 
    from_l->function << " " << from_l->location_number << " to " << 
    to_l->function << " " << to_l->location_number << std::endl;
  #endif
  
  switch(from_l->type)
  {
  case END_FUNCTION:    
    value_set.do_end_function(value_set_domaint::get_return_lhs(to_l), ns);
    break;
  
  case RETURN:
  case OTHER:
  case ASSIGN:
    value_set.apply_code(from_l->code, ns);
    break;

  case FUNCTION_CALL:
    {
      const code_function_callt &code=
        to_code_function_call(from_l->code);

      value_set.do_function_call(to_l->function, code.arguments(), ns);
      break;        
    }
    
  default:;    
  }
  
//  return value_set.handover(); //TODO: not sure what to do with this
}
Example #24
0
void k_inductiont::get_modifies(
  const loopt &loop,
  modifiest &modifies)
{
  for(loopt::const_iterator
      i_it=loop.begin(); i_it!=loop.end(); i_it++)
  {
    const goto_programt::instructiont &instruction=**i_it;

    if(instruction.is_assign())
    {
      const exprt &lhs=to_code_assign(instruction.code).lhs();
      get_modifies_lhs(*i_it, lhs, modifies);
    }
    else if(instruction.is_function_call())
    {
      const exprt &lhs=to_code_function_call(instruction.code).lhs();
      get_modifies_lhs(*i_it, lhs, modifies);
    }
  }
}
void remove_function_pointerst::remove_function_pointer(
  goto_programt &goto_program,
  goto_programt::targett target)
{
  const code_function_callt &code=
    to_code_function_call(target->code);

  const exprt &function=code.function();

  // this better have the right type
  code_typet call_type=to_code_type(function.type());

  // refine the type in case the forward declaration was incomplete
  if(call_type.has_ellipsis() &&
     call_type.parameters().empty())
  {
    call_type.remove_ellipsis();
    forall_expr(it, code.arguments())
      call_type.parameters().push_back(
        code_typet::parametert(it->type()));
  }

  assert(function.id()==ID_dereference);
  assert(function.operands().size()==1);

  bool found_functions;

  const exprt &pointer=function.op0();
  remove_const_function_pointerst::functionst functions;
  does_remove_constt const_removal_check(goto_program, ns);
  if(const_removal_check())
  {
    warning() << "Cast from const to non-const pointer found, only worst case"
              << " function pointer removal will be done." << eom;
    found_functions=false;
  }
  else
  {
    remove_const_function_pointerst fpr(
    get_message_handler(), pointer, ns, symbol_table);

    found_functions=fpr(functions);

    // Either found_functions is true therefore the functions should not
    // be empty
    // Or found_functions is false therefore the functions should be empty
    assert(found_functions != functions.empty());

    if(functions.size()==1)
    {
      to_code_function_call(target->code).function()=*functions.cbegin();
      return;
    }
  }

  if(!found_functions)
  {
    if(only_resolve_const_fps)
    {
      // If this mode is enabled, we only remove function pointers
      // that we can resolve either to an exact funciton, or an exact subset
      // (e.g. a variable index in a constant array).
      // Since we haven't found functions, we would now resort to
      // replacing the function pointer with any function with a valid signature
      // Since we don't want to do that, we abort.
      return;
    }

    bool return_value_used=code.lhs().is_not_nil();

    // get all type-compatible functions
    // whose address is ever taken
    for(const auto &t : type_map)
    {
      // address taken?
      if(address_taken.find(t.first)==address_taken.end())
        continue;

      // type-compatible?
      if(!is_type_compatible(return_value_used, call_type, t.second))
        continue;

      if(t.first=="pthread_mutex_cleanup")
        continue;

      symbol_exprt expr;
      expr.type()=t.second;
      expr.set_identifier(t.first);
        functions.insert(expr);
    }
  }

  // the final target is a skip
  goto_programt final_skip;

  goto_programt::targett t_final=final_skip.add_instruction();
  t_final->make_skip();

  // build the calls and gotos

  goto_programt new_code_calls;
  goto_programt new_code_gotos;

  for(const auto &fun : functions)
  {
    // call function
    goto_programt::targett t1=new_code_calls.add_instruction();
    t1->make_function_call(code);
    to_code_function_call(t1->code).function()=fun;

    // the signature of the function might not match precisely
    fix_argument_types(to_code_function_call(t1->code));

    fix_return_type(to_code_function_call(t1->code), new_code_calls);
    // goto final
    goto_programt::targett t3=new_code_calls.add_instruction();
    t3->make_goto(t_final, true_exprt());

    // goto to call
    address_of_exprt address_of;
    address_of.object()=fun;
    address_of.type()=pointer_typet();
    address_of.type().subtype()=fun.type();

    if(address_of.type()!=pointer.type())
      address_of.make_typecast(pointer.type());

    goto_programt::targett t4=new_code_gotos.add_instruction();
    t4->make_goto(t1, equal_exprt(pointer, address_of));
  }

  // fall-through
  if(add_safety_assertion)
  {
    goto_programt::targett t=new_code_gotos.add_instruction();
    t->make_assertion(false_exprt());
    t->source_location.set_property_class("pointer dereference");
    t->source_location.set_comment("invalid function pointer");
  }

  goto_programt new_code;

  // patch them all together
  new_code.destructive_append(new_code_gotos);
  new_code.destructive_append(new_code_calls);
  new_code.destructive_append(final_skip);

  // set locations
  Forall_goto_program_instructions(it, new_code)
  {
    irep_idt property_class=it->source_location.get_property_class();
    irep_idt comment=it->source_location.get_comment();
    it->source_location=target->source_location;
    it->function=target->function;
    if(!property_class.empty())
      it->source_location.set_property_class(property_class);
    if(!comment.empty())
      it->source_location.set_comment(comment);
  }
Example #26
0
void termination_baset::find_required_steps(
  const goto_tracet &goto_trace,
  goto_tracet::stepst::const_iterator &loop_begin,
  required_stepst &required_steps,
  const std::string &prefix) const
{
  find_symbols_sett required_symbols;
  unsigned before=0, after=1;

  // initialize: find all (potential) loop exits and
  // remember the symbols in them
  for(goto_tracet::stepst::const_iterator it1=loop_begin;
      it1!=goto_trace.steps.end();
      it1++)
  {
    if(it1->pc->is_goto() &&
       it1->pc->function==loop_begin->pc->function)
    {
      bool found_next=false, found_target=false;
      goto_programt::const_targett next=it1->pc; next++;
      goto_programt::const_targett target=it1->pc->targets.front();

      for(goto_tracet::stepst::const_iterator it2=loop_begin;
          it2!=goto_trace.steps.end();
          it2++)
      {
        if(it1!=it2)
        {
          if(it2->pc==next)
            found_next=true;
          else if(it2->pc==target)
            found_target=true;
        }
      }

      if(!found_target || !found_next)
      {
        exprt temp=it1->cond_expr;
        remove_ssa_ids(temp);
        find_symbols(temp, required_symbols);
      }
    }
  }

  #if 0
  std::cout << "INITIAL SYMBOLS: ";
  for(find_symbols_sett::const_iterator it=required_symbols.begin();
      it!=required_symbols.end();
      it++)
    std::cout << *it << ", ";
  std::cout << std::endl;
  #endif

  // get the fixpoint
  while(before!=after)
  {
    before=required_symbols.size();

    for(goto_tracet::stepst::const_iterator step=loop_begin;
        step!=goto_trace.steps.end();
        step++)
    {
      find_symbols_sett intersection;

      if(step->is_assignment())
      {
        exprt lhs, rhs;

        const codet &code=to_code(step->pc->code);

        if(code.get_statement()==ID_assign)
        {
          const code_assignt &acode=to_code_assign(step->pc->code);
          lhs=acode.lhs();
          rhs=acode.rhs();
        }
        else if(code.get_statement()==ID_function_call)
        {
          const code_function_callt fcode=to_code_function_call(step->pc->code);
          lhs=fcode.lhs();
          rhs=fcode.op2();
        }
        else
          throw "Unexpected assign statement";

        if(lhs.id()==ID_symbol &&
           has_prefix(lhs.get_string(ID_identifier), prefix))
        {
          // if we depend on the RHS syms, we also need the pre-symbol
          find_symbols_sett rhs_sym;
          find_symbols(rhs, rhs_sym);

          if(intersects(rhs_sym, required_symbols))
          {
            find_symbols(lhs, required_symbols);
            required_steps.insert(&(*step));
          }
        }
        else
        {
          find_symbols_sett lhs_sym;

          if(lhs.id()==ID_index)
            find_symbols(lhs.op0(), lhs_sym); // we're not modifying the index
          else
            find_symbols(lhs, lhs_sym);

           if(intersects(lhs_sym, required_symbols))
           {
             find_symbols(rhs, required_symbols);
             required_steps.insert(&(*step));
           }
        }
      }
      else if(step->is_assume())
      {
        find_symbols_sett syms;
        find_symbols(step->pc->guard, syms);

        if(intersects(syms, required_symbols))
        {
          required_symbols.insert(syms.begin(), syms.end());
          required_steps.insert(&(*step));
        }
      }
    }

    after=required_symbols.size();

  #if 0
  std::cout << "REQUIRED SYMBOLS: ";
  for(find_symbols_sett::const_iterator it=required_symbols.begin();
      it!=required_symbols.end();
      it++)
    std::cout << *it << ", ";
  std::cout << std::endl;
  #endif
  }
}
void remove_virtual_functionst::remove_virtual_function(
  goto_programt &goto_program,
  goto_programt::targett target)
{
  const code_function_callt &code=
    to_code_function_call(target->code);

  const auto &vcall_source_loc=target->source_location;

  const exprt &function=code.function();
  assert(function.id()==ID_virtual_function);
  assert(!code.arguments().empty());

  functionst functions;
  get_functions(function, functions);

  if(functions.empty())
  {
    target->make_skip();
    return; // give up
  }

  // only one option?
  if(functions.size()==1)
  {
    assert(target->is_function_call());
    if(functions.begin()->symbol_expr==symbol_exprt())
      target->make_skip();
    else
      to_code_function_call(target->code).function()=
        functions.begin()->symbol_expr;
    return;
  }

  // the final target is a skip
  goto_programt final_skip;

  goto_programt::targett t_final=final_skip.add_instruction();
  t_final->source_location=vcall_source_loc;

  t_final->make_skip();

  // build the calls and gotos

  goto_programt new_code_calls;
  goto_programt new_code_gotos;

  exprt this_expr=code.arguments()[0];
  // If necessary, cast to the last candidate function to
  // get the object's clsid. By the structure of get_functions,
  // this is the parent of all other classes under consideration.
  const auto &base_classid=functions.back().class_id;
  const auto &base_function_symbol=functions.back().symbol_expr;
  symbol_typet suggested_type(base_classid);
  exprt c_id2=get_class_identifier_field(this_expr, suggested_type, ns);

  std::map<irep_idt, goto_programt::targett> calls;
  // Note backwards iteration, to get the least-derived candidate first.
  for(auto it=functions.crbegin(), itend=functions.crend(); it!=itend; ++it)
  {
    const auto &fun=*it;
    auto insertit=calls.insert(
      {fun.symbol_expr.get_identifier(), goto_programt::targett()});

    // Only create one call sequence per possible target:
    if(insertit.second)
    {
      goto_programt::targett t1=new_code_calls.add_instruction();
      t1->source_location=vcall_source_loc;
      if(!fun.symbol_expr.get_identifier().empty())
      {
      // call function
        t1->make_function_call(code);
        auto &newcall=to_code_function_call(t1->code);
        newcall.function()=fun.symbol_expr;
        pointer_typet need_type(symbol_typet(fun.symbol_expr.get(ID_C_class)));
        if(!type_eq(newcall.arguments()[0].type(), need_type, ns))
          newcall.arguments()[0].make_typecast(need_type);
      }
      else
      {
        // No definition for this type; shouldn't be possible...
        t1->make_assertion(false_exprt());
      }
      insertit.first->second=t1;
      // goto final
      goto_programt::targett t3=new_code_calls.add_instruction();
      t3->source_location=vcall_source_loc;
      t3->make_goto(t_final, true_exprt());
    }

    // If this calls the base function we just fall through.
    // Otherwise branch to the right call:
    if(fun.symbol_expr!=base_function_symbol)
    {
      exprt c_id1=constant_exprt(fun.class_id, string_typet());
      goto_programt::targett t4=new_code_gotos.add_instruction();
      t4->source_location=vcall_source_loc;
      t4->make_goto(insertit.first->second, equal_exprt(c_id1, c_id2));
    }
  }

  goto_programt new_code;

  // patch them all together
  new_code.destructive_append(new_code_gotos);
  new_code.destructive_append(new_code_calls);
  new_code.destructive_append(final_skip);

  // set locations
  Forall_goto_program_instructions(it, new_code)
  {
    const irep_idt property_class=it->source_location.get_property_class();
    const irep_idt comment=it->source_location.get_comment();
    it->source_location=target->source_location;
    it->function=target->function;
    if(!property_class.empty())
      it->source_location.set_property_class(property_class);
    if(!comment.empty())
      it->source_location.set_comment(comment);
  }

  goto_programt::targett next_target=target;
  next_target++;

  goto_program.destructive_insert(next_target, new_code);

  // finally, kill original invocation
  target->make_skip();
}
Example #28
0
void remove_virtual_functionst::remove_virtual_function(
  goto_programt &goto_program,
  goto_programt::targett target)
{
  const code_function_callt &code=
    to_code_function_call(target->code);

  const exprt &function=code.function();
  assert(function.id()==ID_virtual_function);
  assert(!code.arguments().empty());
  
  functionst functions;
  get_functions(function, functions);
  
  if(functions.empty())
  {
    target->make_skip();
    return; // give up
  }

  // the final target is a skip
  goto_programt final_skip;

  goto_programt::targett t_final=final_skip.add_instruction();
  t_final->make_skip();
  
  // build the calls and gotos

  goto_programt new_code_calls;
  goto_programt new_code_gotos;

  for(functionst::const_iterator
      it=functions.begin();
      it!=functions.end();
      it++)
  {
    // call function
    goto_programt::targett t1=new_code_calls.add_instruction();
    t1->make_function_call(code);
    to_code_function_call(t1->code).function()=it->symbol_expr;
    
    // goto final
    goto_programt::targett t3=new_code_calls.add_instruction();
    t3->make_goto(t_final, true_exprt());

    exprt this_expr=code.arguments()[0];    
    if(this_expr.type().id()!=ID_pointer ||
       this_expr.type().id()!=ID_struct)
    {
      symbol_typet symbol_type(it->class_id);
      this_expr=typecast_exprt(this_expr, pointer_typet(symbol_type));
    }
    
    exprt deref=dereference_exprt(this_expr, this_expr.type().subtype());
    exprt c_id1=constant_exprt(it->class_id, string_typet());
    exprt c_id2=build_class_identifier(deref);
    
    goto_programt::targett t4=new_code_gotos.add_instruction();
    t4->make_goto(t1, equal_exprt(c_id1, c_id2));
  }

  goto_programt new_code;
  
  // patch them all together
  new_code.destructive_append(new_code_gotos);
  new_code.destructive_append(new_code_calls);
  new_code.destructive_append(final_skip);
  
  // set locations
  Forall_goto_program_instructions(it, new_code)
  {
    irep_idt property_class=it->source_location.get_property_class();
    irep_idt comment=it->source_location.get_comment();
    it->source_location=target->source_location;
    it->function=target->function;
    if(!property_class.empty()) it->source_location.set_property_class(property_class);
    if(!comment.empty()) it->source_location.set_comment(comment);
  }
void remove_function_pointerst::remove_function_pointer(
  goto_programt &goto_program,
  goto_programt::targett target)
{
  const code_function_callt &code=
    to_code_function_call(target->code);

  const exprt &function=code.function();

  // this better have the right type
  code_typet call_type=to_code_type(function.type());

  // refine the type in case the forward declaration was incomplete
  if(call_type.has_ellipsis() &&
     call_type.parameters().empty())
  {
    call_type.remove_ellipsis();
    forall_expr(it, code.arguments())
      call_type.parameters().push_back(
        code_typet::parametert(it->type()));
  }

  assert(function.id()==ID_dereference);
  assert(function.operands().size()==1);

  const exprt &pointer=function.op0();

  // Is this simple?
  if(pointer.id()==ID_address_of &&
     to_address_of_expr(pointer).object().id()==ID_symbol)
  {
    to_code_function_call(target->code).function()=
      to_address_of_expr(pointer).object();
    return;
  }

  typedef std::list<exprt> functionst;
  functionst functions;

  bool return_value_used=code.lhs().is_not_nil();

  // get all type-compatible functions
  // whose address is ever taken
  for(type_mapt::const_iterator f_it=
      type_map.begin();
      f_it!=type_map.end();
      f_it++)
  {
    // address taken?
    if(address_taken.find(f_it->first)==address_taken.end())
      continue;

    // type-compatible?
    if(!is_type_compatible(return_value_used, call_type, f_it->second))
      continue;

    if(f_it->first=="pthread_mutex_cleanup")
      continue;

    symbol_exprt expr;
    expr.type()=f_it->second;
    expr.set_identifier(f_it->first);
    functions.push_back(expr);
  }

  // the final target is a skip
  goto_programt final_skip;

  goto_programt::targett t_final=final_skip.add_instruction();
  t_final->make_skip();

  // build the calls and gotos

  goto_programt new_code_calls;
  goto_programt new_code_gotos;

  for(functionst::const_iterator
      it=functions.begin();
      it!=functions.end();
      it++)
  {
    // call function
    goto_programt::targett t1=new_code_calls.add_instruction();
    t1->make_function_call(code);
    to_code_function_call(t1->code).function()=*it;

    // the signature of the function might not match precisely
    fix_argument_types(to_code_function_call(t1->code));

    fix_return_type(to_code_function_call(t1->code), new_code_calls);
    // goto final
    goto_programt::targett t3=new_code_calls.add_instruction();
    t3->make_goto(t_final, true_exprt());

    // goto to call
    address_of_exprt address_of;
    address_of.object()=*it;
    address_of.type()=pointer_typet();
    address_of.type().subtype()=it->type();

    if(address_of.type()!=pointer.type())
      address_of.make_typecast(pointer.type());

    goto_programt::targett t4=new_code_gotos.add_instruction();
    t4->make_goto(t1, equal_exprt(pointer, address_of));
  }

  // fall-through
  if(add_safety_assertion)
  {
    goto_programt::targett t=new_code_gotos.add_instruction();
    t->make_assertion(false_exprt());
    t->source_location.set_property_class("pointer dereference");
    t->source_location.set_comment("invalid function pointer");
  }

  goto_programt new_code;

  // patch them all together
  new_code.destructive_append(new_code_gotos);
  new_code.destructive_append(new_code_calls);
  new_code.destructive_append(final_skip);

  // set locations
  Forall_goto_program_instructions(it, new_code)
  {
    irep_idt property_class=it->source_location.get_property_class();
    irep_idt comment=it->source_location.get_comment();
    it->source_location=target->source_location;
    it->function=target->function;
    if(!property_class.empty()) it->source_location.set_property_class(property_class);
    if(!comment.empty()) it->source_location.set_comment(comment);
  }
Example #30
0
void remove_function_pointerst::remove_function_pointer(
  goto_programt &goto_program,
  goto_programt::targett target)
{
  const code_function_callt &code=
    to_code_function_call(target->code);

  const exprt &function=code.function();
  
  // this better have the right type
  const code_typet &call_type=to_code_type(function.type());
  
  assert(function.id()==ID_dereference);
  assert(function.operands().size()==1);

  const exprt &pointer=function.op0();
  
  typedef std::list<exprt> functionst;
  functionst functions;
  
  // get all type-compatible functions
  // whose address is ever taken
  for(type_mapt::const_iterator f_it=
      type_map.begin();
      f_it!=type_map.end();
      f_it++)
  {
    // address taken?
    if(address_taken.find(f_it->first)==address_taken.end())
      continue;

    // type-compatible?
    if(!is_type_compatible(call_type, f_it->second))
      continue;
    
    symbol_exprt expr;
    expr.type()=f_it->second;
    expr.set_identifier(f_it->first);
    functions.push_back(expr);
  }
  
  // the final target is a skip
  goto_programt final_skip;

  goto_programt::targett t_final=final_skip.add_instruction();
  t_final->make_skip();
  
  // build the calls and gotos

  goto_programt new_code_calls;
  goto_programt new_code_gotos;

  for(functionst::const_iterator
      it=functions.begin();
      it!=functions.end();
      it++)
  {
    // call function
    goto_programt::targett t1=new_code_calls.add_instruction();
    t1->make_function_call(code);
    to_code_function_call(t1->code).function()=*it;
    
    // the signature of the function might not match precisely
    fix_argument_types(to_code_function_call(t1->code));
    
    fix_return_type(to_code_function_call(t1->code), new_code_calls);
    // goto final
    goto_programt::targett t3=new_code_calls.add_instruction();
    t3->make_goto(t_final, true_exprt());
  
    // goto to call
    address_of_exprt address_of;
    address_of.object()=*it;
    address_of.type()=pointer_typet();
    address_of.type().subtype()=it->type();
    
    if(address_of.type()!=pointer.type())
      address_of.make_typecast(pointer.type());
    
    goto_programt::targett t4=new_code_gotos.add_instruction();
    t4->make_goto(t1, equal_exprt(pointer, address_of));
  }

  // fall-through
  if(add_safety_assertion)
  {
    goto_programt::targett t=new_code_gotos.add_instruction();
    t->make_assertion(false_exprt());
    t->location.set(ID_property, "pointer dereference");
    t->location.set(ID_comment, "invalid function pointer");
  }
  
  goto_programt new_code;
  
  // patch them all together
  new_code.destructive_append(new_code_gotos);
  new_code.destructive_append(new_code_calls);
  new_code.destructive_append(final_skip);
  
  // set locations
  Forall_goto_program_instructions(it, new_code)
  {
    irep_idt property=it->location.get_property();
    irep_idt comment=it->location.get_comment();
    it->location=target->location;
    it->function=target->function;
    if(!property.empty()) it->location.set_property(property);
    if(!comment.empty()) it->location.set_comment(comment);
  }