/// does not replace object in address_of expressions
bool replace_symbol_extt::replace(exprt &dest) const
{
  bool result=true;

  // first look at type

  if(have_to_replace(dest.type()))
    if(!replace_symbolt::replace(dest.type()))
      result=false;

  // now do expression itself

  if(!have_to_replace(dest))
    return result;

  // do not replace object in address_of expressions
  if(dest.id()==ID_address_of)
  {
    const exprt &object = to_address_of_expr(dest).object();
    if(object.id()==ID_symbol)
    {
      expr_mapt::const_iterator it=
        expr_map.find(object.get(ID_identifier));

      if(it!=expr_map.end())
        return false;
    }
  }
  else if(dest.id()==ID_symbol)
  {
    expr_mapt::const_iterator it=
      expr_map.find(dest.get(ID_identifier));

    if(it!=expr_map.end())
    {
      dest=it->second;
      return false;
    }
  }

  Forall_operands(it, dest)
    if(!replace(*it))
      result=false;

  const irept &c_sizeof_type=dest.find(ID_C_c_sizeof_type);

  if(c_sizeof_type.is_not_nil() &&
     !replace_symbolt::replace(
       static_cast<typet&>(dest.add(ID_C_c_sizeof_type))))
    result=false;

  const irept &va_arg_type=dest.find(ID_C_va_arg_type);

  if(va_arg_type.is_not_nil() &&
     !replace_symbolt::replace(static_cast<typet&>(dest.add(ID_C_va_arg_type))))
    result=false;

  return result;
}
Beispiel #2
0
void goto_symext::process_array_expr_rec(
  exprt &expr,
  const typet &type) const
{
  if(expr.id()==ID_if)
  {
    if_exprt &if_expr=to_if_expr(expr);
    process_array_expr_rec(if_expr.true_case(), type);
    process_array_expr_rec(if_expr.false_case(), type);
  }
  else if(expr.id()==ID_index)
  {
    // strip index
    index_exprt &index_expr=to_index_expr(expr);
    exprt tmp=index_expr.array();
    expr.swap(tmp);
  }
  else if(expr.id()==ID_typecast)
  {
    // strip
    exprt tmp=to_typecast_expr(expr).op0();
    expr.swap(tmp);
    process_array_expr_rec(expr, type);
  }
  else if(expr.id()==ID_address_of)
  {
    // strip
    exprt tmp=to_address_of_expr(expr).op0();
    expr.swap(tmp);
    process_array_expr_rec(expr, type);
  }
  else if(expr.id()==ID_symbol &&
          expr.get_bool(ID_C_SSA_symbol) &&
          to_ssa_expr(expr).get_original_expr().id()==ID_index)
  {
    const ssa_exprt &ssa=to_ssa_expr(expr);
    const index_exprt &index_expr=to_index_expr(ssa.get_original_expr());
    exprt tmp=index_expr.array();
    expr.swap(tmp);
  }
  else
    Forall_operands(it, expr)
      process_array_expr_rec(*it, it->type());

  if(!base_type_eq(expr.type(), type, ns))
  {
    byte_extract_exprt be(byte_extract_id());
    be.type()=type;
    be.op()=expr;
    be.offset()=gen_zero(index_type());

    expr.swap(be);
  }
}
Beispiel #3
0
exprt dereferencet::dereference_rec(
  const exprt &address,
  const exprt &offset,
  const typet &type)
{
  if(address.id()==ID_address_of)
  {
    const address_of_exprt &address_of_expr=to_address_of_expr(address);

    const exprt &object=address_of_expr.object();

    return read_object(object, offset, type);
  }
  else if(address.id()==ID_typecast)
  {
    const typecast_exprt &typecast_expr=to_typecast_expr(address);

    return dereference_typecast(typecast_expr, offset, type);
  }
  else if(address.id()==ID_plus)
  {
    // pointer arithmetic
    if(address.operands().size()<2)
      throw "plus with less than two operands";

    return dereference_plus(address, offset, type);
  }
  else if(address.id()==ID_if)
  {
    const if_exprt &if_expr=to_if_expr(address);

    return dereference_if(if_expr, offset, type);
  }
  else if(address.id()==ID_constant)
  {
    const typet result_type=ns.follow(address.type()).subtype();

    // pointer-typed constant
    if(to_constant_expr(address).get_value()==ID_NULL) // NULL
    {
      // we turn this into (type *)0
      exprt zero=gen_zero(index_type());
      return dereference_rec(
        typecast_exprt(zero, address.type()), offset, type);
    }
    else
      throw "dereferencet: unexpected pointer constant "+address.pretty();
  }
  else
  {
    throw "failed to dereference `"+address.id_string()+"'";
  }
}
Beispiel #4
0
void goto_symext::process_array_expr(exprt &expr)
{
  // This may change the type of the expression!

  if(expr.id()==ID_if)
  {
    if_exprt &if_expr=to_if_expr(expr);
    process_array_expr(if_expr.true_case());

    process_array_expr_rec(if_expr.false_case(),
                           if_expr.true_case().type());

    if_expr.type()=if_expr.true_case().type();
  }
  else if(expr.id()==ID_index)
  {
    // strip index
    index_exprt &index_expr=to_index_expr(expr);
    exprt tmp=index_expr.array();
    expr.swap(tmp);
  }
  else if(expr.id()==ID_typecast)
  {
    // strip
    exprt tmp=to_typecast_expr(expr).op0();
    expr.swap(tmp);
    process_array_expr(expr);
  }
  else if(expr.id()==ID_address_of)
  {
    // strip
    exprt tmp=to_address_of_expr(expr).op0();
    expr.swap(tmp);
    process_array_expr(expr);
  }
  else if(expr.id()==ID_symbol &&
          expr.get_bool(ID_C_SSA_symbol) &&
          to_ssa_expr(expr).get_original_expr().id()==ID_index)
  {
    const ssa_exprt &ssa=to_ssa_expr(expr);
    const index_exprt &index_expr=to_index_expr(ssa.get_original_expr());
    exprt tmp=index_expr.array();
    expr.swap(tmp);
  }
  else
    Forall_operands(it, expr)
      process_array_expr(*it);
}
Beispiel #5
0
exprt dereference_rec(
  const exprt &src,
  const ssa_value_domaint &ssa_value_domain,
  const std::string &nondet_prefix,
  const namespacet &ns)
{
  if(src.id()==ID_dereference)
  {
    const exprt &pointer=dereference_rec(
      to_dereference_expr(src).pointer(),
      ssa_value_domain,
      nondet_prefix,
      ns);

    const typet &pointed_type=ns.follow(pointer.type().subtype());

    const ssa_value_domaint::valuest values=ssa_value_domain(pointer, ns);

    exprt result;
    if(values.value_set.empty())
    {
      result=pointed_object(pointer, ns);
    }
    else
    {
      auto it=values.value_set.begin();

      if(values.null || values.unknown ||
         (values.value_set.size()>1 && it->type().get_bool("#dynamic")))
      {
        std::string dyn_type_name=pointed_type.id_string();
        if(pointed_type.id()==ID_struct)
          dyn_type_name+="_"+id2string(to_struct_type(pointed_type).get_tag());
        irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown";

        result=symbol_exprt(identifier, src.type());
        result.set("#unknown_obj", true);
      }
      else
      {
        result=ssa_alias_value(src, (it++)->get_expr(), ns);
        result.set("#heap_access", result.type().get_bool("#dynamic"));
      }

      for(; it!=values.value_set.end(); ++it)
      {
        exprt guard=ssa_alias_guard(src, it->get_expr(), ns);
        exprt value=ssa_alias_value(src, it->get_expr(), ns);
        result=if_exprt(guard, value, result);
        result.set(
          "#heap_access",
          result.get_bool("#heap_access") ||
          value.type().get_bool("#dynamic"));
      }
    }

    return result;
  }
  else if(src.id()==ID_member)
  {
    member_exprt tmp=to_member_expr(src);
    tmp.struct_op()=
      dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns);
    tmp.set("#heap_access", tmp.struct_op().get_bool("#heap_access"));

    #ifdef DEBUG
    std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n';
    #endif

    if(tmp.struct_op().is_nil())
      return nil_exprt();

    return lift_if(tmp);
  }
  else if(src.id()==ID_address_of)
  {
    address_of_exprt tmp=to_address_of_expr(src);
    tmp.object()=
      dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns);
    tmp.set("#heap_access", tmp.object().get_bool("#heap_access"));

    if(tmp.object().is_nil())
      return nil_exprt();

    return lift_if(tmp);
  }
  else
  {
    exprt tmp=src;
    Forall_operands(it, tmp)
    {
      *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns);
      if(it->get_bool("#heap_access"))
        tmp.set("#heap_access", true);
    }
    return tmp;
  }
Beispiel #6
0
exprt local_SSAt::read_rhs_rec(const exprt &expr, locationt loc) const
{
  if(expr.id()==ID_side_effect)
  {
    throw "unexpected side effect in read_rhs_rec";
  }
  else if(expr.id()==ID_address_of)
  {
    address_of_exprt tmp=to_address_of_expr(expr);
    tmp.object()=read_rhs_address_of_rec(tmp.object(), loc);
    return address_canonizer(tmp, ns);
  }
  else if(expr.id()==ID_dereference)
  {
    throw "unexpected dereference in read_rhs_rec";
  }
  else if(expr.id()==ID_index)
  {
    const index_exprt &index_expr=to_index_expr(expr);
    return index_exprt(read_rhs(index_expr.array(), loc),
                       read_rhs(index_expr.index(), loc),
                       expr.type());
  }
  
  ssa_objectt object(expr, ns);
  
  // is it an object identifier?
  
  if(!object)
  {
    exprt tmp=expr; // copy
    Forall_operands(it, tmp)
      *it=read_rhs(*it, loc);
    return tmp;
  }
  
  // Argument is a struct-typed ssa object?
  // May need to split up into members.
  const typet &type=ns.follow(expr.type());

  if(type.id()==ID_struct)
  {
    // build struct constructor
    struct_exprt result(expr.type());
  
    const struct_typet &struct_type=to_struct_type(type);
    const struct_typet::componentst &components=struct_type.components();
  
    result.operands().resize(components.size());
  
    for(struct_typet::componentst::const_iterator
        it=components.begin();
        it!=components.end();
        it++)
    {
      result.operands()[it-components.begin()]=
        read_rhs(member_exprt(expr, it->get_name(), it->type()), loc);
    }
  
    return result;
  }

  // is this an object we track?
  if(ssa_objects.objects.find(object)!=
     ssa_objects.objects.end())
  {
    return read_rhs(object, loc);
  }
  else
  {
    return name_input(object);
  }
}
exprt dereference_rec(
 const exprt &src,
 const ssa_value_domaint &ssa_value_domain, 
 const std::string &nondet_prefix,
 const namespacet &ns)
{
  if(src.id()==ID_dereference)
  {
    const exprt &pointer=to_dereference_expr(src).pointer();
    exprt pointer_deref=dereference(pointer, ssa_value_domain, nondet_prefix, ns);

    // We use the identifier produced by
    // local_SSAt::replace_side_effects_rec
    exprt result=symbol_exprt(nondet_prefix, src.type());

    // query the value sets
    const ssa_value_domaint::valuest values=
      ssa_value_domain(pointer, ns);

    for(ssa_value_domaint::valuest::value_sett::const_iterator
        it=values.value_set.begin();
        it!=values.value_set.end();
        it++)
    {
      exprt guard=ssa_alias_guard(src, it->get_expr(), ns);
      exprt value=ssa_alias_value(src, it->get_expr(), ns);
      result=if_exprt(guard, value, result);
    }

    return result;
  }
  else if(src.id()==ID_member)
  {
    member_exprt tmp=to_member_expr(src);
    tmp.struct_op()=dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns);
    
    #ifdef DEBUG
    std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n';
    #endif

    if(tmp.struct_op().is_nil())
      return nil_exprt();
      
    return lift_if(tmp);
  }
  else if(src.id()==ID_address_of)
  {
    address_of_exprt tmp=to_address_of_expr(src);
    tmp.object()=dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns);

    if(tmp.object().is_nil())
      return nil_exprt();
    
    return lift_if(tmp);
  }
  else
  {
    exprt tmp=src;
    Forall_operands(it, tmp)
      *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns);
    return tmp;
  }
}
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);
  }
Beispiel #9
0
exprt address_canonizer(
  const exprt &address,
  const namespacet &ns)
{
  assert(ns.follow(address.type()).id()==ID_pointer);

  if(address.id()==ID_address_of)
  {
    const address_of_exprt &address_of_expr=
      to_address_of_expr(address);
    const exprt &object=address_of_expr.object();

    if(object.id()==ID_dereference)
    {
      // &*x ---> x
      return to_dereference_expr(object).pointer();
    }
    else if(object.id()==ID_member)
    {
      // get offset
      exprt offset=member_offset_expr(to_member_expr(object), ns);

      // &x.m  ---> (&x)+offset

      address_of_exprt address_of_expr(to_member_expr(object).struct_op());
      exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call

      pointer_typet byte_pointer(unsigned_char_type());
      typecast_exprt typecast_expr(rec_result, byte_pointer);
      plus_exprt sum(typecast_expr, offset);
      if(sum.type()!=address.type())
        sum.make_typecast(address.type());

      return sum;
    }
    else if(object.id()==ID_index)
    {
      // &(x[i]) ---> (&x)+i
      address_of_exprt address_of_expr(to_index_expr(object).array());
      exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call

      pointer_typet pointer_type;
      pointer_type.subtype()=object.type();
      typecast_exprt typecast_expr(rec_result, pointer_type);
      plus_exprt sum(typecast_expr, to_index_expr(object).index());
      if(sum.type()!=address.type())
        sum.make_typecast(address.type());

      return sum;
    }
    else if(object.id()==ID_symbol && is_iterator(object))
    {
      // address of iterator is dereferenced to a corresponding symbol -
      // will be bound to real address during analysis
      symbol_exprt iterator_addr(
        id2string(to_symbol_expr(object).get_identifier())+"'addr",
        address.type());
      return iterator_addr;
    }
    else
      return address;
  }
  else if(address.id()==ID_plus ||
          address.id()==ID_minus)
  {
    // one of the operands needs to be a pointer
    assert(address.operands().size()==2);
    exprt tmp=address;
    if(ns.follow(tmp.op0().type()).id()==ID_pointer)
    {
      tmp.op0()=address_canonizer(tmp.op0(), ns);
      return tmp;
    }
    else if(ns.follow(tmp.op1().type()).id()==ID_pointer)
    {
      tmp.op1()=address_canonizer(tmp.op1(), ns);
      return tmp;
    }
    else
      return tmp;
  }
  else if(address.id()==ID_if)
  {
    if_exprt tmp=to_if_expr(address);
    tmp.true_case()=address_canonizer(tmp.true_case(), ns);
    tmp.false_case()=address_canonizer(tmp.false_case(), ns);
    return tmp;
  }
  else if(address.id()==ID_typecast)
  {
    typecast_exprt tmp=to_typecast_expr(address);

    // cast from another pointer?
    if(tmp.op().type().id()==ID_pointer)
    {
      tmp.op()=address_canonizer(tmp.op(), ns);
      return tmp;
    }

    return address;
  }
  else
    return address;
}
bool remove_const_function_pointerst::try_resolve_dereference(
  const dereference_exprt &deref_expr,
  expressionst &out_expressions,
  bool &out_is_const)
{
  // We had a pointer, we need to check both the pointer
  // type can't be changed, and what it what pointing to
  // can't be changed
  expressionst pointer_values;
  bool pointer_const;
  bool resolved=
    try_resolve_expression(deref_expr.pointer(), pointer_values, pointer_const);
  if(resolved && pointer_const)
  {
    bool all_objects_const=true;
    for(const exprt &pointer_val : pointer_values)
    {
      if(pointer_val.id()==ID_address_of)
      {
        address_of_exprt address_expr=to_address_of_expr(pointer_val);
        bool object_const=false;
        expressionst out_object_values;
        bool resolved=
          try_resolve_expression(
            address_expr.object(), out_object_values, object_const);

        if(resolved)
        {
          out_expressions.insert(
            out_expressions.end(),
            out_object_values.begin(),
            out_object_values.end());

          all_objects_const&=object_const;
        }
        else
        {
          LOG("Failed to resolve value of a dereference", address_expr);
        }
      }
      else
      {
        LOG(
          "Squashing dereference did not result in an address", pointer_val);
        return false;
      }
    }
    out_is_const=all_objects_const;
    return true;
  }
  else
  {
    if(!resolved)
    {
      LOG("Failed to resolve pointer of dereference", deref_expr);
    }
    else if(!pointer_const)
    {
      LOG("Pointer value not const so can't squash", deref_expr);
    }
    return false;
  }
}
bool remove_const_function_pointerst::try_resolve_function_call(
  const exprt &expr, functionst &out_functions)
{
  assert(out_functions.empty());
  const exprt &simplified_expr=simplify_expr(expr, ns);
  bool resolved=false;
  functionst resolved_functions;
  if(simplified_expr.id()==ID_index)
  {
    const index_exprt &index_expr=to_index_expr(simplified_expr);
    resolved=try_resolve_index_of_function_call(index_expr, resolved_functions);
  }
  else if(simplified_expr.id()==ID_member)
  {
    const member_exprt &member_expr=to_member_expr(simplified_expr);
    resolved=try_resolve_member_function_call(member_expr, resolved_functions);
  }
  else if(simplified_expr.id()==ID_address_of)
  {
    address_of_exprt address_expr=to_address_of_expr(simplified_expr);
    resolved=try_resolve_address_of_function_call(
      address_expr, resolved_functions);
  }
  else if(simplified_expr.id()==ID_dereference)
  {
    const dereference_exprt &deref=to_dereference_expr(simplified_expr);
    resolved=try_resolve_dereference_function_call(deref, resolved_functions);
  }
  else if(simplified_expr.id()==ID_typecast)
  {
    typecast_exprt typecast_expr=to_typecast_expr(simplified_expr);
    resolved=
      try_resolve_typecast_function_call(typecast_expr, resolved_functions);
  }
  else if(simplified_expr.id()==ID_symbol)
  {
    if(simplified_expr.type().id()==ID_code)
    {
      resolved_functions.insert(simplified_expr);
      resolved=true;
    }
    else
    {
      LOG("Non const symbol wasn't squashed", simplified_expr);
      resolved=false;
    }
  }
  else
  {
    LOG("Unrecognised expression", simplified_expr);
    resolved=false;
  }

  if(resolved)
  {
    out_functions.insert(resolved_functions.begin(), resolved_functions.end());
    return true;
  }
  else
  {
    return false;
  }
}
Beispiel #12
0
void goto_symext::dereference_rec(
  exprt &expr,
  statet &state,
  guardt &guard,
  const bool write)
{
  if(expr.id()==ID_dereference)
  {
    if(expr.operands().size()!=1)
      throw "dereference takes one operand";

    exprt tmp1;
    tmp1.swap(expr.op0());

    // first make sure there are no dereferences in there
    dereference_rec(tmp1, state, guard, false);

    // we need to set up some elaborate call-backs
    symex_dereference_statet symex_dereference_state(*this, state);

    value_set_dereferencet dereference(
      ns,
      new_symbol_table,
      options,
      symex_dereference_state,
      language_mode);
    
    // std::cout << "**** " << from_expr(ns, "", tmp1) << std::endl;
    exprt tmp2=dereference.dereference(
      tmp1, guard, write?value_set_dereferencet::WRITE:value_set_dereferencet::READ);
    //std::cout << "**** " << from_expr(ns, "", tmp2) << std::endl;

    expr.swap(tmp2);

    // this may yield a new auto-object
    trigger_auto_object(expr, state);
  }
  else if(expr.id()==ID_index &&
          to_index_expr(expr).array().id()==ID_member &&
          to_array_type(ns.follow(to_index_expr(expr).array().type())).
            size().is_zero())
  {
    // This is an expression of the form x.a[i],
    // where a is a zero-sized array. This gets
    // re-written into *(&x.a+i)

    index_exprt index_expr=to_index_expr(expr);

    address_of_exprt address_of_expr(index_expr.array());
    address_of_expr.type()=pointer_typet(expr.type());

    dereference_exprt tmp;
    tmp.pointer()=plus_exprt(address_of_expr, index_expr.index());
    tmp.type()=expr.type();
    tmp.add_source_location()=expr.source_location();

    // recursive call
    dereference_rec(tmp, state, guard, write);

    expr.swap(tmp);
  }
  else if(expr.id()==ID_index &&
          to_index_expr(expr).array().type().id()==ID_pointer)
  {
    // old stuff, will go away
    assert(false);
  }
  else if(expr.id()==ID_address_of)
  {
    address_of_exprt &address_of_expr=to_address_of_expr(expr);

    exprt &object=address_of_expr.object();

    const typet &expr_type=ns.follow(expr.type());
    expr=address_arithmetic(object, state, guard,
                            expr_type.subtype().id()==ID_array);
  }
  else if(expr.id()==ID_typecast)
  {
    exprt &tc_op=to_typecast_expr(expr).op();

    // turn &array into &array[0] when casting to pointer-to-element-type
    if(tc_op.id()==ID_address_of &&
       to_address_of_expr(tc_op).object().type().id()==ID_array &&
       base_type_eq(
         expr.type(),
         pointer_typet(to_address_of_expr(tc_op).object().type().subtype()),
         ns))
    {
      expr=
        address_of_exprt(
          index_exprt(
            to_address_of_expr(tc_op).object(),
            from_integer(0, index_type())));

      dereference_rec(expr, state, guard, write);
    }
    else
    {
      dereference_rec(tc_op, state, guard, write);
    }
  }
  else
  {
    Forall_operands(it, expr)
      dereference_rec(*it, state, guard, write);
  }
}
Beispiel #13
0
exprt goto_symext::address_arithmetic(
  const exprt &expr,
  statet &state,
  guardt &guard,
  bool keep_array)
{
  exprt result;

  if(expr.id()==ID_byte_extract_little_endian ||
     expr.id()==ID_byte_extract_big_endian)
  {
    // address_of(byte_extract(op, offset, t)) is
    // address_of(op) + offset with adjustments for arrays

    const byte_extract_exprt &be=to_byte_extract_expr(expr);

    // recursive call
    result=address_arithmetic(be.op(), state, guard, keep_array);

    if(ns.follow(be.op().type()).id()==ID_array &&
       result.id()==ID_address_of)
    {
      address_of_exprt &a=to_address_of_expr(result);

      // turn &a of type T[i][j] into &(a[0][0])
      for(const typet *t=&(ns.follow(a.type().subtype()));
          t->id()==ID_array && !base_type_eq(expr.type(), *t, ns);
          t=&(ns.follow(*t).subtype()))
        a.object()=index_exprt(a.object(), from_integer(0, index_type()));
    }

    // do (expr.type() *)(((char *)op)+offset)
    result=typecast_exprt(result, pointer_typet(char_type()));

    // there could be further dereferencing in the offset
    exprt offset=be.offset();
    dereference_rec(offset, state, guard, false);

    result=plus_exprt(result, offset);

    // treat &array as &array[0]
    const typet &expr_type=ns.follow(expr.type());
    pointer_typet dest_type;

    if(expr_type.id()==ID_array && !keep_array)
      dest_type.subtype()=expr_type.subtype();
    else
      dest_type.subtype()=expr_type;

    result=typecast_exprt(result, dest_type);
  }
  else if(expr.id()==ID_index ||
          expr.id()==ID_member)
  {
    object_descriptor_exprt ode;
    ode.build(expr, ns);

    byte_extract_exprt be(byte_extract_id());
    be.type()=expr.type();
    be.op()=ode.root_object();
    be.offset()=ode.offset();

    // recursive call
    result=address_arithmetic(be, state, guard, keep_array);

    do_simplify(result);
  }
  else if(expr.id()==ID_dereference)
  {
    // ANSI-C guarantees &*p == p no matter what p is,
    // even if it's complete garbage
    // just grab the pointer, but be wary of further dereferencing
    // in the pointer itself
    result=to_dereference_expr(expr).pointer();
    dereference_rec(result, state, guard, false);
  }
  else if(expr.id()==ID_if)
  {
    if_exprt if_expr=to_if_expr(expr);

    // the condition is not an address
    dereference_rec(if_expr.cond(), state, guard, false);

    // recursive call
    if_expr.true_case()=
      address_arithmetic(if_expr.true_case(), state, guard, keep_array);
    if_expr.false_case()=
      address_arithmetic(if_expr.false_case(), state, guard, keep_array);

    result=if_expr;
  }
  else if(expr.id()==ID_symbol ||
          expr.id()==ID_string_constant ||
          expr.id()==ID_label ||
          expr.id()==ID_array)
  {
    // give up, just dereference
    result=expr;
    dereference_rec(result, state, guard, false);

    // turn &array into &array[0]
    if(ns.follow(result.type()).id()==ID_array && !keep_array)
      result=index_exprt(result, from_integer(0, index_type()));

    // handle field-sensitive SSA symbol
    mp_integer offset=0;
    if(expr.id()==ID_symbol &&
       expr.get_bool(ID_C_SSA_symbol))
    {
      offset=compute_pointer_offset(expr, ns);
      assert(offset>=0);
    }

    if(offset>0)
    {
      byte_extract_exprt be(byte_extract_id());
      be.type()=expr.type();
      be.op()=to_ssa_expr(expr).get_l1_object();
      be.offset()=from_integer(offset, index_type());

      result=address_arithmetic(be, state, guard, keep_array);

      do_simplify(result);
    }
    else
      result=address_of_exprt(result);
  }
  else
    throw "goto_symext::address_arithmetic does not handle "+expr.id_string();

  const typet &expr_type=ns.follow(expr.type());
  assert((expr_type.id()==ID_array && !keep_array) ||
         base_type_eq(pointer_typet(expr_type), result.type(), ns));

  return result;
}