예제 #1
0
void goto_convertt::make_temp_symbol(
  exprt &expr,
  goto_programt &dest)
{
  const locationt location=expr.find_location();

  symbolt &new_symbol=new_tmp_symbol(expr.type());

  code_assignt assignment;
  assignment.lhs()=symbol_expr(new_symbol);
  assignment.rhs()=expr;
  assignment.location()=location;

  convert(assignment, dest);

  expr=symbol_expr(new_symbol);
}
예제 #2
0
void goto_checkt::pointer_rel_check(const exprt &expr, const guardt &guard)
{
  if (expr.operands().size() != 2)
    throw expr.id_string() + " takes one argument";

  if (expr.op0().type().id() == "pointer"
      && expr.op1().type().id() == "pointer")
  {
    // add same-object subgoal

    if (!options.get_bool_option("no-pointer-check"))
    {
      exprt same_object("same-object", bool_typet());
      same_object.copy_to_operands(expr.op0(), expr.op1());
      add_guarded_claim(same_object, "same object violation", "pointer",
          expr.find_location(), guard);
    }
  }
}
예제 #3
0
void goto_checkt::div_by_zero_check(const exprt &expr, const guardt &guard)
{
  if (options.get_bool_option("no-div-by-zero-check"))
    return;

  if (expr.operands().size() != 2)
    throw expr.id_string() + " takes two arguments";

  // add divison by zero subgoal

  exprt zero = gen_zero(expr.op1().type());

  if (zero.is_nil())
    throw "no zero of argument type of operator " + expr.id_string();

  exprt inequality("notequal", bool_typet());
  inequality.copy_to_operands(expr.op1(), zero);

  add_guarded_claim(inequality, "division by zero", "division-by-zero",
      expr.find_location(), guard);
}
예제 #4
0
void goto_checkt::nan_check(const exprt &expr, const guardt &guard)
{
  if (!options.get_bool_option("nan-check"))
    return;

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

  if (expr.id() != "+" && expr.id() != "*" && expr.id() != "/"
      && expr.id() != "-")
    return;

  // add nan subgoal

  exprt isnan("isnan", bool_typet());
  isnan.copy_to_operands(expr);

  isnan.make_not();

  add_guarded_claim(isnan, "NaN on " + expr.id_string(), "NaN",
      expr.find_location(), guard);
}
예제 #5
0
void goto_checkt::overflow_check(const exprt &expr, const guardt &guard)
{
  if (!options.get_bool_option("overflow-check"))
    return;

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

  // add overflow subgoal

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

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

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

    unsigned new_width = atoi(expr.type().width().c_str());
    unsigned old_width = atoi(old_type.width().c_str());

    if (old_type.id() == "unsignedbv")
      new_width--;
    if (new_width >= old_width)
      return;

    overflow.id(overflow.id_string() + "-" + i2string(new_width));
  }

  overflow.make_not();

  add_guarded_claim(overflow, "arithmetic overflow on " + expr.id_string(),
      "overflow", expr.find_location(), guard);
}
예제 #6
0
symbol_exprt goto_convertt::make_compound_literal(
  const exprt &expr,
  goto_programt &dest)
{
  const locationt location=expr.find_location();
  
  symbolt new_symbol;
  symbolt *symbol_ptr;
  
  do
  {
    // The lifetime of compound literals is really that of
    // the block they are in.
    new_symbol.base_name="literal$"+i2string(++temporary_counter);
    new_symbol.name=tmp_symbol_prefix+id2string(new_symbol.base_name);
    new_symbol.is_lvalue=true;
    new_symbol.is_thread_local=false;
    new_symbol.is_static_lifetime=true;
    new_symbol.is_file_local=true;
    new_symbol.value=expr;
    new_symbol.type=expr.type();
    new_symbol.location=location;
  }
  while(symbol_table.move(new_symbol, symbol_ptr));    

  // The value might depend on a variable, thus
  // generate code for this.

  symbol_exprt result=symbol_ptr->symbol_expr();
  result.location()=location;
  
  code_assignt code_assign(result, expr);
  code_assign.location()=location;
  convert(code_assign, dest);

  return result;
}
예제 #7
0
void goto_program_dereferencet::dereference_rec(
  exprt &expr,
  guardt &guard,
  const value_set_dereferencet::modet mode)
{
  if(!dereference.has_dereference(expr))
    return;

  if(expr.id()==ID_and || expr.id()==ID_or)
  {
    if(!expr.is_boolean())
      throw expr.id_string()+" must be Boolean, but got "+
            expr.pretty();

    unsigned old_guards=guard.size();

    for(unsigned i=0; i<expr.operands().size(); i++)
    {
      exprt &op=expr.operands()[i];

      if(!op.is_boolean())
        throw expr.id_string()+" takes Boolean operands only, but got "+
              op.pretty();

      if(dereference.has_dereference(op))
        dereference_rec(op, guard, value_set_dereferencet::READ);

      if(expr.id()==ID_or)
      {
        exprt tmp(op);
        tmp.make_not();
        guard.add(tmp);
      }
      else
        guard.add(op);
    }

    guard.resize(old_guards);

    return;
  }
  else if(expr.id()==ID_if)
  {
    if(expr.operands().size()!=3)
      throw "if takes three arguments";

    if(!expr.op0().is_boolean())
    {
      std::string msg=
        "first argument of if must be boolean, but got "
        +expr.op0().to_string();
      throw msg;
    }

    dereference_rec(expr.op0(), guard, value_set_dereferencet::READ);

    bool o1=dereference.has_dereference(expr.op1());
    bool o2=dereference.has_dereference(expr.op2());

    if(o1)
    {
      unsigned old_guard=guard.size();
      guard.add(expr.op0());
      dereference_rec(expr.op1(), guard, mode);
      guard.resize(old_guard);
    }

    if(o2)
    {
      unsigned old_guard=guard.size();
      exprt tmp(expr.op0());
      tmp.make_not();
      guard.add(tmp);
      dereference_rec(expr.op2(), guard, mode);
      guard.resize(old_guard);
    }

    return;
  }

  if(expr.id()==ID_address_of ||
     expr.id()=="reference_to")
  {
    // turn &*p to p
    // this has *no* side effect!
    
    assert(expr.operands().size()==1);
    
    if(expr.op0().id()==ID_dereference ||
       expr.op0().id()=="implicit_dereference")
    {
      assert(expr.op0().operands().size()==1);

      exprt tmp;
      tmp.swap(expr.op0().op0());
      
      if(tmp.type()!=expr.type())
        tmp.make_typecast(expr.type());

      expr.swap(tmp);      
    }
  }
  
  Forall_operands(it, expr)
    dereference_rec(*it, guard, mode);

  if(expr.id()==ID_dereference)
  {
    if(expr.operands().size()!=1)
      throw "dereference expects one operand";

    dereference_location=expr.find_location();
    
    exprt tmp=dereference.dereference(
      expr.op0(), guard, mode);

    expr.swap(tmp);
  }
  else if(expr.id()=="implicit_dereference")
  {
    // old stuff
    assert(false);
  }
  else if(expr.id()==ID_index)
  {
    // this is old stuff and will go away

    if(expr.operands().size()!=2)
      throw "index expects two operands";

    if(expr.op0().type().id()==ID_pointer)
    {
      dereference_location=expr.find_location();

      exprt tmp1(ID_plus, expr.op0().type());
      tmp1.operands().swap(expr.operands());
      
      exprt tmp2=dereference.dereference(tmp1, guard, mode);
      tmp2.swap(expr);
    }
  }
}
예제 #8
0
void goto_inlinet::expand_function_call(
  goto_programt &dest,
  goto_programt::targett &target,
  const exprt &lhs,
  const exprt &function,
  const exprt::operandst &arguments,
  const exprt &constrain,
  bool full)
{
  // look it up
  if(function.id()!="symbol")
  {
    err_location(function);
    throw "function_call expects symbol as function operand, "
          "but got `"+function.id_string()+"'";
  }
  
  const irep_idt &identifier=function.identifier();
  
  // see if we are already expanding it
  if(recursion_set.find(identifier)!=recursion_set.end())
  {
    if(!full)
    {
      target++;
      return; // simply ignore, we don't do full inlining, it's ok
    }

    // it's really recursive. Uh. Buh. Give up.
    err_location(function);
    warning("recursion is ignored");
    target->make_skip();
    
    target++;
    return;
  }

  goto_functionst::function_mapt::iterator m_it=
    goto_functions.function_map.find(identifier);

  if(m_it==goto_functions.function_map.end())
  {
    err_location(function);
    str << "failed to find function `" << identifier
        << "'";
    throw 0;
  }
  
  goto_functiont &f=m_it->second;

  // see if we need to inline this  
  if(!full)
  {
    if(!f.body_available ||
       (!f.is_inlined() && f.body.instructions.size() > smallfunc_limit))
    {
      target++;
      return;
    }
  }

  if(f.body_available)
  {
    inlined_funcs.insert(identifier.as_string());
    for (std::set<std::string>::const_iterator it2 = f.inlined_funcs.begin();
         it2 != f.inlined_funcs.end(); it2++) {
      inlined_funcs.insert(*it2);
    }

    recursion_sett::iterator recursion_it=
      recursion_set.insert(identifier).first;  
  
    goto_programt tmp2;
    tmp2.copy_from(f.body);
    
    assert(tmp2.instructions.back().is_end_function());
    tmp2.instructions.back().type=LOCATION;
    
    replace_return(tmp2, lhs, constrain);
    
    goto_programt tmp;
    parameter_assignments(tmp2.instructions.front().location, f.type, arguments, tmp);
    tmp.destructive_append(tmp2);
    
    // set local variables
    Forall_goto_program_instructions(it, tmp)
      it->local_variables.insert(target->local_variables.begin(),
                                 target->local_variables.end());

    if(f.type.hide())
    {
      const locationt &new_location=function.find_location();
    
      Forall_goto_program_instructions(it, tmp)
      {
        if(new_location.is_not_nil())
        {
          // can't just copy, e.g., due to comments field
          it->location.id(""); // not NIL
          it->location.set_file(new_location.get_file());
          it->location.set_line(new_location.get_line());
          it->location.set_column(new_location.get_column());
          it->location.set_function(new_location.get_function());
        }
      }
    }

    // do this recursively
    goto_inline_rec(tmp, full);

    // set up location instruction for function call  
    target->type=LOCATION;
    target->code = expr2tc();
    
    goto_programt::targett next_target(target);
    next_target++;

    dest.instructions.splice(next_target, tmp.instructions);
    target=next_target;

    recursion_set.erase(recursion_it);
  }
예제 #9
0
void goto_checkt::bounds_check(const exprt &expr, const guardt &guard)
{
  if (options.get_bool_option("no-bounds-check"))
    return;

  if (expr.id() != "index")
    return;

  if (expr.operands().size() != 2)
    throw "index takes two operands";

  // Don't bounds check the initial index of argv in the "main" function; it's
  // always correct, and just adds needless claims. In the past a "no bounds
  // check" attribute in old irep handled this.
  if (expr.op0().id_string() == "symbol"
      && expr.op0().identifier() == "c::argv'"
      && expr.op1().id_string() == "symbol"
      && expr.op1().identifier() == "c::argc'")
    return;

  if (expr.op0().id_string() == "symbol"
      && expr.op0().identifier() == "c::envp'"
      && expr.op1().id_string() == "symbol"
      && expr.op1().identifier() == "c::envp_size'")
    return;

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

  if (array_type.id() == "pointer")
    return;  // done by the pointer code
  else if (array_type.id() == "incomplete_array")
  {
    std::cerr << expr.pretty() << std::endl;
    throw "index got incomplete array";
  }
  else if (!array_type.is_array())
    throw "bounds check expected array type, got " + array_type.id_string();

  // Otherwise, if there's a dereference in the array source, this bounds check
  // should be performed by the symex-time dereferencing code, as the base thing
  // being accessed may be anything.
  if (has_dereference(expr.op0()))
    return;

  std::string name = "array bounds violated: " + array_name(expr.op0());
  const exprt &index = expr.op1();

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

      if (!to_integer(index, i) && i >= 0)
      {
        // ok
      }
      else
      {
        exprt zero = gen_zero(index.type());

        if (zero.is_nil())
          throw "no zero constant of index type " + index.type().to_string();

        exprt inequality(">=", bool_typet());
        inequality.copy_to_operands(index, zero);

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

  {
    if (array_type.size_irep().is_nil())
      throw "index array operand of wrong type";

    const exprt &size = (const exprt &) array_type.size_irep();

    if (size.id() != "infinity")
    {
      exprt inequality("<", bool_typet());
      inequality.copy_to_operands(index, size);

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

      add_guarded_claim(inequality, name + " upper bound", "array bounds",
          expr.find_location(), guard);
    }
  }
}
예제 #10
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
    {