Example #1
0
bool goto_symex_statet::constant_propagation(const expr2tc &expr) const
{
  static unsigned int with_counter=0;

  // Don't permit const propagaion of infinite-size arrays. They're going to
  // be special modelling arrays that require special handling either at SMT
  // or some other level, so attempting to optimse them is a Bad Plan (TM).
  if (is_array_type(expr) && to_array_type(expr->type).size_is_infinite)
    return false;

  if (is_nil_expr(expr)) {
    return true; // It's fine to constant propagate something that's absent.
  } else if (is_constant_expr(expr)) {
    return true;
  }
  else if (is_symbol2t(expr) && to_symbol2t(expr).thename == "NULL")
  {
    // Null is also essentially a constant.
    return true;
  }
  else if (is_address_of2t(expr))
  {
    return constant_propagation_reference(to_address_of2t(expr).ptr_obj);
  }
  else if (is_typecast2t(expr))
  {
    return constant_propagation(to_typecast2t(expr).from);
  }
  else if (is_add2t(expr))
  {
    forall_operands2(it, idx, expr)
      if(!constant_propagation(*it))
        return false;

    return true;
  }
  else if (is_constant_array_of2t(expr))
Example #2
0
void goto_symext::symex_other()
{
  const goto_programt::instructiont &instruction = *cur_state->source.pc;

  expr2tc code2 = instruction.code;

  if(is_code_expression2t(code2))
  {
    // Represents an expression that gets evaluated, but does not have any
    // other effect on execution, i.e. doesn't contain a call or assignment.
    // This can, however, cause the program to fail if it dereferences an
    // invalid pointer. Therefore, dereference it.
    const code_expression2t &expr = to_code_expression2t(code2);
    expr2tc operand = expr.operand;
    dereference(operand, dereferencet::READ);
  }
  else if(is_code_cpp_del_array2t(code2) || is_code_cpp_delete2t(code2))
  {
    expr2tc deref_code(code2);

    replace_dynamic_allocation(deref_code);
    replace_nondet(deref_code);
    dereference(deref_code, dereferencet::READ);

    symex_cpp_delete(deref_code);
  }
  else if(is_code_free2t(code2))
  {
    symex_free(code2);
  }
  else if(is_code_printf2t(code2))
  {
    replace_dynamic_allocation(code2);
    replace_nondet(code2);
    dereference(code2, dereferencet::READ);
    symex_printf(expr2tc(), code2);
  }
  else if(is_code_decl2t(code2))
  {
    replace_dynamic_allocation(code2);
    replace_nondet(code2);
    dereference(code2, dereferencet::READ);

    const code_decl2t &decl_code = to_code_decl2t(code2);

    // just do the L2 renaming to preseve locality
    const irep_idt &identifier = decl_code.value;

    // Generate dummy symbol as a vehicle for renaming.
    symbol2tc l1_sym(get_empty_type(), identifier);

    cur_state->top().level1.get_ident_name(l1_sym);
    symbol2t &l1_symbol = to_symbol2t(l1_sym);

    // increase the frame if we have seen this declaration before
    while(cur_state->top().declaration_history.find(
            renaming::level2t::name_record(l1_symbol)) !=
          cur_state->top().declaration_history.end())
    {
      unsigned &index = cur_state->variable_instance_nums[identifier];
      cur_state->top().level1.rename(l1_sym, ++index);
      l1_symbol.level1_num = index;
    }

    renaming::level2t::name_record tmp_name(l1_symbol);
    cur_state->top().declaration_history.insert(tmp_name);
    cur_state->top().local_variables.insert(tmp_name);

    // seen it before?
    // it should get a fresh value
    if(cur_state->level2.current_number(l1_sym) != 0)
    {
      // Dummy assignment - blank constant value isn't considered for const
      // propagation, variable number will be bumped to result in a new free
      // variable. Invalidates l1_symbol reference?
      cur_state->level2.make_assignment(l1_sym, expr2tc(), expr2tc());
    }
  }
  else if(is_code_asm2t(code2))
  {
    // Assembly statement -> do nothing.
    return;
  }
  else
    throw "goto_symext: unexpected statement: " + get_expr_id(code2);
}
Example #3
0
void
goto_symext::symex_step(reachability_treet & art)
{

  assert(!cur_state->call_stack.empty());

  const goto_programt::instructiont &instruction = *cur_state->source.pc;

  // depth exceeded?
  {
    if (depth_limit != 0 && cur_state->depth > depth_limit)
      cur_state->guard.add(false_expr);
    cur_state->depth++;
  }

  // actually do instruction
  switch (instruction.type) {
  case SKIP:
  case LOCATION:
    // really ignore
    cur_state->source.pc++;
    break;

  case END_FUNCTION:
    symex_end_of_function();

    // Potentially skip to run another function ptr target; if not,
    // continue
    if (!run_next_function_ptr_target(false))
      cur_state->source.pc++;
    break;

  case GOTO:
  {
    expr2tc tmp(instruction.guard);
    replace_nondet(tmp);

    dereference(tmp, false);
    replace_dynamic_allocation(tmp);

    symex_goto(tmp);
  }
  break;

  case ASSUME:
    if (!cur_state->guard.is_false()) {
      expr2tc tmp = instruction.guard;
      replace_nondet(tmp);

      dereference(tmp, false);
      replace_dynamic_allocation(tmp);

      cur_state->rename(tmp);
      do_simplify(tmp);

      if (!is_true(tmp)) {
        expr2tc tmp2 = tmp;
        expr2tc tmp3 = tmp2;
        cur_state->guard.guard_expr(tmp2);

        assume(tmp2);

        // we also add it to the state guard
        cur_state->guard.add(tmp3);
      }
    }
    cur_state->source.pc++;
    break;

  case ASSERT:
    if (!cur_state->guard.is_false()) {
      if (!no_assertions ||
        !cur_state->source.pc->location.user_provided()
        || deadlock_check) {

        std::string msg = cur_state->source.pc->location.comment().as_string();
        if (msg == "") msg = "assertion";

        expr2tc tmp = instruction.guard;
        replace_nondet(tmp);

        dereference(tmp, false);
        replace_dynamic_allocation(tmp);

        claim(tmp, msg);
      }
    }
    cur_state->source.pc++;
    break;

  case RETURN:
    if (!cur_state->guard.is_false()) {
      expr2tc thecode = instruction.code, assign;
      if (make_return_assignment(assign, thecode)) {
        goto_symext::symex_assign(assign);
      }

      symex_return();
    }

    cur_state->source.pc++;
    break;

  case ASSIGN:
    if (!cur_state->guard.is_false()) {
      code_assign2tc deref_code = instruction.code;

      // XXX jmorse -- this is not fully symbolic.
      if (thrown_obj_map.find(cur_state->source.pc) != thrown_obj_map.end()) {
        symbol2tc thrown_obj = thrown_obj_map[cur_state->source.pc];

        if (is_pointer_type(deref_code.get()->target.get()->type)
            && !is_pointer_type(thrown_obj.get()->type))
        {
          expr2tc new_thrown_obj(new address_of2t(thrown_obj.get()->type, thrown_obj));
          deref_code.get()->source = new_thrown_obj;
        }
        else
          deref_code.get()->source = thrown_obj;

        thrown_obj_map.erase(cur_state->source.pc);
      }

      replace_nondet(deref_code);

      code_assign2t &assign = to_code_assign2t(deref_code);

      dereference(assign.target, true);
      dereference(assign.source, false);
      replace_dynamic_allocation(deref_code);

      symex_assign(deref_code);
    }

    cur_state->source.pc++;
    break;

  case FUNCTION_CALL:
  {
    expr2tc deref_code = instruction.code;
    replace_nondet(deref_code);

    code_function_call2t &call = to_code_function_call2t(deref_code);

    if (!is_nil_expr(call.ret)) {
      dereference(call.ret, true);
    }

    replace_dynamic_allocation(deref_code);

    for (std::vector<expr2tc>::iterator it = call.operands.begin();
         it != call.operands.end(); it++)
      if (!is_nil_expr(*it))
        dereference(*it, false);

    // Always run intrinsics, whether guard is false or not. This is due to the
    // unfortunate circumstance where a thread starts with false guard due to
    // decision taken in another thread in this trace. In that case the
    // terminate intrinsic _has_ to run, or we explode.
    if (is_symbol2t(call.function)) {
      const irep_idt &id = to_symbol2t(call.function).thename;
      if (has_prefix(id.as_string(), "c::__ESBMC")) {
        cur_state->source.pc++;
        std::string name = id.as_string().substr(3);
        run_intrinsic(call, art, name);
        return;
      } else if (has_prefix(id.as_string(), "cpp::__ESBMC")) {
        cur_state->source.pc++;
        std::string name = id.as_string().substr(5);
        name = name.substr(0, name.find("("));
        run_intrinsic(call, art, name);
        return;
      }
    }

    // Don't run a function call if the guard is false.
    if (!cur_state->guard.is_false()) {
      symex_function_call(deref_code);
    } else {
      cur_state->source.pc++;
    }
  }
  break;

  case OTHER:
    if (!cur_state->guard.is_false()) {
      symex_other();
    }
    cur_state->source.pc++;
    break;

  case CATCH:
    symex_catch();
    break;

  case THROW:
    if (!cur_state->guard.is_false()) {
      if(symex_throw())
        cur_state->source.pc++;
    } else {
      cur_state->source.pc++;
    }
    break;

  case THROW_DECL:
    symex_throw_decl();
    cur_state->source.pc++;
    break;

  case THROW_DECL_END:
    // When we reach THROW_DECL_END, we must clear any throw_decl
    if(stack_catch.size())
    {
      // Get to the correct try (always the last one)
      goto_symex_statet::exceptiont* except=&stack_catch.top();

      except->has_throw_decl=false;
      except->throw_list_set.clear();
    }

    cur_state->source.pc++;
    break;

  default:
    std::cerr << "GOTO instruction type " << instruction.type;
    std::cerr << " not handled in goto_symext::symex_step" << std::endl;
    abort();
  }
}