//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.listener;
import java.util.ArrayList;
import java.util.HashSet;
import gov.nasa.jpf.Config;
import gov.nasa.jpf.PropertyListenerAdapter;
import gov.nasa.jpf.search.Search;
import gov.nasa.jpf.vm.SystemState;
import gov.nasa.jpf.vm.VM;
/**
* If there is a cycle in the states of the program, JPF doesn't execute the
* already visited states. A cycle in the states may represent the ability for
* the program to hang. This property finds and outputs cycles in the states
* so that they may be investigated.
*
* The following might need to be added to listener property...
* gov.nasa.jpf.tools.SimpleIdleFilter
* gov.nasa.jpf.tools.IdleFilter
*/
public class NoStateCycles extends PropertyListenerAdapter {
private final HashSet<Integer> m_inStack = new HashSet<Integer>();
private final ArrayList<Integer> m_stack = new ArrayList<Integer>();
private int m_cycleFound = -1;
private int m_stackPos = -1;
public NoStateCycles(Config config) {
if (!config.getString("search.class").equals("gov.nasa.jpf.search.DFSearch"))
config.throwException("search.class must be gov.nasa.jpf.search.DFSearch"); // Or any class which does a depth first search.
}
@Override
public void stateAdvanced(Search search) {
SystemState state;
Integer id;
state = search.getVM().getSystemState();
if (state.isInitState())
return;
id = state.getId();
if ((m_stackPos < 0) && (m_inStack.contains(id))) {
m_cycleFound = id;
for (m_stackPos = m_stack.size() - 1; m_stackPos >= 0; m_stackPos--)
if (m_stack.get(m_stackPos).equals(id))
break;
}
m_stack.add(id);
m_inStack.add(id);
}
@Override
public void stateBacktracked(Search search) {
Integer id;
int pos;
pos = m_stack.size() - 1;
id = m_stack.remove(pos);
m_inStack.remove(id);
if (m_stackPos >= pos)
m_stackPos = -1;
}
@Override
public boolean check(Search search, VM vm) {
return(m_cycleFound < 0);
}
@Override
public void reset () {
m_cycleFound = -1;
}
public String getErrorMessage () {
StringBuilder result;
int i, id;
result = new StringBuilder();
result.append("States:\n");
for (i = m_stack.size() - 1; i >= 0; i--) {
id = m_stack.get(i);
result.append(" ");
result.append(id);
result.append('\n');
if (id == m_cycleFound)
break;
}
return(result.toString());
}
public String getExplanation () {
return("Finds cycles in states. A cycle suggests that the program might be able to hang.");
}
}