/* * Copyright 2008 Wishnu Prasetya. * * This file is part of T2. * T2 is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License (GPL) as published by the * Free Software Foundation; either version 3 of the License, or any * later version. * * T2 is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * A copy of the GNU General Public License can be found in T2 distribution. * If it is missing, see http://www.gnu.org/licenses. */ package t2ext.trace; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Random; import t2ext.trace.utils.TraceAnalysis; import t2ext.trace.utils.TraceStepAnalysis; import t2ext.util.Util; import Sequenic.T2.Engines.BaseEngine; import Sequenic.T2.Seq.CALL_METHOD; import Sequenic.T2.Seq.ExecResult; import Sequenic.T2.Seq.MkValStep; import Sequenic.T2.Seq.REF; import Sequenic.T2.Seq.Trace; import Sequenic.T2.Seq.TraceSetExecInfo; import Sequenic.T2.Seq.TraceStep; import Sequenic.T2.Seq.UPDATE_FIELD; /** * @author Maaike Gerritsen */ public class TraceModifier { private BaseEngine _baseEngine; private LinkedList _faultyTraces; private boolean _faultyFieldUpdate; private LinkedList _traceSteps; public TraceModifier(BaseEngine baseEngine) { _baseEngine = baseEngine; _faultyTraces = new LinkedList(); } public LinkedList getFaultyTraces(){ return _faultyTraces; } public void modifyAndExecuteTraceChangingCurrentMethodParams( TraceAnalysis traceAnalysis, String methodName) { Trace trace = traceAnalysis.getTrace(); TraceSetExecInfo info = new TraceSetExecInfo(); info.time = System.currentTimeMillis(); int counter = 0; boolean faulty = false; boolean faultyAux = false; _traceSteps = new LinkedList(); for (Iterator iterator = traceAnalysis.getSteps() .iterator(); iterator.hasNext();) { TraceStepAnalysis tsa = iterator.next(); if (tsa.isCallMethod() && tsa.getMethodName().equals(methodName)){ faultyAux = modifyAndExecuteStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } else{ faultyAux = executeStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } } if(faulty){ trace.trace = _traceSteps; _faultyTraces.add(trace); } } public void modifyAndExecuteTraceChangingCurrentMethodParamsForBestID( TraceAnalysis traceAnalysis, Integer bestPathId, String methodName, boolean checkSpec, Integer pathToFind) { Trace trace = traceAnalysis.getTrace(); TraceSetExecInfo info = new TraceSetExecInfo(); info.time = System.currentTimeMillis(); int counter = 0; _traceSteps = new LinkedList(); boolean faulty = false; boolean faultyAux = false; for (Iterator iterator = traceAnalysis.getSteps() .iterator(); iterator.hasNext();) { TraceStepAnalysis tsa = iterator.next(); boolean found = false; if (checkSpec) found = tsa.getSpecPathIds().contains(bestPathId); else found = tsa.getPathIds().contains(bestPathId); if (tsa.isCallMethod() && tsa.getMethodName().equals(methodName) && found) { faultyAux = modifyAndExecuteStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } else { // execute normal step without changes faultyAux = executeStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } counter++; } if(faulty){ trace.trace = _traceSteps; _faultyTraces.add(trace); } } public void modifyAndExecCompleteTrace(TraceAnalysis traceAnalysis) { Trace trace = traceAnalysis.getTrace(); int counter = 0; _traceSteps = new LinkedList(); boolean faulty = false; boolean faultyAux = false; for (Iterator iterator = traceAnalysis.getSteps() .iterator(); iterator.hasNext();) { TraceStepAnalysis tsa = iterator.next(); if (tsa.isCallMethod()){ faultyAux = modifyAndExecuteStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } else { // execute a field update, we do not want to change this yet, // because it changes the state of the target object faultyAux = executeStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } counter++; } if(faulty){ trace.trace = _traceSteps; _faultyTraces.add(trace); } } private boolean executeStep(TraceStepAnalysis tsa, Trace trace, int counter) { TraceStep step = tsa.getTraceStep(); ExecResult stepResult = step.exec(_baseEngine.CUT, tsa.getPool(), tsa .getTargetObject(), counter, _baseEngine.allClassINVs); if (stepResult.isAsmOrReqViolating()){ printViolatingTrace(); return true; } _traceSteps.add(step); return false; } private T getRndElem(Random rnd, List s) { if (s.isEmpty()) { return null; } else { return s.get(rnd.nextInt(s.size())); } } @SuppressWarnings("unchecked") private boolean modifyAndExecuteStep(TraceStepAnalysis tsa, Trace trace, int counter) { Random rnd = _baseEngine.rnd; int whichParam = -1; Class[] paramTypes = tsa.getMethod().getParameterTypes(); LinkedList possiblePlaces = new LinkedList(); for (int i = 0; i < paramTypes.length; i++) { if (paramTypes[i].isAssignableFrom(_baseEngine.CUT)) { possiblePlaces.add(i); } } if (!possiblePlaces.isEmpty()) whichParam = getRndElem(rnd, possiblePlaces); MkValStep[] params = new MkValStep[paramTypes.length]; for (int i = 0; i < params.length; i++) { if (i == whichParam) { params[i] = new REF(trace.indexOfTargetObj); } else { params[i] = _baseEngine.META_mkObject(paramTypes[i], 1, true); } } TraceStep step = null; MkValStep receiver = null; if (whichParam < 0) { receiver = new REF(trace.indexOfTargetObj); } else { receiver = _baseEngine.META_mkObject(tsa.getMethod() .getDeclaringClass(), 0, false); } if (Modifier.isStatic(tsa.getMethod().getModifiers())) step = new CALL_METHOD(tsa.getMethod(), null, params); else step = new CALL_METHOD(tsa.getMethod(), receiver, params); ExecResult stepResult = step.exec(_baseEngine.CUT, tsa.getPool(), tsa .getTargetObject(), counter, _baseEngine.allClassINVs); if (stepResult.isAsmOrReqViolating()){ printViolatingTrace(); return true; } _traceSteps.add(step); return false; } private void printViolatingTrace() { StringBuffer buffer = new StringBuffer(); buffer.append("++++++++++++++++++++++++++++++++++++++++++++++++++ \n"); buffer.append("A violating trace was found! \n"); buffer.append("Rerun T2 with the --regress option to see a full report \n"); buffer.append("++++++++++++++++++++++++++++++++++++++++++++++++++ \n"); System.out.println(buffer.toString()); } public void modifyTraceWithFieldUpdates(TraceAnalysis traceAnalysis, String name) { Trace trace = traceAnalysis.getTrace(); TraceSetExecInfo info = new TraceSetExecInfo(); info.time = System.currentTimeMillis(); int counter = 0; _traceSteps = new LinkedList(); boolean faulty = false; boolean faultyAux = false; for (Iterator iterator = traceAnalysis.getSteps() .iterator(); iterator.hasNext();) { TraceStepAnalysis tsa = iterator.next(); if (tsa.isCallMethod() && tsa.getMethodName().equals(name)) { if (tsa.getFields().size() < traceAnalysis.getFields().size()) { counter = updateFieldsAndExecStep(traceAnalysis, tsa, counter); if(_faultyFieldUpdate) faulty = true; } else{ faultyAux = executeStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } } else{ faultyAux = executeStep(tsa, trace, counter); if(faultyAux && !faulty) faulty = true; } counter++; } if(faulty){ trace.trace = _traceSteps; _faultyTraces.add(trace); } } private int updateFieldsAndExecStep(TraceAnalysis traceAnalysis, TraceStepAnalysis tsa, int counter) { _faultyFieldUpdate = false; for (Iterator iterator = traceAnalysis.getFields().iterator(); iterator .hasNext();) { Field field = iterator.next(); if (!tsa.getFields().contains(field)) { UPDATE_FIELD updateField = new UPDATE_FIELD(field, _baseEngine .META_mkObject(field.getType(), 0, true)); ExecResult stepResult = updateField.exec(_baseEngine.CUT, tsa.getPool(), tsa .getTargetObject(), counter, _baseEngine.allClassINVs); if (stepResult.isAsmOrReqViolating()){ printViolatingTrace(); _faultyFieldUpdate = true; } _traceSteps.add(updateField); counter++; } } boolean faultyAux = executeStep(tsa, traceAnalysis.getTrace(), counter+1); if(faultyAux && !_faultyFieldUpdate) _faultyFieldUpdate = true; return counter; } }