Ejemplo n.º 1
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);
  }
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
0
void goto_checkt::invalidate(const exprt &lhs)
{
  if(lhs.id()==ID_index)
    invalidate(to_index_expr(lhs).array());
  else if(lhs.id()==ID_member)
    invalidate(to_member_expr(lhs).struct_op());
  else if(lhs.id()==ID_symbol)
  {
    // clear all assertions about 'symbol'
    find_symbols_sett find_symbols_set;
    find_symbols_set.insert(to_symbol_expr(lhs).get_identifier());

    for(assertionst::iterator
        it=assertions.begin();
        it!=assertions.end();
        ) // no it++
    {
      assertionst::iterator next=it;
      next++;

      if(has_symbol(*it, find_symbols_set) ||
         has_dereference(*it))
        assertions.erase(it);

      it=next;
    }
  }
  else
  {
    // give up, clear all
    assertions.clear();
  }
}
bool remove_const_function_pointerst::try_resolve_expression(
  const exprt &expr, expressionst &out_resolved_expression, bool &out_is_const)
{
  exprt simplified_expr=simplify_expr(expr, ns);
  bool resolved;
  expressionst resolved_expressions;
  bool is_resolved_expression_const;
  if(simplified_expr.id()==ID_index)
  {
    const index_exprt &index_expr=to_index_expr(simplified_expr);
    resolved=
      try_resolve_index_of(
        index_expr, resolved_expressions, is_resolved_expression_const);
  }
  else if(simplified_expr.id()==ID_member)
  {
    const member_exprt &member_expr=to_member_expr(simplified_expr);
    resolved=try_resolve_member(
      member_expr, resolved_expressions, is_resolved_expression_const);
  }
  else if(simplified_expr.id()==ID_dereference)
  {
    const dereference_exprt &deref=to_dereference_expr(simplified_expr);
    resolved=
      try_resolve_dereference(
        deref, resolved_expressions, is_resolved_expression_const);
  }
  else if(simplified_expr.id()==ID_typecast)
  {
    typecast_exprt typecast_expr=to_typecast_expr(simplified_expr);
    resolved=
      try_resolve_typecast(
        typecast_expr, resolved_expressions, is_resolved_expression_const);
  }
  else if(simplified_expr.id()==ID_symbol)
  {
    LOG("Non const symbol will not be squashed", simplified_expr);
    resolved=false;
  }
  else
  {
    resolved_expressions.push_back(simplified_expr);
    is_resolved_expression_const=is_const_expression(simplified_expr);
    resolved=true;
  }

  if(resolved)
  {
    out_resolved_expression.insert(
      out_resolved_expression.end(),
      resolved_expressions.begin(),
      resolved_expressions.end());
    out_is_const=is_resolved_expression_const;
    return true;
  }
  else
  {
    return false;
  }
}
Ejemplo n.º 5
0
exprt local_SSAt::read_rhs_address_of_rec(
  const exprt &expr,
  locationt loc) const
{
  if(expr.id()==ID_dereference)
  {
    // We 'read' the pointer only, the dereferencing expression stays.
    dereference_exprt tmp=to_dereference_expr(expr);
    tmp.pointer()=read_rhs_rec(tmp.pointer(), loc);
    return tmp;
  }
  else if(expr.id()==ID_member)
  {
    member_exprt tmp=to_member_expr(expr);
    tmp.struct_op()=read_rhs_address_of_rec(tmp.struct_op(), loc);
    return tmp;
  }
  else if(expr.id()==ID_index)
  {
    index_exprt tmp=to_index_expr(expr);
    tmp.array()=read_rhs_address_of_rec(tmp.array(), loc);
    tmp.index()=read_rhs_rec(tmp.index(), loc);
    return tmp;
  }
  else if(expr.id()==ID_if)
  {
    if_exprt tmp=to_if_expr(expr);
    tmp.cond()=read_rhs_rec(tmp.cond(), loc);
    tmp.true_case()=read_rhs_address_of_rec(tmp.true_case(), loc);
    tmp.false_case()=read_rhs_address_of_rec(tmp.false_case(), loc);
    return tmp;
  }
  else
    return expr;
}
Ejemplo n.º 6
0
void rd_range_domaint::assign(
  const namespacet &ns,
  locationt from,
  const exprt &lhs,
  const mp_integer &range_start,
  const mp_integer &size)
{
  if(lhs.id()==ID_member)
    assign(ns, from, to_member_expr(lhs).struct_op(), range_start, size);
  else if(lhs.id()==ID_index)
    assign(ns, from, to_index_expr(lhs).array(), range_start, size);
  else
  {
    const symbol_exprt &symbol=to_symbol_expr(lhs);
    const irep_idt identifier=symbol.get_identifier();

    if(range_start>=0)
    {
      kill(from, identifier, range_start, size);
      gen(from, identifier, range_start, size);
    }
    else
    {
      mp_integer full_size=pointer_offset_size(ns, symbol.type());
      gen(from, identifier, 0, full_size);
    }
  }
}
Ejemplo n.º 7
0
static void build_object_descriptor_rec(
  const namespacet &ns,
  const exprt &expr,
  object_descriptor_exprt &dest)
{
  const signedbv_typet index_type(config.ansi_c.pointer_width);

  if(expr.id()==ID_index)
  {
    const index_exprt &index=to_index_expr(expr);

    build_object_descriptor_rec(ns, index.array(), dest);

    exprt sub_size=size_of_expr(expr.type(), ns);
    assert(sub_size.is_not_nil());

    dest.offset()=
      plus_exprt(dest.offset(),
                 mult_exprt(typecast_exprt(index.index(), index_type),
                            typecast_exprt(sub_size, index_type)));
  }
  else if(expr.id()==ID_member)
  {
    const member_exprt &member=to_member_expr(expr);
    const exprt &struct_op=member.struct_op();

    build_object_descriptor_rec(ns, struct_op, dest);

    exprt offset=member_offset_expr(member, ns);
    assert(offset.is_not_nil());

    dest.offset()=
      plus_exprt(dest.offset(),
                 typecast_exprt(offset, index_type));
  }
  else if(expr.id()==ID_byte_extract_little_endian ||
          expr.id()==ID_byte_extract_big_endian)
  {
    const byte_extract_exprt &be=to_byte_extract_expr(expr);

    dest.object()=be.op();

    build_object_descriptor_rec(ns, be.op(), dest);

    dest.offset()=
      plus_exprt(dest.offset(),
                 typecast_exprt(to_byte_extract_expr(expr).offset(),
                                index_type));
  }
  else if(expr.id()==ID_typecast)
  {
    const typecast_exprt &tc=to_typecast_expr(expr);

    dest.object()=tc.op();

    build_object_descriptor_rec(ns, tc.op(), dest);
  }
}
Ejemplo n.º 8
0
void uninitialized_domaint::assign(const exprt &lhs)
{
  if(lhs.id()==ID_index)
    assign(to_index_expr(lhs).array());
  else if(lhs.id()==ID_member)
    assign(to_member_expr(lhs).struct_op());
  else if(lhs.id()==ID_symbol)
    uninitialized.erase(to_symbol_expr(lhs).get_identifier());
}
Ejemplo n.º 9
0
bool goto_convertt::needs_cleaning(const exprt &expr)
{
  if(expr.id()==ID_dereference ||
     expr.id()==ID_sideeffect ||
     expr.id()==ID_compound_literal ||
     expr.id()==ID_comma)
    return true;

  if(expr.id()==ID_index)
  {
    // Will usually clean index because of possible memory violation.
    // We do an exception for "string-lit"[0], which is safe.
    if(to_index_expr(expr).array().id()==ID_string_constant &&
       to_index_expr(expr).index().is_zero())
      return false;
    
    return true;
  }

  // We can't flatten quantified expressions by introducing new literals for
  // conditional expressions.  This is because the body of the quantified
  // may refer to bound variables, which are not visible outside the scope
  // of the quantifier.
  //
  // For example, the following transformation would not be valid:
  //
  // forall (i : int) (i == 0 || i > 10)
  //
  //   transforming to
  //
  // g1 = (i == 0)
  // g2 = (i > 10)
  // forall (i : int) (g1 || g2)
  if(expr.id()==ID_forall || expr.id()==ID_exists)
    return false;
  
  forall_operands(it, expr)
    if(needs_cleaning(*it))
      return true;
      
  return false;
}
Ejemplo n.º 10
0
static void build_ssa_identifier_rec(
  const exprt &expr,
  const irep_idt &l0,
  const irep_idt &l1,
  const irep_idt &l2,
  std::ostream &os,
  std::ostream &l1_object_os)
{
  if(expr.id()==ID_member)
  {
    const member_exprt &member=to_member_expr(expr);

    build_ssa_identifier_rec(member.struct_op(), l0, l1, l2, os, l1_object_os);

    os << '.' << member.get_component_name();
  }
  else if(expr.id()==ID_index)
  {
    const index_exprt &index=to_index_expr(expr);

    build_ssa_identifier_rec(index.array(), l0, l1, l2, os, l1_object_os);

    mp_integer idx;
    if(to_integer(to_constant_expr(index.index()), idx))
      assert(false);

    os << '[' << idx << ']';
  }
  else if(expr.id()==ID_symbol)
  {
    auto symid=to_symbol_expr(expr).get_identifier();
    os << symid;
    l1_object_os << symid;

    if(!l0.empty())
    {
      os << '!' << l0;
      l1_object_os << '!' << l0;
    }

    if(!l1.empty())
    {
      os << '@' << l1;
      l1_object_os << '@' << l1;
    }

    if(!l2.empty())
      os << '#' << l2;
  }
  else
    assert(false);
}
Ejemplo n.º 11
0
bool is_lvalue(const exprt &expr)
{
  if(expr.id()==ID_index)
    return is_lvalue(to_index_expr(expr).op0());
  else if(expr.id()==ID_member)
    return is_lvalue(to_member_expr(expr).op0());
  else if(expr.id()==ID_dereference)
    return true;
  else if(expr.id()==ID_symbol)
    return true;
  else
    return false;
}
Ejemplo n.º 12
0
void goto_symext::dereference_rec_address_of(
  exprt &expr,
  statet &state,
  guardt &guard)
{
  // Could be member, could be if, could be index.

  if(expr.id()==ID_member)
    dereference_rec_address_of(
      to_member_expr(expr).struct_op(), state, guard);
  else if(expr.id()==ID_if)
  {
    // the condition is not an address
    dereference_rec(
      to_if_expr(expr).cond(), state, guard, false);

    // add to guard?
    dereference_rec_address_of(
      to_if_expr(expr).true_case(), state, guard);
    dereference_rec_address_of(
      to_if_expr(expr).false_case(), state, guard);
  }
  else if(expr.id()==ID_index)
  {
    // the index is not an address
    dereference_rec(
      to_index_expr(expr).index(), state, guard, false);

    // the array _is_ an address
    dereference_rec_address_of(
      to_index_expr(expr).array(), state, guard);
  }
  else
  {
    // give up and dereference

    dereference_rec(expr, state, guard, false);
  }
}
Ejemplo n.º 13
0
exprt path_symex_statet::array_theory(const exprt &src, bool propagate)
{
  // top-level constant-sized arrays only right now

  if(src.id()==ID_index)
  {
    const index_exprt &index_expr=to_index_expr(src);
    exprt index_tmp1=read(index_expr.index(), propagate);
    exprt index_tmp2=simplify_expr(index_tmp1, var_map.ns);

    if(!index_tmp2.is_constant())
    {
      const array_typet &array_type=to_array_type(index_expr.array().type());
      const typet &subtype=array_type.subtype();

      if(array_type.size().is_constant())
      {
        mp_integer size;
        if(to_integer(array_type.size(), size))
          throw "failed to convert array size";

        std::size_t size_int=integer2size_t(size);

        exprt result=nil_exprt();

        // split it up
        for(std::size_t i=0; i<size_int; ++i)
        {
          exprt index=from_integer(i, index_expr.index().type());
          exprt new_src=index_exprt(index_expr.array(), index, subtype);

          if(result.is_nil())
            result=new_src;
          else
          {
            equal_exprt index_equal(index_expr.index(), index);
            result=if_exprt(index_equal, new_src, result);
          }
        }

        return result; // done
      }
      else
      {
        // TODO: variable-sized array
      }
    }
  }

  return src;
}
Ejemplo n.º 14
0
bool simplify_exprt::simplify_inequality_address_of(exprt &expr)
{
    assert(expr.type().id()==ID_bool);
    assert(expr.operands().size()==2);
    assert(expr.id()==ID_equal || expr.id()==ID_notequal);

    exprt tmp0=expr.op0();
    if(tmp0.id()==ID_typecast)
        tmp0=expr.op0().op0();
    if(tmp0.op0().id()==ID_index &&
            to_index_expr(tmp0.op0()).index().is_zero())
        tmp0=address_of_exprt(to_index_expr(tmp0.op0()).array());
    exprt tmp1=expr.op1();
    if(tmp1.id()==ID_typecast)
        tmp1=expr.op1().op0();
    if(tmp1.op0().id()==ID_index &&
            to_index_expr(tmp1.op0()).index().is_zero())
        tmp1=address_of_exprt(to_index_expr(tmp1.op0()).array());
    assert(tmp0.id()==ID_address_of);
    assert(tmp1.id()==ID_address_of);

    if(tmp0.operands().size()!=1) return true;
    if(tmp1.operands().size()!=1) return true;

    if(tmp0.op0().id()==ID_symbol &&
            tmp1.op0().id()==ID_symbol)
    {
        bool equal=
            tmp0.op0().get(ID_identifier)==
            tmp1.op0().get(ID_identifier);

        expr.make_bool(expr.id()==ID_equal?equal:!equal);

        return false;
    }

    return true;
}
Ejemplo n.º 15
0
bool simplify_exprt::simplify_address_of(exprt &expr)
{
    if(expr.operands().size()!=1) return true;

    if(ns.follow(expr.type()).id()!=ID_pointer) return true;

    exprt &object=expr.op0();

    bool result=simplify_address_of_arg(object);

    if(object.id()==ID_index)
    {
        index_exprt &index_expr=to_index_expr(object);

        if(!index_expr.index().is_zero())
        {
            // we normalize &a[i] to (&a[0])+i
            exprt offset;
            offset.swap(index_expr.op1());
            index_expr.op1()=gen_zero(offset.type());

            exprt addition(ID_plus, expr.type());
            addition.move_to_operands(expr, offset);

            expr.swap(addition);
            return false;
        }
    }
    else if(object.id()==ID_dereference)
    {
        // simplify &*p to p
        assert(object.operands().size()==1);
        exprt tmp=object.op0();
        expr=tmp;
        return false;
    }

    return result;
}
Ejemplo n.º 16
0
Archivo: ai.cpp Proyecto: danpoe/cbmc
/// Use the information in the domain to simplify the expression on the LHS of
/// an assignment. This for example won't simplify symbols to their values, but
/// does simplify indices in arrays, members of structs and dereferencing of
/// pointers
/// \param condition: the expression to simplify
/// \param ns: the namespace
/// \return True if condition did not change. False otherwise. condition will be
///   updated with the simplified condition if it has worked
bool ai_domain_baset::ai_simplify_lhs(
  exprt &condition, const namespacet &ns) const
{
  // Care must be taken here to give something that is still writable
  if(condition.id()==ID_index)
  {
    index_exprt ie=to_index_expr(condition);
    bool no_simplification=ai_simplify(ie.index(), ns);
    if(!no_simplification)
      condition=simplify_expr(ie, ns);

    return no_simplification;
  }
  else if(condition.id()==ID_dereference)
  {
    dereference_exprt de=to_dereference_expr(condition);
    bool no_simplification=ai_simplify(de.pointer(), ns);
    if(!no_simplification)
      condition=simplify_expr(de, ns);  // So *(&x) -> x

    return no_simplification;
  }
  else if(condition.id()==ID_member)
  {
    member_exprt me=to_member_expr(condition);
    // Since simplify_ai_lhs is required to return an addressable object
    // (so remains a valid left hand side), to simplify
    // `(something_simplifiable).b` we require that `something_simplifiable`
    // must also be addressable
    bool no_simplification=ai_simplify_lhs(me.compound(), ns);
    if(!no_simplification)
      condition=simplify_expr(me, ns);

    return no_simplification;
  }
  else
    return true;
}
Ejemplo n.º 17
0
bool goto_symext::is_index_member_symbol_if(const exprt &expr)
{
  // Could be member, could be if, could be index.

  if(expr.id()==ID_member)
  {
    return is_index_member_symbol_if(
      to_member_expr(expr).struct_op());
  }
  else if(expr.id()==ID_if)
  {
    return
      is_index_member_symbol_if(to_if_expr(expr).true_case()) &&
      is_index_member_symbol_if(to_if_expr(expr).false_case());
  }
  else if(expr.id()==ID_index)
  {
    return is_index_member_symbol_if(to_index_expr(expr).array());
  }
  else if(expr.id()==ID_symbol)
    return true;
  else
    return false;
}
Ejemplo n.º 18
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);
  }
}
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;
  }
}
Ejemplo n.º 20
0
bool ssa_may_alias(
  const exprt &e1,
  const exprt &e2,
  const namespacet &ns)
{
  #ifdef DEBUG
  std::cout << "MAY ALIAS1 " << from_expr(ns, "", e1) << " "
                             << from_expr(ns, "", e2) << "\n";
  #endif

  // The same?
  if(e1==e2)
    return true;

  // Both symbol?
  if(e1.id()==ID_symbol &&
     e2.id()==ID_symbol)
  {
    return to_symbol_expr(e1).get_identifier()==
           to_symbol_expr(e2).get_identifier();
  }

  // __CPROVER symbols
  if(e1.id()==ID_symbol &&
     has_prefix(
       id2string(to_symbol_expr(e1).get_identifier()), CPROVER_PREFIX))
    return false;

  if(e2.id()==ID_symbol &&
     has_prefix(
       id2string(to_symbol_expr(e2).get_identifier()), CPROVER_PREFIX))
    return false;

  if(e1.id()==ID_symbol &&
     has_suffix(
       id2string(to_symbol_expr(e1).get_identifier()), "#return_value"))
    return false;

  if(e2.id()==ID_symbol &&
     has_suffix(
       id2string(to_symbol_expr(e2).get_identifier()), "#return_value"))
    return false;

  // Both member?
  if(e1.id()==ID_member &&
     e2.id()==ID_member)
  {
    const member_exprt &m1=to_member_expr(e1);
    const member_exprt &m2=to_member_expr(e2);

    // same component?
    if(m1.get_component_name()!=m2.get_component_name())
      return false;

    return ssa_may_alias(m1.struct_op(), m2.struct_op(), ns);
  }

  // Both index?
  if(e1.id()==ID_index &&
     e2.id()==ID_index)
  {
    const index_exprt &i1=to_index_expr(e1);
    const index_exprt &i2=to_index_expr(e2);

    return ssa_may_alias(i1.array(), i2.array(), ns);
  }

  const typet &t1=ns.follow(e1.type());
  const typet &t2=ns.follow(e2.type());

  // If one is an array and the other not, consider the elements
  if(t1.id()==ID_array && t2.id()!=ID_array)
    if(ssa_may_alias(
         index_exprt(e1, gen_zero(index_type()), t1.subtype()), e2, ns))
      return true;

  if(t2.id()==ID_array && t2.id()!=ID_array)
    if(ssa_may_alias(
         e1, index_exprt(e2, gen_zero(index_type()), t2.subtype()), ns))
      return true;

  // Pointers only alias with other pointers,
  // which is a restriction.
  if(t1.id()==ID_pointer)
    return t2.id()==ID_pointer;

  if(t2.id()==ID_pointer)
    return t1.id()==ID_pointer;

  // Is one a scalar pointer?
  if(e1.id()==ID_dereference &&
     (t1.id()==ID_signedbv || t1.id()==ID_unsignedbv || t1.id()==ID_floatbv))
    return true;

  if(e2.id()==ID_dereference &&
     (t2.id()==ID_signedbv || t2.id()==ID_unsignedbv || t1.id()==ID_floatbv))
    return true;

  // Is one a pointer?
  if(e1.id()==ID_dereference ||
     e2.id()==ID_dereference)
  {
    // look at the types

    // same type?
    if(base_type_eq(t1, t2, ns))
    {
      return true;
    }

    // should consider further options, e.g., struct prefixes
    return false;
  }

  return false; // both different objects
}
Ejemplo n.º 21
0
bool simplify_exprt::simplify_index(exprt &expr)
{
  bool result=true;

  // extra arithmetic optimizations
  const exprt &index=to_index_expr(expr).index();
  const exprt &array=to_index_expr(expr).array();

  if(index.id()==ID_div &&
     index.operands().size()==2)
  {
    if(index.op0().id()==ID_mult &&
       index.op0().operands().size()==2 &&
       index.op0().op1()==index.op1())
    {
      exprt tmp=index.op0().op0();
      expr.op1()=tmp;
      result=false;
    }
    else if(index.op0().id()==ID_mult &&
            index.op0().operands().size()==2 &&
            index.op0().op0()==index.op1())
    {
      exprt tmp=index.op0().op1();
      expr.op1()=tmp;
      result=false;
    }
  }

  if(array.id()==ID_lambda)
  {
    // simplify (lambda i: e)(x) to e[i/x]

    const exprt &lambda_expr=array;

    if(lambda_expr.operands().size()!=2)
      return true;

    if(expr.op1().type()==lambda_expr.op0().type())
    {
      exprt tmp=lambda_expr.op1();
      replace_expr(lambda_expr.op0(), expr.op1(), tmp);
      expr.swap(tmp);
      return false;
    }
  }
  else if(array.id()==ID_with)
  {
    // we have (a WITH [i:=e])[j]

    const exprt &with_expr=array;

    if(with_expr.operands().size()!=3)
      return true;

    if(with_expr.op1()==expr.op1())
    {
      // simplify (e with [i:=v])[i] to v
      exprt tmp=with_expr.op2();
      expr.swap(tmp);
      return false;
    }
    else
    {
      // Turn (a with i:=x)[j] into (i==j)?x:a[j].
      // watch out that the type of i and j might be different.
      equal_exprt equality_expr(expr.op1(), with_expr.op1());

      if(equality_expr.lhs().type()!=equality_expr.rhs().type())
        equality_expr.rhs().make_typecast(equality_expr.lhs().type());

      simplify_inequality(equality_expr);

      index_exprt new_index_expr;
      new_index_expr.type()=expr.type();
      new_index_expr.array()=with_expr.op0();
      new_index_expr.index()=expr.op1();

      simplify_index(new_index_expr); // recursive call

      if(equality_expr.is_true())
      {
        expr=with_expr.op2();
        return false;
      }
      else if(equality_expr.is_false())
      {
        expr.swap(new_index_expr);
        return false;
      }

      if_exprt if_expr(equality_expr, with_expr.op2(), new_index_expr);
      simplify_if(if_expr);

      expr.swap(if_expr);

      return false;
    }
  }
  else if(array.id()==ID_constant ||
          array.id()==ID_array)
  {
    mp_integer i;

    if(to_integer(expr.op1(), i))
    {
    }
    else if(i<0 || i>=array.operands().size())
    {
      // out of bounds
    }
    else
    {
      // ok
      exprt tmp=array.operands()[integer2size_t(i)];
      expr.swap(tmp);
      return false;
    }
  }
  else if(array.id()==ID_string_constant)
  {
    mp_integer i;

    const irep_idt &value=array.get(ID_value);

    if(to_integer(expr.op1(), i))
    {
    }
    else if(i<0 || i>value.size())
    {
      // out of bounds
    }
    else
    {
      // terminating zero?
      char v=(i==value.size())?0:value[integer2size_t(i)];
      exprt tmp=from_integer(v, expr.type());
      expr.swap(tmp);
      return false;
    }
  }
  else if(array.id()==ID_array_of)
  {
    if(array.operands().size()==1)
    {
      exprt tmp=array.op0();
      expr.swap(tmp);
      return false;
    }
  }
  else if(array.id()=="array-list")
  {
    // These are index/value pairs, alternating.
    for(size_t i=0; i<array.operands().size()/2; i++)
    {
      exprt tmp_index=array.operands()[i*2];
      tmp_index.make_typecast(index.type());
      simplify(tmp_index);
      if(tmp_index==index)
      {
        exprt tmp=array.operands()[i*2+1];
        expr.swap(tmp);
        return false;
      }
    }
  }
  else if(array.id()==ID_byte_extract_little_endian ||
          array.id()==ID_byte_extract_big_endian)
  {
    const typet &array_type=ns.follow(array.type());

    if(array_type.id()==ID_array)
    {
      // This rewrites byte_extract(s, o, array_type)[i]
      // to byte_extract(s, o+offset, sub_type)

      mp_integer sub_size=pointer_offset_size(array_type.subtype(), ns);
      if(sub_size==-1)
        return true;

      // add offset to index
      mult_exprt offset(from_integer(sub_size, array.op1().type()), index);
      plus_exprt final_offset(array.op1(), offset);
      simplify_node(final_offset);

      exprt result(array.id(), expr.type());
      result.copy_to_operands(array.op0(), final_offset);
      expr.swap(result);

      simplify_rec(expr);

      return false;
    }
  }
  else if(array.id()==ID_if)
  {
    const if_exprt &if_expr=to_if_expr(array);
    exprt cond=if_expr.cond();

    index_exprt idx_false=to_index_expr(expr);
    idx_false.array()=if_expr.false_case();

    to_index_expr(expr).array()=if_expr.true_case();

    expr=if_exprt(cond, expr, idx_false, expr.type());
    simplify_rec(expr);

    return false;
  }

  return result;
}
Ejemplo n.º 22
0
exprt dereferencet::read_object(
  const exprt &object,
  const exprt &offset,
  const typet &type)
{
  const typet &object_type=ns.follow(object.type());
  const typet &dest_type=ns.follow(type);

  // is the object an array with matching subtype?

  exprt simplified_offset=simplify_expr(offset, ns);

  // check if offset is zero
  if(simplified_offset.is_zero())
  {
    // check type
    if(base_type_eq(object_type, dest_type, ns))
    {
      return object; // trivial case
    }
    else if(type_compatible(object_type, dest_type))
    {
      // the type differs, but we can do this with a typecast
      return typecast_exprt(object, dest_type);
    }
  }

  if(object.id()==ID_index)
  {
    const index_exprt &index_expr=to_index_expr(object);

    exprt index=index_expr.index();

    // multiply index by object size
    exprt size=size_of_expr(object_type, ns);

    if(size.is_nil())
      throw "dereference failed to get object size for index";

    index.make_typecast(simplified_offset.type());
    size.make_typecast(index.type());

    exprt new_offset=plus_exprt(simplified_offset, mult_exprt(index, size));

    return read_object(index_expr.array(), new_offset, type);
  }
  else if(object.id()==ID_member)
  {
    const member_exprt &member_expr=to_member_expr(object);

    const typet &compound_type=
      ns.follow(member_expr.struct_op().type());

    if(compound_type.id()==ID_struct)
    {
      const struct_typet &struct_type=
        to_struct_type(compound_type);

      exprt member_offset=member_offset_expr(
        struct_type, member_expr.get_component_name(), ns);

      if(member_offset.is_nil())
        throw "dereference failed to get member offset";

      member_offset.make_typecast(simplified_offset.type());

      exprt new_offset=plus_exprt(simplified_offset, member_offset);

      return read_object(member_expr.struct_op(), new_offset, type);
    }
    else if(compound_type.id()==ID_union)
    {
      // Unions are easy: the offset is always zero,
      // so simply pass down.
      return read_object(member_expr.struct_op(), offset, type);
    }
  }

  // check if we have an array with the right subtype
  if(object_type.id()==ID_array &&
     base_type_eq(object_type.subtype(), dest_type, ns))
  {
    // check proper alignment
    exprt size=size_of_expr(dest_type, ns);

    if(size.is_not_nil())
    {
      mp_integer size_constant, offset_constant;
      if(!to_integer(simplify_expr(size, ns), size_constant) &&
         !to_integer(simplified_offset, offset_constant) &&
         (offset_constant%size_constant)==0)
      {
        // Yes! Can use index expression!
        mp_integer index_constant=offset_constant/size_constant;
        exprt index_expr=from_integer(index_constant, size.type());
        return index_exprt(object, index_expr, dest_type);
      }
    }
  }

  // give up and use byte_extract
  return binary_exprt(object, byte_extract_id(), simplified_offset, dest_type);
}
Ejemplo n.º 23
0
void local_SSAt::assign_rec(
  const exprt &lhs,
  const exprt &rhs,
  const exprt &guard,
  locationt loc)
{
  const typet &type=ns.follow(lhs.type());

  if(is_symbol_struct_member(lhs, ns))
  {
    if(type.id()==ID_struct)
    {
      // need to split up

      const struct_typet &struct_type=to_struct_type(type);
      const struct_typet::componentst &components=struct_type.components();
      
      for(struct_typet::componentst::const_iterator
          it=components.begin();
          it!=components.end();
          it++)
      {
        member_exprt new_lhs(lhs, it->get_name(), it->type());
        member_exprt new_rhs(rhs, it->get_name(), it->type());
        assign_rec(new_lhs, new_rhs, guard, loc);
      }

      return;
    }

    ssa_objectt lhs_object(lhs, ns);
    
    const std::set<ssa_objectt> &assigned=
      assignments.get(loc);

    if(assigned.find(lhs_object)!=assigned.end())
    {
      exprt ssa_rhs=read_rhs(rhs, loc);

      const symbol_exprt ssa_symbol=name(lhs_object, OUT, loc);
      
      equal_exprt equality(ssa_symbol, ssa_rhs);
      nodes[loc].equalities.push_back(equality);
    }
  }
  else if(lhs.id()==ID_index)
  {
    const index_exprt &index_expr=to_index_expr(lhs);
    exprt ssa_array=index_expr.array();
    exprt new_rhs=with_exprt(ssa_array, index_expr.index(), rhs);
    assign_rec(index_expr.array(), new_rhs, guard, loc);
  }
  else if(lhs.id()==ID_member)
  {
    // These are non-flattened struct or union members.
    const member_exprt &member_expr=to_member_expr(lhs);
    const exprt &compound=member_expr.struct_op();
    const typet &compound_type=ns.follow(compound.type());

    if(compound_type.id()==ID_union)
    {
      union_exprt new_rhs(member_expr.get_component_name(), rhs, compound.type());
      assign_rec(member_expr.struct_op(), new_rhs, guard, loc);
    }
    else if(compound_type.id()==ID_struct)
    {
      exprt member_name(ID_member_name);
      member_name.set(ID_component_name, member_expr.get_component_name());
      with_exprt new_rhs(compound, member_name, rhs);
      assign_rec(compound, new_rhs, guard, loc);
    }
  }
  else if(lhs.id()==ID_complex_real)
  {
    assert(lhs.operands().size()==1);
    const exprt &op=lhs.op0();
    const complex_typet &complex_type=to_complex_type(op.type());
    exprt imag_op=unary_exprt(ID_complex_imag, op, complex_type.subtype());
    complex_exprt new_rhs(rhs, imag_op, complex_type);
    assign_rec(op, new_rhs, guard, loc);
  }
  else if(lhs.id()==ID_complex_imag)
  {
    assert(lhs.operands().size()==1);
    const exprt &op=lhs.op0();
    const complex_typet &complex_type=to_complex_type(op.type());
    exprt real_op=unary_exprt(ID_complex_real, op, complex_type.subtype());
    complex_exprt new_rhs(real_op, rhs, complex_type);
    assign_rec(op, new_rhs, guard, loc);
  }
  else if(lhs.id()==ID_if)
  {
    const if_exprt &if_expr=to_if_expr(lhs);
    assign_rec(if_expr.true_case(), rhs, and_exprt(guard, if_expr.cond()), loc);
    assign_rec(if_expr.false_case(), rhs, and_exprt(guard, not_exprt(if_expr.cond())), loc);
  }
  else if(lhs.id()==ID_byte_extract_little_endian ||
          lhs.id()==ID_byte_extract_big_endian)
  {
    const byte_extract_exprt &byte_extract_expr=to_byte_extract_expr(lhs);

    exprt new_lhs=byte_extract_expr.op();

    exprt new_rhs=byte_extract_exprt(
      byte_extract_expr.id(), rhs, byte_extract_expr.offset(), new_lhs.type());

    assign_rec(new_lhs, new_rhs, guard, loc);
  }
  else
    throw "UNKNOWN LHS: "+lhs.id_string();
}
Ejemplo n.º 24
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;
}
Ejemplo n.º 25
0
void goto_checkt::check_rec(
  const exprt &expr,
  guardt &guard,
  bool address)
{
  // we don't look into quantifiers
  if(expr.id()==ID_exists || expr.id()==ID_forall)
    return;

  if(address)
  {
    if(expr.id()==ID_dereference)
    {
      assert(expr.operands().size()==1);
      check_rec(expr.op0(), guard, false);
    }
    else if(expr.id()==ID_index)
    {
      assert(expr.operands().size()==2);
      check_rec(expr.op0(), guard, true);
      check_rec(expr.op1(), guard, false);
    }
    else
    {
      forall_operands(it, expr)
        check_rec(*it, guard, true);
    }
    return;
  }

  if(expr.id()==ID_address_of)
  {
    assert(expr.operands().size()==1);
    check_rec(expr.op0(), guard, true);
    return;
  }
  else if(expr.id()==ID_and || expr.id()==ID_or)
  {
    if(!expr.is_boolean())
      throw "`"+expr.id_string()+"' must be Boolean, but got "+
            expr.pretty();

    guardt old_guard=guard;

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

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

      check_rec(op, guard, false);

      if(expr.id()==ID_or)
        guard.add(not_exprt(op));
      else
        guard.add(op);
    }

    guard.swap(old_guard);

    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().pretty();
      throw msg;
    }

    check_rec(expr.op0(), guard, false);

    {
      guardt old_guard=guard;
      guard.add(expr.op0());
      check_rec(expr.op1(), guard, false);
      guard.swap(old_guard);
    }

    {
      guardt old_guard=guard;
      guard.add(not_exprt(expr.op0()));
      check_rec(expr.op2(), guard, false);
      guard.swap(old_guard);
    }

    return;
  }

  forall_operands(it, expr)
    check_rec(*it, guard, false);

  if(expr.id()==ID_index)
  {
    bounds_check(to_index_expr(expr), guard);
  }
  else if(expr.id()==ID_div)
  {
    div_by_zero_check(to_div_expr(expr), guard);

    if(expr.type().id()==ID_signedbv)
      integer_overflow_check(expr, guard);
    else if(expr.type().id()==ID_floatbv)
    {
      nan_check(expr, guard);
      float_overflow_check(expr, guard);
    }
  }
  else if(expr.id()==ID_shl || expr.id()==ID_ashr || expr.id()==ID_lshr)
  {
    undefined_shift_check(to_shift_expr(expr), guard);
  }
  else if(expr.id()==ID_mod)
  {
    mod_by_zero_check(to_mod_expr(expr), guard);
  }
  else if(expr.id()==ID_plus || expr.id()==ID_minus ||
          expr.id()==ID_mult ||
          expr.id()==ID_unary_minus)
  {
    if(expr.type().id()==ID_signedbv ||
       expr.type().id()==ID_unsignedbv)
    {
      if(expr.operands().size()==2 &&
         expr.op0().type().id()==ID_pointer)
        pointer_overflow_check(expr, guard);
      else
        integer_overflow_check(expr, guard);
    }
    else if(expr.type().id()==ID_floatbv)
    {
      nan_check(expr, guard);
      float_overflow_check(expr, guard);
    }
    else if(expr.type().id()==ID_pointer)
    {
      pointer_overflow_check(expr, guard);
    }
  }
  else if(expr.id()==ID_typecast)
    conversion_check(expr, guard);
  else if(expr.id()==ID_le || expr.id()==ID_lt ||
          expr.id()==ID_ge || expr.id()==ID_gt)
    pointer_rel_check(expr, guard);
  else if(expr.id()==ID_dereference)
    pointer_validity_check(to_dereference_expr(expr), guard);
}
Ejemplo n.º 26
0
exprt build_full_lhs_rec(
  const prop_convt &prop_conv,
  const namespacet &ns,
  const exprt &src_original, // original identifiers
  const exprt &src_ssa)      // renamed identifiers
{
  if(src_ssa.id()!=src_original.id())
    return src_original;

  const irep_idt id=src_original.id();

  if(id==ID_index)
  {
    // get index value from src_ssa
    exprt index_value=prop_conv.get(to_index_expr(src_ssa).index());

    if(index_value.is_not_nil())
    {
      simplify(index_value, ns);
      index_exprt tmp=to_index_expr(src_original);
      tmp.index()=index_value;
      tmp.array()=
        build_full_lhs_rec(prop_conv, ns,
          to_index_expr(src_original).array(),
          to_index_expr(src_ssa).array());
      return tmp;
    }

    return src_original;
  }
  else if(id==ID_member)
  {
    member_exprt tmp=to_member_expr(src_original);
    tmp.struct_op()=build_full_lhs_rec(
      prop_conv, ns,
      to_member_expr(src_original).struct_op(),
      to_member_expr(src_ssa).struct_op());
  }
  else if(id==ID_if)
  {
    if_exprt tmp2=to_if_expr(src_original);

    tmp2.false_case()=build_full_lhs_rec(prop_conv, ns,
      tmp2.false_case(), to_if_expr(src_ssa).false_case());

    tmp2.true_case()=build_full_lhs_rec(prop_conv, ns,
      tmp2.true_case(), to_if_expr(src_ssa).true_case());

    exprt tmp=prop_conv.get(to_if_expr(src_ssa).cond());

    if(tmp.is_true())
      return tmp2.true_case();
    else if(tmp.is_false())
      return tmp2.false_case();
    else
      return tmp2;
  }
  else if(id==ID_typecast)
  {
    typecast_exprt tmp=to_typecast_expr(src_original);
    tmp.op()=build_full_lhs_rec(prop_conv, ns,
      to_typecast_expr(src_original).op(), to_typecast_expr(src_ssa).op());
    return tmp;
  }
  else if(id==ID_byte_extract_little_endian ||
          id==ID_byte_extract_big_endian)
  {
    exprt tmp=src_original;
    assert(tmp.operands().size()==2);
    tmp.op0()=build_full_lhs_rec(prop_conv, ns, tmp.op0(), src_ssa.op0());

    // re-write into big case-split

  }

  return src_original;
}
Ejemplo n.º 27
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);
  }
}