Package dk.brics.jwig.analysis.jaive

Source Code of dk.brics.jwig.analysis.jaive.FormChecker

package dk.brics.jwig.analysis.jaive;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.log4j.Logger;

import soot.Body;
import soot.RefType;
import soot.SootClass;
import soot.SootMethod;
import soot.Type;
import soot.Unit;
import soot.ValueBox;
import soot.jimple.AssignStmt;
import soot.jimple.ReturnStmt;
import soot.jimple.Stmt;
import dk.brics.jwig.WebContext;
import dk.brics.jwig.WebSite;
import dk.brics.jwig.analysis.JwigResolver;
import dk.brics.jwig.analysis.graph.HandlerState;
import dk.brics.jwig.analysis.graph.State;
import dk.brics.jwig.analysis.graph.StateMachine;
import dk.brics.jwig.analysis.graph.StateMachine.MethodStatementContainer;
import dk.brics.jwig.analysis.graph.WebMethodState;
import dk.brics.jwig.analysis.jaive.feedback.SourceUtil;
import dk.brics.xact.XML;
import dk.brics.xact.analysis.XMLAnalysis;
import dk.brics.xact.analysis.config.StandardConfiguration;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
import dk.brics.xact.analysis.flowgraph.statements.AnalyzeStm;
import dk.brics.xact.analysis.soot.TranslationResult;
import dk.brics.xact.analysis.xmlgraph.XMLGraphBuilder;
import dk.brics.xmlgraph.ChoiceNode;
import dk.brics.xmlgraph.ElementNode;
import dk.brics.xmlgraph.Node;
import dk.brics.xmlgraph.NodeProcessor;
import dk.brics.xmlgraph.XMLGraph;
import dk.brics.xmlgraph.converter.XMLGraph2Dot;

public class FormChecker {

    public static class JWIGConfiguration extends StandardConfiguration {
        private final Set<ValueBox> hotspots;

        public JWIGConfiguration(Collection<ValueBox> collection) {
            super();
            this.hotspots = new HashSet<ValueBox>(collection);
        }

        @Override
        public Set<ValueBox> getHotspots() {
            return hotspots;
        }

    }

    private static final Logger log = Logger.getLogger(FormChecker.class);

    private final StateMachine machine;

    private final JwigResolver resolver;

    private final Map<ReturnStmt, MethodStatementContainer> returnLocations;

    public FormChecker(StateMachine machine) {
        this.machine = machine;
        resolver = JwigResolver.get();
        returnLocations = new HashMap<ReturnStmt, StateMachine.MethodStatementContainer>();
    }

    public void checkForms() {
        log.info("Checking forms");
        final Collection<Plugging> pluggings = machine.getPluggings();
        Set<SootMethod> xmlReturners = findXMLReturners();
        Map<Stmt, ValueBox> stmt2box = markAnalysisStatements(pluggings,
                xmlReturners);
        List<String> classes = markAnalysisClasses(pluggings, xmlReturners);

        //
        // run xact//
        //
        log.info("Starting xact analysis");
        // non constant gap names has been reported already - no need to crash
        // and burn on them
        System.setProperty("dk.brics.xact.analysis.ignore-non-constant-string",
                true + "");
        XMLAnalysis analysis = new XMLAnalysis(null, classes);
        analysis.loadClasses();
        analysis.setConfiguration(new JWIGConfiguration(stmt2box.values()));
        TranslationResult result = analysis.buildFlowGraph();

        analysis.transformFlowGraph(result.getGraph());

        final FlowGraph graph = result.getGraph();
        XMLGraphBuilder xmlGraphs = analysis.buildXMLGraphs(graph);
        log.info("xact analysis done");

        Map<ChoiceNode, Set<Plugging>> gap2plug = linkGapsToPluggings(
                pluggings, stmt2box, result, xmlGraphs);

        Map<ReturnStmt, XMLGraph> ret2xg = linkReturnsToGraphs(stmt2box,
                result, xmlGraphs);

        Map<ChoiceNode, Set<ElementNode>> shGap2form = linkFormsAndSubmitHandlers(
                gap2plug, ret2xg);

        System.out.println("FORM GAPS");
        for (Entry<ChoiceNode, Set<ElementNode>> entry : shGap2form.entrySet()) {
            System.out.println(entry.toString());
        }
        // find submithandler run method (if it exists, if not: ignore as an
        // errorneous SH has been reported already) (if Parameters used: ignore)

        // find input names

        // match with runmethod

        // (find input types(!), match with runmethod)
        log.info("Done checking forms");
    }

    private boolean couldBeSubmitHandler(Set<Plugging> pluggings) {
        for (Plugging plugging : pluggings) {
            Set<Type> types = plugging.getTypes();
            for (Type type : types) {
                if (resolver.couldBeSubmitHandler(type))
                    return true;
            }
        }
        return false;
    }

    List<String> markAnalysisClasses(final Collection<Plugging> pluggings,
            Set<SootMethod> xmlReturners) {
        List<String> classNames = new ArrayList<String>();
        Set<SootClass> classes = new HashSet<SootClass>();
        for (Plugging plugging : pluggings) {
            classes.add(plugging.getContainer().getMethod().getDeclaringClass());
        }
        for (SootMethod xmlReturningMethod : xmlReturners) {
            classes.add(xmlReturningMethod.getDeclaringClass());
        }
        // FIXME these arent automatically added to the classes despite having
        // plug/makeURL entries!?
        classes.add(resolver.getSootClass(WebContext.class));
        classes.add(resolver.getSootClass(WebSite.class));

        for (SootClass clazz : classes) {
            final String name = clazz.getJavaStyleName();
            if (name == null) {
                throw new RuntimeException("javastylename is null for class: "
                        + clazz);
            }
            classNames.add(name);
        }

        return classNames;
    }

    Map<Stmt, ValueBox> markAnalysisStatements(
            final Collection<Plugging> pluggings, Set<SootMethod> xmlReturners) {
        Map<Stmt, ValueBox> stmt2box = new HashMap<Stmt, ValueBox>();
        // add the return statements of the xml returning
        // methods to the
        // analysis

        for (SootMethod method : xmlReturners) {
            Body body = method.retrieveActiveBody();
            for (Unit unit : body.getUnits()) {
                if (unit instanceof ReturnStmt) {
                    ReturnStmt stmt = (ReturnStmt) unit;
                    final ValueBox box = stmt.getOpBox();
                    returnLocations.put(stmt, new MethodStatementContainer(
                            method, stmt));
                    stmt2box.put(stmt, box);
                }
            }
        }

        // add the plug statements
        for (Plugging plugging : pluggings) {
            final AssignStmt stmt = plugging.getStmt();
            final ValueBox box = stmt.getInvokeExprBox();
            stmt2box.put(stmt, box);
        }
        return stmt2box;
    }

    Set<SootMethod> findXMLReturners() {
        // find webmethods / handler run methods which return XML
        Set<SootMethod> xmlReturners = new HashSet<SootMethod>();
        Set<State> allStates = machine.getAllStates();
        final SootClass xml = resolver.getSootClass(XML.class);
        for (State state : allStates) {
            if (state instanceof WebMethodState
                    || state instanceof HandlerState) {
                final SootMethod method = state.getMethod();
                final Type returnType = method.getReturnType();
                // TODO explicitly checking for the XML type. XML content
                // should be checked too perhaps?
                if (returnType instanceof RefType
                        && resolver.is(((RefType) returnType).getSootClass(),
                                xml))
                    xmlReturners.add(method);
            }
        }
        return xmlReturners;
    }

    private Set<ElementNode> getEnclosingForms(ChoiceNode gap,
            Plugging plugging, Map<ReturnStmt, XMLGraph> ret2xg) {
        // TODO optimize (greatly!) by only considering the WebMethods and
        // SubmitHandler-runmethods which can reach this plugging

        Set<ElementNode> forms = new HashSet<ElementNode>();
        for (XMLGraph xg : ret2xg.values()) {
            NodeProcessor<Set<ElementNode>> isInFormActionChecker = new IsInFormActionChecker(
                    xg);
            Node node = xg.getNode(gap.getIndex());
            final Set<ElementNode> parentForms = node
                    .process(isInFormActionChecker);
            forms.addAll(parentForms);
        }
        return forms;
    }

    private Map<ChoiceNode, Set<ElementNode>> linkFormsAndSubmitHandlers(
            Map<ChoiceNode, Set<Plugging>> gap2plug,
            Map<ReturnStmt, XMLGraph> ret2xg) {
        // find submithandler pluggings forms (<form action=SH>...)
        Map<ChoiceNode, Set<ElementNode>> shGap2form = new HashMap<ChoiceNode, Set<ElementNode>>();
        for (Entry<ChoiceNode, Set<Plugging>> entry : gap2plug.entrySet()) {
            ChoiceNode gap = entry.getKey();
            Set<Plugging> plugValues = entry.getValue();
            // only check possible submithandlers
            if (couldBeSubmitHandler(plugValues)) {
                for (Plugging plugging : plugValues) {
                    Set<ElementNode> forms = getEnclosingForms(gap, plugging,
                            ret2xg);
                    if (!forms.isEmpty())
                        shGap2form.put(gap, forms);
                }
            }

        }
        return shGap2form;
    }

    private Map<ChoiceNode, Set<Plugging>> linkGapsToPluggings(
            final Collection<Plugging> pluggings, Map<Stmt, ValueBox> stmt2box,
            TranslationResult result, XMLGraphBuilder xmlGraphs) {
        // link xml gaps to their plug values
        Map<ChoiceNode, Set<Plugging>> gap2plug = new HashMap<ChoiceNode, Set<Plugging>>();
        for (Plugging plugging : pluggings) {
            final AssignStmt statement = plugging.getStmt();
            AnalyzeStm analyzeStm = result.getHotspots().get(
                    stmt2box.get(statement));
            if (analyzeStm != null) {
                XMLGraph xg = xmlGraphs.getIn(analyzeStm, analyzeStm.getBase());
                final GapFinderByName gapFinder = new GapFinderByName(
                        plugging.getNames());
                log.debug("looking for gaps with the name: "
                        + plugging.getNames().getFiniteStrings());
                log.debug("the xml graph is known to have the following gaps:");

                if (getGapNames(xg).isEmpty()) {
                    System.out.println("empty gaps for: "
                            + SourceUtil.getLocation(plugging.getContainer()
                                    .getMethod(), plugging.getContainer()
                                    .getStatement()));
                    new XMLGraph2Dot(new PrintWriter(System.out)).print(xg);
                }
                xg.processNodes(gapFinder);
                for (ChoiceNode gap : gapFinder.getGaps()) {
                    if (!gap2plug.containsKey(gap))
                        gap2plug.put(gap, new HashSet<Plugging>());
                    gap2plug.get(gap).add(plugging);
                }
            } else
                log.error("analyzeStmt is null for: " + statement
                        + " associated with " + stmt2box.get(statement));
        }
        return gap2plug;
    }

    private Set<String> getGapNames(XMLGraph xg) {
        Set<String> closedAttributeGaps = xg.getClosedAttributeGaps();
        Set<String> openAttributeGaps = xg.getOpenAttributeGaps();
        Set<String> closedTemplateGaps = xg.getClosedTemplateGaps();
        Set<String> openTemplateGaps = xg.getOpenTemplateGaps();
        Set<String> names = new HashSet<String>();
        names.addAll(closedTemplateGaps);
        names.addAll(closedAttributeGaps);
        names.addAll(openAttributeGaps);
        names.addAll(openTemplateGaps);
        return names;
    }

    private Map<ReturnStmt, XMLGraph> linkReturnsToGraphs(
            Map<Stmt, ValueBox> stmt2box, TranslationResult result,
            XMLGraphBuilder xmlGraphs) {
        // link return values to their xmlgraphs
        Map<ReturnStmt, XMLGraph> ret2xg = new HashMap<ReturnStmt, XMLGraph>();
        for (Stmt stmt : stmt2box.keySet()) {
            if (!(stmt instanceof ReturnStmt)) // ignore plugs
                continue;

            ReturnStmt returnStmt = (ReturnStmt) stmt;

            AnalyzeStm analyzeStm = result.getHotspots().get(
                    stmt2box.get(returnStmt));
            if (analyzeStm == null) {
                final MethodStatementContainer container = returnLocations
                        .get(returnStmt);
                System.err.println(returnStmt
                        + " -- "
                        + stmt2box.get(returnStmt)
                        + " @ "
                        + SourceUtil.getLocation(container.getMethod(),
                                container.getStatement())
                        + " --> null analyzestmt");
            } else {
                XMLGraph xg = xmlGraphs.getIn(analyzeStm, analyzeStm.getBase());
                new XMLGraph2Dot(new PrintWriter(System.out)).print(xg);
                ret2xg.put(returnStmt, xg);
            }
        }
        return ret2xg;
    }
}
TOP

Related Classes of dk.brics.jwig.analysis.jaive.FormChecker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.