Exemple #1
0
void goto_checkt::undefined_shift_check(
  const shift_exprt &expr,
  const guardt &guard)
{
  if(!enable_undefined_shift_check)
    return;

  // Undefined for all types and shifts if distance exceeds width,
  // and also undefined for negative distances.

  const typet &distance_type=
    ns.follow(expr.distance().type());

  if(distance_type.id()==ID_signedbv)
  {
    binary_relation_exprt inequality(
      expr.distance(), ID_ge, gen_zero(distance_type));

    add_guarded_claim(
      inequality,
      "shift distance is negative",
      "undefined-shift",
      expr.find_source_location(),
      expr,
      guard);
  }

  const typet &op_type=
    ns.follow(expr.op().type());

  if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv)
  {
    exprt width_expr=
      from_integer(to_bitvector_type(op_type).get_width(), distance_type);

    if(width_expr.is_nil())
      throw "no number for width for operator "+expr.id_string();

    binary_relation_exprt inequality(
      expr.distance(), ID_lt, width_expr);

    add_guarded_claim(
      inequality,
      "shift distance too large",
      "undefined-shift",
      expr.find_source_location(),
      expr,
      guard);
  }
}
Exemple #2
0
void goto_checkt::mod_by_zero_check(
  const mod_exprt &expr,
  const guardt &guard)
{
  if(!enable_div_by_zero_check)
    return;

  // 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(ID_notequal, bool_typet());
  inequality.copy_to_operands(expr.op1(), zero);

  add_guarded_claim(
    inequality,
    "division by zero",
    "division-by-zero",
    expr.find_source_location(),
    expr,
    guard);
}
Exemple #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);
}
Exemple #4
0
void goto_checkt::bounds_check(
  const index_exprt &expr,
  const guardt &guard)
{
  if(!enable_bounds_check)
    return;

  if(expr.find("bounds_check").is_not_nil() &&
     !expr.get_bool("bounds_check"))
    return;

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

  if(array_type.id()==ID_pointer)
    return; // done by the pointer code
  else if(array_type.id()==ID_incomplete_array)
    throw "index got incomplete array";
  else if(array_type.id()!=ID_array && array_type.id()!=ID_vector)
    throw "bounds check expected array or vector type, got "
      +array_type.id_string();

  std::string name=array_name(expr.array());

  const exprt &index=expr.index();
  object_descriptor_exprt ode;
  ode.build(expr, ns);

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

      if(!to_integer(index, i) && i>=0)
      {
        // ok
      }
      else
      {
        exprt effective_offset=ode.offset();

        if(ode.root_object().id()==ID_dereference)
        {
          exprt p_offset=pointer_offset(
            to_dereference_expr(ode.root_object()).pointer());
          assert(p_offset.type()==effective_offset.type());

          effective_offset=plus_exprt(p_offset, effective_offset);
        }

        exprt zero=gen_zero(ode.offset().type());
        assert(zero.is_not_nil());

        // the final offset must not be negative
        binary_relation_exprt inequality(effective_offset, ID_ge, zero);

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

  if(ode.root_object().id()==ID_dereference)
  {
    const exprt &pointer=
      to_dereference_expr(ode.root_object()).pointer();

    if_exprt size(
      dynamic_object(pointer),
      typecast_exprt(dynamic_size(ns), object_size(pointer).type()),
      object_size(pointer));

    plus_exprt effective_offset(ode.offset(), pointer_offset(pointer));

    assert(effective_offset.op0().type()==effective_offset.op1().type());
    assert(effective_offset.type()==size.type());

    binary_relation_exprt inequality(effective_offset, ID_lt, size);

    or_exprt precond(
      and_exprt(
        dynamic_object(pointer),
        not_exprt(malloc_object(pointer, ns))),
      inequality);

    add_guarded_claim(
      precond,
      name+" upper bound",
      "array bounds",
      expr.find_source_location(),
      expr,
      guard);

    return;
  }

  const exprt &size=array_type.id()==ID_array ?
                    to_array_type(array_type).size() :
                    to_vector_type(array_type).size();

  if(size.is_nil())
  {
    // Linking didn't complete, we don't have a size.
    // Not clear what to do.
  }
  else if(size.id()==ID_infinity)
  {
  }
  else if(size.is_zero() &&
          expr.array().id()==ID_member)
  {
    // a variable sized struct member
  }
  else
  {
    binary_relation_exprt inequality(index, ID_lt, size);

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

    // 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_source_location(),
      expr,
      guard);
  }
}
void value_set_dereferencet::bounds_check(
  const index_exprt &expr,
  const guardt &guard)
{
  if(!options.get_bool_option("pointer-check"))
    return;

  if(!options.get_bool_option("bounds-check"))
    return;

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

  if(array_type.id()!=ID_array)
    throw "bounds check expected array type";

  std::string name=array_name(ns, expr.array());

  {
    mp_integer i;
    if(!to_integer(expr.index(), i) &&
       i>=0)
    {
    }
    else
    {
      exprt zero=from_integer(0, expr.index().type());

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

      binary_relation_exprt
        inequality(expr.index(), ID_lt, zero);

      guardt tmp_guard(guard);
      tmp_guard.add(inequality);
      dereference_callback.dereference_failure(
        "array bounds",
        name+" lower bound", tmp_guard);
    }
  }

  const exprt &size_expr=
    to_array_type(array_type).size();

  if(size_expr.id()==ID_infinity)
  {
  }
  else if(size_expr.is_zero() && expr.array().id()==ID_member)
  {
    // this is a variable-sized struct field
  }
  else
  {
    if(size_expr.is_nil())
      throw "index array operand of wrong type";

    binary_relation_exprt inequality(expr.index(), ID_ge, size_expr);

    if(c_implicit_typecast(
      inequality.op0(),
      inequality.op1().type(),
      ns))
      throw "index address of wrong type";

    guardt tmp_guard(guard);
    tmp_guard.add(inequality);
    dereference_callback.dereference_failure(
      "array bounds",
      name+" upper bound", tmp_guard);
  }
}
Exemple #6
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);
    }
  }
}