Пример #1
0
void goto_convertt::do_function_call(
  const exprt &lhs,
  const exprt &function,
  const exprt::operandst &arguments,
  goto_programt &dest)
{
  // make it all side effect free

  exprt new_lhs=lhs,
        new_function=function;

  exprt::operandst new_arguments=arguments;

  if(!new_lhs.is_nil())
    clean_expr(new_lhs, dest);

  clean_expr(new_function, dest);

  // the arguments of __noop do not get evaluated
  if(new_function.id()==ID_symbol &&
     to_symbol_expr(new_function).get_identifier()=="__noop")
  {
    new_arguments.clear();
  }

  Forall_expr(it, new_arguments)
    clean_expr(*it, dest);

  // split on the function

  if(new_function.id()==ID_if)
  {
    do_function_call_if(new_lhs, to_if_expr(new_function), new_arguments, dest);
  }
  else if(new_function.id()==ID_symbol)
  {
    do_function_call_symbol(new_lhs, to_symbol_expr(new_function), new_arguments, dest);
  }
  else if(new_function.id()=="NULL-object")
  {
  }
  else if(new_function.id()==ID_dereference ||
          new_function.id()=="virtual_function")
  {
    do_function_call_other(new_lhs, new_function, new_arguments, dest);
  }
  else
  {
    error().source_location=function.find_source_location();
    error() << "unexpected function argument: " << new_function.id()
            << eom;
    throw 0;
  }
}
Пример #2
0
      Forall_operands(it, expr)
      {
        clean_expr(*it, dest, false);

        // remember as expression statement for later checks
        if(it->is_not_nil())
          convert(code_expressiont(*it), dest);
      }
Пример #3
0
void goto_convertt::do_cpp_new(
  const exprt &lhs,
  const side_effect_exprt &rhs,
  goto_programt &dest)
{
  if(lhs.is_nil())
    throw "do_cpp_new without lhs is yet to be implemented";
  
  // build size expression
  exprt object_size=
    static_cast<const exprt &>(rhs.find(ID_sizeof));

  bool new_array=rhs.get(ID_statement)==ID_cpp_new_array;
  
  exprt count;

  if(new_array)
  {
    count=static_cast<const exprt &>(rhs.find(ID_size));

    if(count.type()!=object_size.type())
      count.make_typecast(object_size.type());

    // might have side-effect
    clean_expr(count, dest);
  }

  exprt tmp_symbol_expr;

  // is this a placement new?
  if(rhs.operands().empty()) // no, "regular" one
  {
    // call __new or __new_array
    exprt new_symbol=
      ns.lookup(new_array?"__new_array":"__new").symbol_expr();
    
    const code_typet &code_type=
      to_code_type(new_symbol.type());

    const typet &return_type=
      code_type.return_type();

    assert(code_type.parameters().size()==1 ||
           code_type.parameters().size()==2);

    const symbolt &tmp_symbol=
      new_tmp_symbol(return_type, "new", dest, rhs.source_location());
    
    tmp_symbol_expr=tmp_symbol.symbol_expr();
    
    code_function_callt new_call;
    new_call.function()=new_symbol;
    if(new_array) new_call.arguments().push_back(count);
    new_call.arguments().push_back(object_size);
    new_call.set("#type", lhs.type().subtype());
    new_call.lhs()=tmp_symbol_expr;
    new_call.add_source_location()=rhs.source_location();
    
    convert(new_call, dest);
  }
  else if(rhs.operands().size()==1)
  {
    // call __placement_new
    exprt new_symbol=
      ns.lookup(new_array?"__placement_new_array":"__placement_new").symbol_expr();
    
    const code_typet &code_type=
      to_code_type(new_symbol.type());

    const typet &return_type=code_type.return_type();
    
    assert(code_type.parameters().size()==2 ||
           code_type.parameters().size()==3);

    const symbolt &tmp_symbol=
      new_tmp_symbol(return_type, "new", dest, rhs.source_location());

    tmp_symbol_expr=tmp_symbol.symbol_expr();

    code_function_callt new_call;
    new_call.function()=new_symbol;
    if(new_array) new_call.arguments().push_back(count);
    new_call.arguments().push_back(object_size);
    new_call.arguments().push_back(rhs.op0()); // memory location
    new_call.set("#type", lhs.type().subtype());
    new_call.lhs()=tmp_symbol_expr;
    new_call.add_source_location()=rhs.source_location();

    for(unsigned i=0; i<code_type.parameters().size(); i++)
      if(new_call.arguments()[i].type()!=code_type.parameters()[i].type())
        new_call.arguments()[i].make_typecast(code_type.parameters()[i].type());
    
    convert(new_call, dest);
  }
  else
    throw "cpp_new expected to have 0 or 1 operands";

  goto_programt::targett t_n=dest.add_instruction(ASSIGN);
  t_n->code=code_assignt(
    lhs, typecast_exprt(tmp_symbol_expr, lhs.type()));
  t_n->source_location=rhs.find_source_location();
    
  // grab initializer
  goto_programt tmp_initializer;
  cpp_new_initializer(lhs, rhs, tmp_initializer);

  dest.destructive_append(tmp_initializer);
}
Пример #4
0
void goto_symext::symex_other(
  const goto_functionst &goto_functions,
  statet &state)
{
  const goto_programt::instructiont &instruction=*state.source.pc;

  const codet &code=to_code(instruction.code);

  const irep_idt &statement=code.get_statement();
  
  if(statement==ID_expression)
  {
    // ignore
  }
  else if(statement==ID_cpp_delete ||
          statement=="cpp_delete[]")
  {
    codet clean_code=code;
    clean_expr(clean_code, state, false);
    symex_cpp_delete(state, clean_code);
  }
  else if(statement==ID_free)
  {
    // ignore
  }
  else if(statement==ID_printf)
  {
    codet clean_code=code;
    clean_expr(clean_code, state, false);
    symex_printf(state, nil_exprt(), clean_code);
  }
  else if(statement==ID_input)
  {
    codet clean_code(code);
    clean_expr(clean_code, state, false);
    symex_input(state, clean_code);
  }
  else if(statement==ID_output)
  {
    codet clean_code(code);
    clean_expr(clean_code, state, false);
    symex_output(state, clean_code);
  }
  else if(statement==ID_decl)
  {
    assert(false); // see symex_decl.cpp
  }
  else if(statement==ID_nondet)
  {
    // like skip
  }
  else if(statement==ID_asm)
  {
    // we ignore this for now
  }
  else if(statement==ID_array_copy)
  {
    assert(code.operands().size()==2);

    codet clean_code(code);
    
    // we need to add dereferencing for both operands
    dereference_exprt d0, d1;
    d0.op0()=code.op0();
    d0.type()=code.op0().type().subtype();
    d1.op0()=code.op1();
    d1.type()=code.op1().type().subtype();
    
    clean_code.op0()=d0;
    clean_code.op1()=d1;
    
    clean_expr(clean_code, state, false);
    
    process_array_expr(clean_code.op0());
    process_array_expr(clean_code.op1());
    
    if(ns.follow(clean_code.op0().type()).id()!=ID_array)
      throw "array_copy expects array operand";
    
    if(!base_type_eq(clean_code.op0().type(),
                     clean_code.op1().type(), ns))
      throw "array_copy expects matching array types";
    
    code_assignt assignment;
    assignment.lhs()=clean_code.op0();
    assignment.rhs()=clean_code.op1();
    basic_symext::symex_assign(state, assignment);    
  }
  else if(statement==ID_array_set)
  {
    assert(code.operands().size()==2);
    
    codet clean_code(code);

    // we need to add dereferencing for the first operand
    dereference_exprt d0;
    d0.op0()=code.op0();
    d0.type()=code.op0().type().subtype();
    
    clean_code.op0()=d0;

    clean_expr(clean_code, state, false);
    
    process_array_expr(clean_code.op0());
    
    const typet &array_type=ns.follow(clean_code.op0().type());
    
    if(array_type.id()!=ID_array)
      throw "array_set expects array operand";

    if(!base_type_eq(array_type.subtype(),
                     clean_code.op1().type(), ns))
      clean_code.op1().make_typecast(array_type.subtype());
    
    code_assignt assignment;
    assignment.lhs()=clean_code.op0();
    assignment.rhs()=array_of_exprt(clean_code.op1(), clean_code.op0().type());
    basic_symext::symex_assign(state, assignment);    
  }
  else if(statement==ID_user_specified_predicate || statement==ID_user_specified_parameter_predicates || statement == ID_user_specified_return_predicates)
  {
	  // like skip
  }
  else
    throw "unexpected statement: "+id2string(statement);
}
Пример #5
0
void goto_convertt::clean_expr(
  exprt &expr,
  goto_programt &dest,
  bool result_is_used)
{
  // this cleans:
  //   && || ?: comma (control-dependency)
  //   function calls
  //   object constructors like arrays, string constants, structs
  //   ++ --
  //   compound assignments
  //   compound literals

  if(!needs_cleaning(expr)) return;

  if(expr.id()==ID_and || expr.id()==ID_or)
  {
    // rewrite into ?:
    rewrite_boolean(expr);
    
    // recursive call
    clean_expr(expr, dest, result_is_used);
    return;
  }
  else if(expr.id()==ID_if)
  {
    // first clean condition
    clean_expr(to_if_expr(expr).cond(), dest, true);

    // possibly done now
    if(!needs_cleaning(to_if_expr(expr).true_case()) &&
       !needs_cleaning(to_if_expr(expr).false_case()))
      return;

    // copy expression
    if_exprt if_expr=to_if_expr(expr);
    
    if(!if_expr.cond().is_boolean())
      throw "first argument of `if' must be boolean, but got "
        +if_expr.cond().to_string();

    const locationt location=expr.find_location();
  
    // We do some constant-folding here, to mimic
    // what typical compilers do.
    {
      exprt tmp_cond=if_expr.cond();
      simplify(tmp_cond, ns);
      if(tmp_cond.is_true())
      {
        clean_expr(if_expr.true_case(), dest, result_is_used);
        expr=if_expr.true_case();
        return;
      }
      else if(tmp_cond.is_false())
      {
        clean_expr(if_expr.false_case(), dest, result_is_used);
        expr=if_expr.false_case();
        return;
      }
    }

    goto_programt tmp_true;
    clean_expr(if_expr.true_case(), tmp_true, result_is_used);

    goto_programt tmp_false;
    clean_expr(if_expr.false_case(), tmp_false, result_is_used);
    
    if(result_is_used)
    {
      symbolt &new_symbol=
        new_tmp_symbol(expr.type(), "if_expr", dest, location);

      code_assignt assignment_true;
      assignment_true.lhs()=new_symbol.symbol_expr();
      assignment_true.rhs()=if_expr.true_case();
      assignment_true.location()=location;
      convert(assignment_true, tmp_true);

      code_assignt assignment_false;
      assignment_false.lhs()=new_symbol.symbol_expr();
      assignment_false.rhs()=if_expr.false_case();
      assignment_false.location()=location;
      convert(assignment_false, tmp_false);

      // overwrites expr
      expr=new_symbol.symbol_expr();
    }
    else
    {
      // preserve the expressions for possible later checks
      if(if_expr.true_case().is_not_nil())
      {
        code_expressiont code_expression(if_expr.true_case());
        convert(code_expression, tmp_true);
      }
      
      if(if_expr.false_case().is_not_nil())
      {
        code_expressiont code_expression(if_expr.false_case());
        convert(code_expression, tmp_false);
      }
      
      expr=nil_exprt();
    }

    // generate guard for argument side-effects    
    generate_ifthenelse(
      if_expr.cond(), tmp_true, tmp_false,
      location, dest);

    return;
  }
  else if(expr.id()==ID_comma)
  {
    if(result_is_used)
    {
      exprt result;
    
      Forall_operands(it, expr)
      {
        bool last=(it==--expr.operands().end());
        
        // special treatment for last one
        if(last)
        {
          result.swap(*it);
          clean_expr(result, dest, true);
        }
        else
        {
          clean_expr(*it, dest, false);

          // remember these for later checks
          if(it->is_not_nil())
            convert(code_expressiont(*it), dest);
        }
      }

      expr.swap(result);
    }
    else // result not used
    {
void goto_convertt::clean_expr(
  exprt &expr,
  goto_programt &dest,
  bool result_is_used)
{
  // this cleans:
  //   && || ?: comma (control-dependency)
  //   function calls
  //   object constructors like arrays, string constants, structs
  //   ++ --
  //   compound assignments

  if(!needs_cleaning(expr)) return;

  if(expr.id()==ID_and || expr.id()==ID_or)
  {
    // rewrite into ?:
    rewrite_boolean(expr);
    
    // recursive call
    clean_expr(expr, dest, result_is_used);
    return;
  }
  else if(expr.id()==ID_if)
  {
    if(expr.operands().size()!=3)
      throw "if takes three arguments";

    if(!expr.op0().is_boolean())
      throw "first argument of `if' must be boolean, but got "
        +expr.op0().to_string();

    // first pull out condition -- we need to prevent
    // this getting destroyed by the side-effects in the other
    // operands
    make_temp_symbol(expr.op0(), "condition", dest);

    // now clean arguments    
    goto_programt tmp_true, tmp_false;
    clean_expr(expr.op1(), tmp_true, result_is_used);
    clean_expr(expr.op2(), tmp_false, result_is_used);

    // generate guard for argument side-effects    
    generate_ifthenelse(
      expr.op0(), tmp_true, tmp_false,
      expr.location(), dest);

    return;
  }
  else if(expr.id()==ID_comma)
  {
    exprt result;
  
    Forall_operands(it, expr)
    {
      bool last=(it==--expr.operands().end());
      
      if(last)
      {
        result.swap(*it);
        clean_expr(result, dest, result_is_used);
      }
      else
        clean_expr(*it, dest, false);
    }
Пример #7
0
void goto_symext::symex_step(
  const goto_functionst &goto_functions,
  statet &state)
{
  #if 0
  std::cout << "\ninstruction type is " << state.source.pc->type << '\n';
  std::cout << "Location: " << state.source.pc->source_location << '\n';
  std::cout << "Guard: " << from_expr(ns, "", state.guard.as_expr()) << '\n';
  std::cout << "Code: " << from_expr(ns, "", state.source.pc->code) << '\n';
  #endif

  assert(!state.threads.empty());
  assert(!state.call_stack().empty());

  const goto_programt::instructiont &instruction=*state.source.pc;

  merge_gotos(state);

  // depth exceeded?
  {
    unsigned max_depth=options.get_unsigned_int_option("depth");
    if(max_depth!=0 && state.depth>max_depth)
      state.guard.add(false_exprt());
    state.depth++;
  }

  // actually do instruction
  switch(instruction.type)
  {
  case SKIP:
    if(!state.guard.is_false())
      target.location(state.guard.as_expr(), state.source);
    state.source.pc++;
    break;

  case END_FUNCTION:
    // do even if state.guard.is_false() to clear out frame created
    // in symex_start_thread
    symex_end_of_function(state);
    state.source.pc++;
    break;

  case LOCATION:
    if(!state.guard.is_false())
      target.location(state.guard.as_expr(), state.source);
    state.source.pc++;
    break;

  case GOTO:
    symex_goto(state);
    break;

  case ASSUME:
    if(!state.guard.is_false())
    {
      exprt tmp=instruction.guard;
      clean_expr(tmp, state, false);
      state.rename(tmp, ns);
      symex_assume(state, tmp);
    }

    state.source.pc++;
    break;

  case ASSERT:
    if(!state.guard.is_false())
    {
      std::string msg=id2string(state.source.pc->source_location.get_comment());
      if(msg=="")
        msg="assertion";
      exprt tmp(instruction.guard);
      clean_expr(tmp, state, false);
      vcc(tmp, msg, state);
    }

    state.source.pc++;
    break;

  case RETURN:
    if(!state.guard.is_false())
      return_assignment(state);

    state.source.pc++;
    break;

  case ASSIGN:
    if(!state.guard.is_false())
      symex_assign_rec(state, to_code_assign(instruction.code));

    state.source.pc++;
    break;

  case FUNCTION_CALL:
    if(!state.guard.is_false())
    {
      code_function_callt deref_code=
        to_code_function_call(instruction.code);

      if(deref_code.lhs().is_not_nil())
        clean_expr(deref_code.lhs(), state, true);

      clean_expr(deref_code.function(), state, false);

      Forall_expr(it, deref_code.arguments())
        clean_expr(*it, state, false);

      symex_function_call(goto_functions, state, deref_code);
    }
    else
      state.source.pc++;
    break;

  case OTHER:
    if(!state.guard.is_false())
      symex_other(goto_functions, state);

    state.source.pc++;
    break;

  case DECL:
    if(!state.guard.is_false())
      symex_decl(state);

    state.source.pc++;
    break;

  case DEAD:
    symex_dead(state);
    state.source.pc++;
    break;

  case START_THREAD:
    symex_start_thread(state);
    state.source.pc++;
    break;

  case END_THREAD:
    // behaves like assume(0);
    if(!state.guard.is_false())
      state.guard.add(false_exprt());
    state.source.pc++;
    break;

  case ATOMIC_BEGIN:
    symex_atomic_begin(state);
    state.source.pc++;
    break;

  case ATOMIC_END:
    symex_atomic_end(state);
    state.source.pc++;
    break;

  case CATCH:
    symex_catch(state);
    state.source.pc++;
    break;

  case THROW:
    symex_throw(state);
    state.source.pc++;
    break;

  case NO_INSTRUCTION_TYPE:
    throw "symex got NO_INSTRUCTION";

  default:
    throw "symex got unexpected instruction";
  }
}