Ejemplo n.º 1
0
path_searcht::resultt path_searcht::operator()(
  const goto_functionst &goto_functions)
{
#ifdef PATH_SYMEX_FORK
  // Disable output because there is no meaningful way
  // to write text when multiple path_search processes
  // run concurrently. This could be remedied by piping
  // to individual files or inter-process communication,
  // a performance bottleneck, however.
  *messaget::mstream.message_handler=NULL;
#endif

  locst locs(ns);
  var_mapt var_map(ns);
  
  locs.build(goto_functions);

  // this is the container for the history-forest  
  path_symex_historyt history;
  
  queue.push_back(initial_state(var_map, locs, history));
  
  // set up the statistics
  number_of_paths=0;
  number_of_instructions=0;
  number_of_dropped_states=0;
  number_of_VCCs=0;
  number_of_VCCs_after_simplification=0;
  number_of_failed_properties=0;
  number_of_fast_forward_steps=0;

  // stop the time
  start_time=current_time();
  
  initialize_property_map(goto_functions);
  
  while(!queue.empty())
  {
    // Pick a state from the queue,
    // according to some heuristic.
    queuet::iterator state=pick_state();

    // fast forwarding required?
    if(state->is_lazy())
    {
      assert(state->is_executable());
      assert(state->history.is_nil());

      // keep allocated memory, this is faster than
      // instantiating a new empty vector and map
      history.clear();
      var_map.clear();
      state->history=path_symex_step_reft(history);

      // restore all fields of a lazy state by symbolic
      // execution along previously recorded branches
      const queuet::size_type queue_size=queue.size();
      do
      {
        number_of_fast_forward_steps++;

        path_symex(*state, queue);
#ifdef PATH_SYMEX_OUTPUT
        status() << "Fast forward thread " << state->get_current_thread()
                 << "/" << state->threads.size()
                 << " PC " << state->pc() << messaget::eom;
#endif
      }
      while(state->is_lazy() && state->is_executable());
      assert(queue.size() == queue_size);
    }
    
    // TODO: check lazy states before fast forwarding, or perhaps it
    // is better to even check before inserting into queue
    if(drop_state(*state))
    {
      number_of_dropped_states++;
      queue.erase(state);
      continue;
    }
    
    if(!state->is_executable())
    {
      queue.erase(state);
      continue;
    }
    
    // count only executable instructions
    number_of_instructions++;

#ifdef PATH_SYMEX_OUTPUT
    status() << "Queue " << queue.size()
             << " thread " << state->get_current_thread()
             << "/" << state->threads.size()
             << " PC " << state->pc() << messaget::eom;
#endif

    // an error, possibly?
    if(state->get_instruction()->is_assert())
    {
      if(show_vcc)
        do_show_vcc(*state, ns);
      else
      {
        check_assertion(*state, ns);
        
        // all assertions failed?
        if(number_of_failed_properties==property_map.size())
          break;
      }
    }

#ifdef PATH_SYMEX_FORK
    if(try_await())
    {
      debug() << "Child process has terminated "
                 "so exit parent" << messaget::eom;
      break;
    }
#endif

    // execute and record whether a "branch" occurred
    const queuet::size_type queue_size = queue.size();
    path_symex(*state, queue);

    assert(queue_size <= queue.size());
    number_of_paths += (queue.size() - queue_size);
  }

#ifdef PATH_SYMEX_FORK
  int exit_status=await();
  if(exit_status==0 && number_of_failed_properties!=0)
  {
    // the eldest child process (if any) reports found bugs
    report_statistics();
    return UNSAFE;
  }
  else
  {
    // either a child found and reported a bug or
    // the parent's search partition is safe
    switch (exit_status)
    {
    case 0: return SAFE;
    case 10: return UNSAFE;
    default: return ERROR;
    }
  }
#else
  report_statistics();

  return number_of_failed_properties==0?SAFE:UNSAFE;
#endif
}
Ejemplo n.º 2
0
path_searcht::resultt path_searcht::operator()(
  const goto_functionst &goto_functions)
{
  locst locs(ns);
  var_mapt var_map(ns);
  
  locs.build(goto_functions);

  // this is the container for the history-forest  
  path_symex_historyt history;
  
  queue.push_back(initial_state(var_map, locs, history));
  
  // set up the statistics
  number_of_dropped_states=0;
  number_of_paths=0;
  number_of_VCCs=0;
  number_of_steps=0;
  number_of_feasible_paths=0;
  number_of_infeasible_paths=0;
  number_of_VCCs_after_simplification=0;
  number_of_failed_properties=0;
  number_of_locs=locs.size();

  // stop the time
  start_time=current_time();
  
  initialize_property_map(goto_functions);
  
  while(!queue.empty())
  {
    number_of_steps++;
  
    // Pick a state from the queue,
    // according to some heuristic.
    // The state moves to the head of the queue.
    pick_state();
    
    // move into temporary queue
    queuet tmp_queue;
    tmp_queue.splice(
      tmp_queue.begin(), queue, queue.begin(), ++queue.begin());
    
    try
    {
      statet &state=tmp_queue.front();
      
      // record we have seen it
      loc_data[state.get_pc().loc_number].visited=true;

      debug() << "Loc: #" << state.get_pc().loc_number
              << ", queue: " << queue.size()
              << ", depth: " << state.get_depth();
      for(const auto & s : queue)
        debug() << ' ' << s.get_depth();
        
      debug() << eom;
    
      if(drop_state(state))
      {
        number_of_dropped_states++;
        number_of_paths++;
        continue;
      }
      
      if(!state.is_executable())
      {
        number_of_paths++;
        continue;
      }

      if(eager_infeasibility &&
         state.last_was_branch() &&
         !is_feasible(state))
      {
        number_of_infeasible_paths++;
        number_of_paths++;
        continue;
      }
      
      if(number_of_steps%1000==0)
      {
        status() << "Queue " << queue.size()
                 << " thread " << state.get_current_thread()
                 << '/' << state.threads.size()
                 << " PC " << state.pc() << messaget::eom;
      }

      // an error, possibly?
      if(state.get_instruction()->is_assert())
      {
        if(show_vcc)
          do_show_vcc(state);
        else
        {
          check_assertion(state);
          
          // all assertions failed?
          if(number_of_failed_properties==property_map.size())
            break;
        }
      }

      // execute
      path_symex(state, tmp_queue);
      
      // put at head of main queue
      queue.splice(queue.begin(), tmp_queue);
    }
    catch(const std::string &e)
    {
      error() << e << eom;
      number_of_dropped_states++;
    }
    catch(const char *e)
    {
      error() << e << eom;
      number_of_dropped_states++;
    }
    catch(int)
    {
      number_of_dropped_states++;
    }
  }
  
  report_statistics();
  
  return number_of_failed_properties==0?SAFE:UNSAFE;
}