org.sosy_lab.cpachecker.util.cwriter.PathToCWithLoopsTranslator.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.util.cwriter.PathToCWithLoopsTranslator.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2015  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 *  CPAchecker web page:
 *    http://cpachecker.sosy-lab.org
 */
package org.sosy_lab.cpachecker.util.cwriter;

import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.FluentIterable.from;
import static java.util.Collections.singletonList;
import static org.sosy_lab.common.Appenders.concat;
import static org.sosy_lab.common.Appenders.forIterable;
import static org.sosy_lab.cpachecker.util.cwriter.LoopCollectingEdgeVisitor.getLoopsOfNode;

import com.google.common.base.Joiner;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;

import org.sosy_lab.common.Appender;
import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.cpachecker.cfa.CFA;
import org.sosy_lab.cpachecker.cfa.model.AReturnStatementEdge;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.cfa.model.FunctionCallEdge;
import org.sosy_lab.cpachecker.cfa.model.FunctionEntryNode;
import org.sosy_lab.cpachecker.cfa.model.c.CAssumeEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CFunctionCallEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CFunctionEntryNode;
import org.sosy_lab.cpachecker.cfa.model.c.CFunctionReturnEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CFunctionSummaryEdge;
import org.sosy_lab.cpachecker.cpa.arg.ARGPath;
import org.sosy_lab.cpachecker.cpa.arg.ARGState;
import org.sosy_lab.cpachecker.util.CFATraversal;
import org.sosy_lab.cpachecker.util.CFAUtils;
import org.sosy_lab.cpachecker.util.LoopStructure;
import org.sosy_lab.cpachecker.util.LoopStructure.Loop;
import org.sosy_lab.cpachecker.util.Pair;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Pattern;

/**
 * This class translates a given ARGpath into c-code. The created code consists
 * partly of unrolled parts of the usual program and recreated / uprolled parts
 * of the given ARG.
 * Therefore this translator is a mix of the code generated by the RealCTranslator
 * and the real program (there may be additional temporary variables, and also
 * some functions / variables may be called different)
 */
public class PathToCWithLoopsTranslator extends PathTranslator {

    private static final Pattern uniqueFunction = Pattern.compile(".*_[0-9]+(.*)");

    private final LoopStructure loopStructure;
    private final Map<Loop, Set<ARGState>> loopsInPathToRecreate;
    private Deque<String> callStack = new ArrayDeque<>();
    private Map<String, Pair<CFunctionEntryNode, FunctionBody>> nonUniqueFunctions = new HashMap<>();
    private int labelCounter = 0;

    // all necessary stacks / queues / maps for recreatig loops and functions
    private Map<Loop, String> loopInLabels = new HashMap<>();
    private Map<Loop, CFANode> loopToHead = new HashMap<>();
    private Map<Loop, String> loopOutLabels = new HashMap<>();
    private Set<CFAEdge> handledEdges = new HashSet<>();
    private Set<String> handledFunctions = new HashSet<>();
    private Map<CFAEdge, String> ifOutLabels = new HashMap<>();
    private Deque<Map<CFANode, String>> ifOutLabelEnd = new ArrayDeque<>();
    private Set<CFANode> ifThenHandled = new HashSet<>();
    private Map<CFAEdge, String> ifElseLabels = new HashMap<>();

    private String currentFunctionName = "";

    private PathToCWithLoopsTranslator(CFA pCFA, Map<Loop, Set<ARGState>> pLoopsInPathToRecreate) {
        this.loopStructure = pCFA.getLoopStructure().get();
        this.loopsInPathToRecreate = pLoopsInPathToRecreate;
    }

    /**
     * Transform a single linear path into C code.
     * The path needs to be loop free.
     *
     * TODO: implement the proper handling of labels/gotos, currently the created
     *       code is not correct in all cases when gotos are used.
     *
     * TODO: Detect loops in the paths and signal an error.
     * Currently when there are loops, the generated C code is invalid
     * because there is a goto to a missing label.
     *
     * @param pPath The path.
     * @return An appender that generates C code.
     */
    public static Appender translateSinglePath(ARGPath pPath, CFA cfa, Configuration config)
            throws InvalidConfigurationException {
        PathToCTranslator translator = new PathToCTranslator();

        // at first we fetch all loops that we want to uproll
        LoopCollectingEdgeVisitor loopCollectingVisitor = new LoopCollectingEdgeVisitor(
                cfa.getLoopStructure().get(), config);
        translator.translateSinglePath0(pPath, loopCollectingVisitor);
        Map<Loop, Set<ARGState>> loopsInPathToRecreate = loopCollectingVisitor.getRelevantLoops();

        // new translator, now for creating the c-code
        PathToCWithLoopsTranslator loopTranslator = new PathToCWithLoopsTranslator(cfa, loopsInPathToRecreate);
        loopTranslator.translateSinglePath0(pPath, new DefaultEdgeVisitor(loopTranslator));

        return loopTranslator.generateCCode();
    }

    @Override
    protected Appender generateCCode() {
        // proper order and c-code without warnings
        mGlobalDefinitionsList.add(0, "#include <stdlib.h>\n");
        mGlobalDefinitionsList.add(1, "#include <time.h>\n");
        mGlobalDefinitionsList.add(2, "#define __VERIFIER_nondet_int() rand()");

        mGlobalDefinitionsList.remove("int __VERIFIER_nondet_int()");

        mFunctionDecls.add("int main() {\n  srand(time(NULL));\n  return main_0();\n}");

        // now create the usual program without the non-unique functions
        Appender app = super.generateCCode();

        // and generate the non-unique functions here
        return createNonUniqueFunctions(app);
    }

    private Appender createNonUniqueFunctions(Appender app) {
        List<FunctionBody> finishedBodies = new ArrayList<>();
        for (Pair<CFunctionEntryNode, FunctionBody> p : nonUniqueFunctions.values()) {
            FunctionBody body = p.getSecond();
            body.write(recreateFunction(p.getFirst(), p.getFirst(), p.getFirst().getExitNode(),
                    body.getCurrentBlock()));
            finishedBodies.add(body);
        }
        return concat(app, forIterable(Joiner.on('\n'), finishedBodies));
    }

    @Override
    protected String startFunction(final ARGState firstFunctionElement, Stack<FunctionBody> functionStack,
            final CFANode predecessor) {
        // create the first stack element using the first element of the function
        CFunctionEntryNode functionStartNode = extractFunctionCallLocation(firstFunctionElement);
        String functionName = functionStartNode.getFunctionName();

        // only use a unique name where we are not inside a relevant loop
        if (loopsInPathToRecreate.isEmpty() || !loopsInPathToRecreate.keySet().stream()
                .anyMatch(loop -> loop.getLoopNodes().contains(predecessor))) {
            functionName = getFreshFunctionName(functionStartNode);
        }

        String lFunctionHeader = functionStartNode.getFunctionDefinition().getType().toASTString(functionName);
        // lFunctionHeader is for example "void foo_99(int a)"

        // create a new function
        FunctionBody newFunction = new FunctionBody(firstFunctionElement.getStateId(), lFunctionHeader);

        // register function if necessary
        if (!mFunctionDecls.contains(lFunctionHeader + ";")) {
            mFunctionDecls.add(lFunctionHeader + ";");
            if (uniqueFunction.matcher(lFunctionHeader).matches()) {
                mFunctionBodies.add(newFunction);
                functionStack.push(newFunction); // add function to current stack
            } else {
                nonUniqueFunctions.put(lFunctionHeader,
                        Pair.<CFunctionEntryNode, FunctionBody>of(functionStartNode, newFunction));
            }
        }

        // push to callstack after the if-clause before, we allow several calls
        // to the same function but we do not allow them to be on the same callstack
        callStack.push(lFunctionHeader);
        assert callStack.size() == new HashSet<>(callStack).size() : "Recursive function call found";

        return functionName;
    }

    @Override
    protected void processEdge(ARGState childElement, CFAEdge edge, Stack<FunctionBody> functionStack) {
        // we don't need to handle this edge again
        if (handledFunctions.contains(callStack.peek()) && edge instanceof CFunctionReturnEdge) {
            callStack.pop();
            return;
        }

        // we don't need to handle this edge again
        if (handledEdges.contains(edge) || handledFunctions.contains(callStack.peek())) {
            return;
        }

        if (loopsInPathToRecreate == null) {
            super.processEdge(childElement, edge, functionStack);
        } else {
            processEdge0(childElement, edge, functionStack);
        }
    }

    /**
     * Processes an edge of the CFA and will write code to the output function body.
     */
    private final void processEdge0(ARGState childElement, CFAEdge edge, Stack<FunctionBody> functionStack) {
        FunctionBody currentFunction = functionStack.peek();

        if (childElement.isTarget()) {
            currentFunction.write(getTargetState());
        }

        // handle the edge

        if (edge instanceof CFunctionCallEdge) {

            // if this function is already handled we need to quit here and just push
            // the function onto the callstack
            if (handledFunctions.contains(((CFunctionEntryNode) edge.getSuccessor()).getFunctionName())) {
                callStack.push(((CFunctionEntryNode) edge.getSuccessor()).getFunctionName());
                currentFunctionName = ((CFunctionEntryNode) edge.getSuccessor()).getFunctionName();
                return;
            }
            // if this is a function call edge we need to create a new state and push
            // it to the topmost stack to represent the function

            // create function and put in onto stack
            String freshFunctionName = startFunction(childElement, functionStack, edge.getPredecessor());
            currentFunctionName = freshFunctionName;

            // write summary edge to the caller site (with the new unique function name)
            currentFunction.write(processFunctionCall(edge, freshFunctionName));

        } else if (edge instanceof CFunctionReturnEdge) {
            // only pop from functionStack when we have a unique function
            // and the functionreturn has also to be matchin to the current function we are
            // in
            if (callStack.peek().contains(((CFunctionReturnEdge) edge).getFunctionEntry().getFunctionName())) {
                if (uniqueFunction.matcher(callStack.peek()).matches()) {
                    functionStack.pop();
                }
                callStack.pop();
            }
            currentFunctionName = callStack.peek();

        } else {
            // only write edges that are not from functions which we have to
            // write completely, this will be done afterwards
            if (uniqueFunction.matcher(callStack.peek()).matches()) {
                currentFunction.write(processSimpleEdge0(edge, currentFunction.getCurrentBlock(), childElement));
            }
        }
    }

    private String processSimpleEdge0(CFAEdge pCFAEdge, BasicBlock currentBlock, final ARGState state) {

        CFANode succ = pCFAEdge.getSuccessor();
        List<Loop> loopsAfter = from(getLoopsOfNode(loopStructure, succ)).filter(loopsInPathToRecreate::containsKey)
                .toList();

        // we do not go into a loop that has to be uprolled, so just continue normally
        if (loopsAfter.isEmpty()
                || !loopsInPathToRecreate.get(loopsAfter.get(loopsAfter.size() - 1)).contains(state)) {
            return processSimpleWithLoop(pCFAEdge, currentBlock, "").trim();
        } else {
            return recreateLoop(pCFAEdge, currentBlock, loopsAfter).getFirst();
        }
    }

    /**
     * Recreates a function from the currentStartNode up to the given untilNode.
     * @param functionEntryNode the entry node into this function
     * @param currentStartNode the node from where the recreation should start
     * @param untilNode the node where the recreation should end
     * @param block the current basic block
     * @return the c-code of the recreated function part
     */
    private String recreateFunction(FunctionEntryNode functionEntryNode, CFANode currentStartNode,
            CFANode untilNode, BasicBlock block) {
        StringBuilder wholeFunction = new StringBuilder();

        Deque<CFAEdge> nextEdge = new ArrayDeque<>();
        // the function entry node always has exactly one following edge
        // which is labeled "function start dummy edge"
        // therefore it is safe to only use this edge without further checks
        nextEdge.offer(currentStartNode.getLeavingEdge(0));

        while (!nextEdge.isEmpty()) {
            CFAEdge currentEdge = nextEdge.poll();
            wholeFunction.append(processSimpleWithLoop(currentEdge, block, ""));

            if (currentEdge.getSuccessor() == untilNode) {
                return wholeFunction.toString();
            }

            // there is no successor after this node
            // so just look if we have more edges to do
            if (currentEdge instanceof AReturnStatementEdge) {
                continue;
            }

            CFANode successor = currentEdge.getSuccessor();

            // check if we already encountered the current edge before
            if (handledEdges.contains(currentEdge)) {
                continue;
            }

            FluentIterable<Loop> currentLoops = from(getLoopsOfNode(loopStructure, successor));

            // we found a loop which has to be handled
            if (!currentLoops.isEmpty()) {
                Pair<String, CFAEdge> tmp = recreateLoop(currentEdge, block, currentLoops.toList());
                // there should be only one successor on a leaving edge from a loop
                assert tmp.getSecond().getSuccessor().getNumLeavingEdges() == 1;
                nextEdge.offer(tmp.getSecond().getSuccessor().getLeavingEdge(0));
                wholeFunction.append(tmp.getFirst());

                // we found an if-statement
            } else if (successor.getNumLeavingEdges() > 1) {
                Pair<String, CFAEdge> tmp = recreateIf(currentEdge, block, functionEntryNode);
                nextEdge.offer(tmp.getSecond());
                wholeFunction.append(tmp.getFirst());

                // a normal edge
            } else {
                CFAEdge leavingEdge = successor.getLeavingEdge(0);

                // use the summary edge so that we write only the code of one function
                if (leavingEdge instanceof CFunctionCallEdge) {
                    leavingEdge = successor.getLeavingSummaryEdge();
                }

                nextEdge.offer(leavingEdge);
            }
        }
        return wholeFunction.toString();
    }

    /**
     * Recreates the code of an if-clause with gotos
     * @param pCFAEdge the edge to the head of the if-clause
     * @param currentBlock the current block
     * @return the complete c-code for the recreated if-clause
     */
    private Pair<String, CFAEdge> recreateIf(CFAEdge pCFAEdge, BasicBlock currentBlock,
            FunctionEntryNode entryNode) {
        StringBuilder ifString = new StringBuilder();

        CFAEdge branch1 = pCFAEdge.getSuccessor().getLeavingEdge(0);
        CFAEdge branch2 = pCFAEdge.getSuccessor().getLeavingEdge(1);

        CFANode ifEnd = findEndOfBranches(singletonList((CFANode) entryNode.getExitNode()),
                pCFAEdge.getPredecessor(), branch1.getSuccessor(), branch2.getSuccessor());

        String elseLabel = createFreshLabelForIf(branch2, ifEnd);
        String outLabel = ifOutLabelEnd.peek().get(ifEnd);
        ifString.append(processSimpleWithLoop(branch1, currentBlock, elseLabel))
                .append(recreateFunction(entryNode, branch1.getSuccessor(), ifEnd, currentBlock)).append("goto ")
                .append(outLabel).append(";\n").append(elseLabel).append(": ;\n")
                .append(recreateFunction(entryNode, branch2.getSuccessor(), ifEnd, currentBlock)).append(outLabel)
                .append(": ;\n");

        // there should only be one leaving edge from the mergepoint
        assert ifEnd.getNumLeavingEdges() == 1;
        return Pair.of(ifString.toString(), ifEnd.getLeavingEdge(0));
    }

    /**
     * Recreates the code of one (or more nested) loops with gotos.
     * @param pCFAEdge the edge into the loop
     * @param currentBlock the current block
     * @param loopsAfter the loops which we are in after the edge
     * @return the complete c-code for the recreated loop
     */
    private Pair<String, CFAEdge> recreateLoop(CFAEdge pCFAEdge, BasicBlock currentBlock, List<Loop> loopsAfter) {
        // clear all necessary things
        resetLoopAndIfMaps();

        CFAEdge lastEdge = null;

        // start actual loop recreation
        StringBuilder wholeLoopString = new StringBuilder();

        // we go into a loop thus we have to uproll it right now, and add all
        // handled edges to the handledEdges list, so they wont occur twice in the
        // generated c code

        // this should be already handled by the handledEdges check at the beginning
        // of the processEdge method
        assert loopsAfter.get(loopsAfter.size() - 1).getIncomingEdges().contains(pCFAEdge);

        Loop loop = loopsAfter.get(loopsAfter.size() - 1);

        // create necessary mappings
        String labelStayInLoop = createFreshLabelForLoop(pCFAEdge, loop);

        // uproll loop and write code
        wholeLoopString.append(labelStayInLoop).append(": ;\n");
        Deque<CFAEdge> edgesToHandle = new ArrayDeque<>();
        edgesToHandle.offer(pCFAEdge);

        Deque<Loop> loopStack = new ArrayDeque<>();
        loopStack.push(loop);
        Deque<CFAEdge> ifStack = new ArrayDeque<>();
        Deque<CFAEdge> outOfLoopEdgesStack = new ArrayDeque<>();

        while ((!edgesToHandle.isEmpty() || !outOfLoopEdgesStack.isEmpty() || !ifStack.isEmpty())) {

            // all nodes from the current loop handled, so we can go on to the
            // next one
            if (edgesToHandle.isEmpty()) {
                // at first we need to handle ifs
                if (!ifStack.isEmpty()) {
                    edgesToHandle.offer(ifStack.pop());
                    wholeLoopString.append("goto ").append(ifOutLabels.get(edgesToHandle.peek())).append(";\n")
                            .append(ifElseLabels.get(edgesToHandle.peek())).append(": ;\n");
                } else {
                    edgesToHandle.offer(outOfLoopEdgesStack.pop());
                    Loop oldLoop = loopStack.pop();
                    wholeLoopString.append("goto ").append(loopInLabels.get(oldLoop)).append(";\n")
                            .append(loopOutLabels.get(oldLoop)).append(": ;\n");
                }
            }

            CFANode currentEdgePredecessor = edgesToHandle.peek().getPredecessor();
            handleIfOutLabels(wholeLoopString, currentEdgePredecessor);

            // only continue if we didn't already visit this edge
            if (handledEdges.contains(edgesToHandle.peek())) {
                edgesToHandle.pop();
                continue;
            }

            CFAEdge currentEdge = edgesToHandle.pop();
            handledEdges.add(currentEdge);
            FluentIterable<CFAEdge> leaving = CFAUtils.leavingEdges(currentEdge.getSuccessor())
                    .filter(not(instanceOf(FunctionCallEdge.class)));

            // there was a function call, we need to replace it with the correct successor
            // as we are sure that there is only one, this is safe, we also don't
            // need to update loops here
            if (leaving.isEmpty()) {
                CFAEdge realLeavingEdge = currentEdge.getSuccessor().getLeavingEdge(0);
                CFAEdge leavingSummaryEdge = currentEdge.getSuccessor().getLeavingSummaryEdge();

                wholeLoopString.append(processSimpleWithLoop(realLeavingEdge, currentBlock, ""));
                handledFunctions.add(((CFunctionEntryNode) realLeavingEdge.getSuccessor()).getFunctionName());
                leaving = leaving.append(leavingSummaryEdge);

                // no function call just and ordinary statement, add it as it is
                // to the loopString
            } else if (leaving.size() == 1) {
                wholeLoopString.append(processSimpleWithLoop(leaving.get(0), currentBlock, ""));
            }

            // only one successor, to handle
            // we need to check the loops so that we know if we need
            // to update the loopStack, or only the handledEdges
            if (leaving.size() == 1) {
                CFAEdge onlyEdge = leaving.get(0);

                // this is an edge from inside the loop back to the loop
                if (loopToHead.get(loopStack.peek()) == onlyEdge.getSuccessor()
                        && !loopStack.peek().getIncomingEdges().contains(onlyEdge)) {
                    handledEdges.add(onlyEdge);

                    handleIfOutLabels(wholeLoopString, onlyEdge.getPredecessor());
                } else {
                    edgesToHandle.offer(onlyEdge);
                    updateLoopStack(wholeLoopString, loopStack, onlyEdge);
                }

                // more sucessors, we have to add some gotos
            } else {
                // there can be at most two leaving edges
                assert leaving.size() == 2 : leaving.toString();

                CFAEdge leaving1 = leaving.get(0);
                CFAEdge leaving2 = leaving.get(1);

                // outgoing edges have to be handled first, this way
                // we can create the goto easier
                ImmutableSet<CFAEdge> outOfCurrentLoop = loopStack.peek().getOutgoingEdges();

                boolean isOutOfLoopContained = false;
                CFAEdge leavingLoopEdge = null;

                if (outOfCurrentLoop.contains(leaving1)) {
                    handleOutOfLoopEdge(currentBlock, wholeLoopString, edgesToHandle, loopStack, leaving1,
                            leaving2);
                    leavingLoopEdge = leaving1;
                    isOutOfLoopContained = true;

                } else if (outOfCurrentLoop.contains(leaving2)) {
                    handleOutOfLoopEdge(currentBlock, wholeLoopString, edgesToHandle, loopStack, leaving2,
                            leaving1);
                    leavingLoopEdge = leaving2;
                    isOutOfLoopContained = true;
                }

                if (isOutOfLoopContained) {
                    // we are alredy in the outermost loop that should be handled
                    // if we have an edge which is leaving this loop we just need
                    // to create a goto
                    if (loopStack.size() == 1) {
                        lastEdge = leavingLoopEdge;
                        handledEdges.add(leavingLoopEdge);

                        // deeper loopstack, potentially the same code as above
                        // we do only need to handle the successor of the outOfLoopEdge, too
                    } else {
                        outOfLoopEdgesStack.push(leavingLoopEdge);
                    }

                    // end this loop iteration here
                    continue;
                }

                // now comes the case where both edges stay in the loop, this means
                // this is a "simple" if statement
                // we need to find the merging point of both branches, such that we
                // know where the gotos and labels have to go
                if (!handledEdges.contains(leaving1)) {
                    wholeLoopString.append(processSimpleWithLoop(leaving1, currentBlock,
                            createFreshLabelForIf(leaving2,
                                    findEndOfBranches(singletonList(loopToHead.get(loopStack.peek())),
                                            currentEdgePredecessor, leaving1.getSuccessor(),
                                            leaving2.getSuccessor()))));
                    edgesToHandle.push(leaving1);
                    ifStack.push(leaving2);
                }
            }
        }

        wholeLoopString.append("goto ").append(loopInLabels.get(loop)).append(";\n").append(loopOutLabels.get(loop))
                .append(": ;\n");

        //    assert ifOutLabelEnd.isEmpty() && loopStack.isEmpty();
        return Pair.of(wholeLoopString.toString(), lastEdge);
    }

    /**
     * Should only be called by {@link #recreateLoop(CFAEdge, BasicBlock, List)}.
     * It handles out of if-clause edges in a way that the necessary gotos and labels
     * are added
     */
    private void handleIfOutLabels(StringBuilder wholeLoopString, CFANode predecessor) {
        if (!ifOutLabelEnd.isEmpty() && ifOutLabelEnd.peek().containsKey(predecessor)) {
            if (ifThenHandled.contains(predecessor)) {
                wholeLoopString.append(ifOutLabelEnd.pop().get(predecessor)).append(": ;\n");
            } else {
                ifThenHandled.add(predecessor);
            }
        }
    }

    /**
     * Should only be called by {@link #recreateLoop(CFAEdge, BasicBlock, List)}.
     * It handles out of loop edges in a way that the necessary gotos and labels
     * are added
     */
    private void handleOutOfLoopEdge(BasicBlock currentBlock, StringBuilder wholeLoopString,
            Deque<CFAEdge> edgesToHandle, Deque<Loop> loopStack, CFAEdge leavingEdge, CFAEdge stayingEdge) {
        updateLoopStack(wholeLoopString, loopStack, stayingEdge);
        wholeLoopString
                .append(processSimpleWithLoop(leavingEdge, currentBlock, loopOutLabels.get(loopStack.peek())));
        edgesToHandle.push(stayingEdge);
    }

    /**
     * After each processSimpleEdge0 call, all loop recreation related maps,
     * deques and sets have to be cleared.
     * Should only be called from this method also and not from outside.
     */
    private void resetLoopAndIfMaps() {
        loopInLabels = new HashMap<>();
        loopToHead = new HashMap<>();
        loopOutLabels = new HashMap<>();
        ifOutLabels = new HashMap<>();
        ifOutLabelEnd = new ArrayDeque<>();
        ifThenHandled = new HashSet<>();
        ifElseLabels = new HashMap<>();
    }

    /**
     * Updates the loopStack for loopHandling in processSimpleEdge0. It should
     * be only called from there.
     */
    private void updateLoopStack(StringBuilder wholeLoopString, Deque<Loop> loopStack, CFAEdge onlyEdge) {
        List<Loop> newLoops = getLoopsOfNode(loopStructure, onlyEdge.getSuccessor());

        // nothing to update in this case
        if (newLoops.isEmpty()) {
            return;
        }

        Loop newInnerLoop = newLoops.get(newLoops.size() - 1);
        if (newInnerLoop.getIncomingEdges().contains(onlyEdge)) {
            String newLabel = createFreshLabelForLoop(onlyEdge, newInnerLoop);
            wholeLoopString.append(newLabel + ": ;\n");
            loopStack.push(newInnerLoop);
        }
    }

    /**
     * Creates a new label for an loop, thus, for the into loop case a label before
     * the loop and for the out of loop case a label after the loop
     *
     * @param pCFAEdge the edge into the loop
     * @param loop the loop for which the labels are needed
     * @return the label to stay in the loop
     */
    private String createFreshLabelForLoop(CFAEdge pCFAEdge, Loop loop) {
        assert !loopInLabels.containsKey(loop);
        String labelStayInLoop = getFreshLabel();
        loopInLabels.put(loop, labelStayInLoop);

        assert !loopToHead.containsKey(loop);
        loopToHead.put(loop, pCFAEdge.getSuccessor());

        assert !loopOutLabels.containsKey(loop);
        String labelGetOutOfLoop = getFreshLabel();
        loopOutLabels.put(loop, labelGetOutOfLoop);

        return labelStayInLoop;
    }

    /**
     * Creates a new label for an "if" statement, thus, for the then case a goto
     * after the else branch, and for the else case a goto after the then branch.
     *
     * @param elseEdge the edge into the else branch
     * @param meetingPoint the point where both branches meet again
     * @return the label to jump to the else branch
     */
    private String createFreshLabelForIf(CFAEdge elseEdge, CFANode meetingPoint) {
        assert !ifElseLabels.containsKey(elseEdge);
        String labelElse = getFreshLabel();
        ifElseLabels.put(elseEdge, labelElse);

        assert !ifOutLabels.containsKey(elseEdge);
        String labelOut = getFreshLabel();
        ifOutLabels.put(elseEdge, labelOut);

        Map<CFANode, String> outMap = new HashMap<>();
        outMap.put(meetingPoint, labelOut);
        ifOutLabelEnd.push(outMap);
        return labelElse;
    }

    /**
     * This method processes a given edge which may be inside of a loop. The suffix
     * is used to jump to a label if we have found an assume edge. If the suffix
     * is empty this is an assume which leads to program termination if not hold,
     * in order to have only the one path of the program we want to analyze afterwards.
     *
     * @param edge the edge to be handled
     * @param currentBlock the currentBlock
     * @param suffix the label to jump to, may be the empty string (in most cases it is) but not null
     * @return the c-code resulting from processing the given edge
     */
    private String processSimpleWithLoop(CFAEdge edge, BasicBlock currentBlock, String suffix) {
        switch (edge.getEdgeType()) {

        case BlankEdge:
        case StatementEdge:
        case ReturnStatementEdge:
        case DeclarationEdge:
            return super.processSimpleEdge(edge, currentBlock) + "\n";

        case AssumeEdge: {
            CAssumeEdge lAssumeEdge = (CAssumeEdge) edge;
            if (suffix.isEmpty()) {
                if (currentFunctionName.equals("int main_0()")) {
                    return "if(! (" + lAssumeEdge.getCode() + ")) { return 0; }\n"; // we do only want to see the relevant path
                } else {
                    return ""; // we cannot just use exit(0) as the invariant generators does
                               // cannot cope with non-returning functions
                }
            } else {
                // this is either an out of loop-if or a normal if which has to be redone in a normal way
                // therefore we cannot invert the condition, otherwise the meaning is wrong
                return ("if(" + lAssumeEdge.getCode() + ") { goto " + suffix + "; }\n");
            }
        }

        case FunctionCallEdge: {

            // write summary edge to the caller site (with the new unique function name)
            CFunctionEntryNode entryNode = ((CFunctionSummaryEdge) ((FunctionCallEdge) edge).getSummaryEdge())
                    .getFunctionEntry();
            String functionName = entryNode.getFunctionName();
            String functionHeader = entryNode.getFunctionDefinition().getType().toASTString(functionName);
            // lFunctionHeader is for example "void foo_99(int a)"

            if (!nonUniqueFunctions.containsKey(functionHeader)) {
                nonUniqueFunctions.put(functionHeader, Pair.of(entryNode, new FunctionBody(-1, functionHeader)));
            }

            return processFunctionCall(edge, functionName) + "\n";
        }

        default:
            throw new AssertionError("Unexpected edge " + edge + " of type " + edge.getEdgeType());
        }
    }

    /**
     * {@inheritDoc}
     *
     * Our target state is the end of the program, therefore we return 1 to
     * signalize a wrong program (although for the invariants this will have
     * no meaning at all)
     */
    @Override
    protected String getTargetState() {
        return "return 1;";
    }

    /**
     * This method can be used to find the end of a branching statement, e.g. if then else
     * given the first nodes after the branch it computes the point where both branches
     * are merged together again, or if no merging point was found. It returns the
     * initially given node from the list of intermediateFunctionEnds.
     *
     * @param intermediateFunctionEnds Should contain exactly the last point you
     *                                 know that is definitely the merging point
     *                                 (e.g. the function end)
     * @param functionStart Should be the node which is definitely above the branching
     *                      point. E.g. the function start or the node from which
     *                      the two branches are leaving
     * @param thenNode the first node in the then branch
     * @param elseNode the first node in the else branch
     * @return The point where both given branches are merged
     */
    private CFANode findEndOfBranches(final List<CFANode> intermediateFunctionEnds, final CFANode functionStart,
            final CFANode thenNode, final CFANode elseNode) {
        return findEndOfBranchesNonRecursive(elseNode, thenNode, functionStart, intermediateFunctionEnds.get(0));
    }

    private CFANode findEndOfBranchesNonRecursive(CFANode branch1, CFANode branch2, CFANode head, CFANode bottom) {
        Set<CFANode> foundNodes = CFATraversal.dfs().backwards().ignoreFunctionCalls()
                .collectNodesReachableFromTo(bottom, head);

        // only if both branches are contained the branching is a real if-clause
        if (foundNodes.contains(branch1) && foundNodes.contains(branch2)) {
            Deque<CFANode> branchStack = new ArrayDeque<>();
            branchStack.push(branch1);
            while (!branchStack.isEmpty()) {
                branch1 = branchStack.pop();

                if (CFATraversal.dfs().backwards().ignoreFunctionCalls().collectNodesReachableFromTo(branch1, head)
                        .contains(branch2)) {
                    return branch1;
                }

                if (branch1.getNumLeavingEdges() == 2) {
                    branchStack.push(branch1.getLeavingEdge(1).getSuccessor());
                }
                CFANode tmpSucc = branch1.getLeavingEdge(0).getSuccessor();
                if (tmpSucc != bottom) {
                    branchStack.push(tmpSucc);
                }
            }

            // we did not find the loop although we should have
            throw new AssertionError(
                    "We did not find a merging point although there should be one, this is a BUG!");

        } else {
            return bottom;
        }
    }

    /**
     * Returns a new unique label with a number incremented in the end
     */
    private String getFreshLabel() {
        return "CPAchecker_label_" + labelCounter++;
    }

}