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

Java tutorial

Introduction

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

Source

/*
 * CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2016  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 com.google.common.base.Splitter;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

import org.sosy_lab.common.ShutdownNotifier;
import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.configuration.Option;
import org.sosy_lab.common.configuration.Options;
import org.sosy_lab.common.io.MoreFiles;
import org.sosy_lab.common.io.PathTemplate;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cfa.ast.FileLocation;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.core.interfaces.AbstractState;
import org.sosy_lab.cpachecker.core.interfaces.FormulaReportingState;
import org.sosy_lab.cpachecker.core.reachedset.ReachedSet;
import org.sosy_lab.cpachecker.util.AbstractStates;
import org.sosy_lab.cpachecker.util.predicates.smt.FormulaManagerView;
import org.sosy_lab.cpachecker.util.predicates.smt.Solver;
import org.sosy_lab.cpachecker.util.predicates.weakening.InductiveWeakeningManager;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.BooleanFormulaManager;

import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

@Options(prefix = "cinvariants")
public class CExpressionInvariantExporter {

    @Option(secure = true, description = "Attempt to simplify the invariant before "
            + "exporting [may be very expensive].")
    private boolean simplify = false;

    private final PathTemplate prefix;

    private final FormulaManagerView fmgr;
    private final BooleanFormulaManager bfmgr;
    private final FormulaToCExpressionConverter formulaToCExpressionConverter;
    private final InductiveWeakeningManager inductiveWeakeningManager;

    public CExpressionInvariantExporter(Configuration pConfiguration, LogManager pLogManager,
            ShutdownNotifier pShutdownNotifier, PathTemplate pPrefix) throws InvalidConfigurationException {
        pConfiguration.inject(this);
        prefix = pPrefix;
        Solver solver = Solver.create(pConfiguration, pLogManager, pShutdownNotifier);
        fmgr = solver.getFormulaManager();
        bfmgr = fmgr.getBooleanFormulaManager();
        formulaToCExpressionConverter = new FormulaToCExpressionConverter(fmgr);
        inductiveWeakeningManager = new InductiveWeakeningManager(pConfiguration, solver, pLogManager,
                pShutdownNotifier);
    }

    /**
     * Export invariants extracted from {@code pReachedSet} into the file
     * specified by the options as {@code __VERIFIER_assume()} calls,
     * intermixed with the program source code.
     */
    public void exportInvariant(String analyzedPrograms, ReachedSet pReachedSet)
            throws IOException, InterruptedException {

        Splitter commaSplitter = Splitter.on(',').omitEmptyStrings().trimResults();
        List<String> programs = commaSplitter.splitToList(analyzedPrograms);

        for (String program : programs) {
            // Grab only the last component of the program filename.
            Path trimmedFilename = Paths.get(program).getFileName();
            if (trimmedFilename != null) {
                try (Writer output = MoreFiles.openOutputFile(prefix.getPath(trimmedFilename.toString()),
                        Charset.defaultCharset())) {
                    writeProgramWithInvariants(output, program, pReachedSet);
                }
            }
        }
    }

    private void writeProgramWithInvariants(Appendable out, String filename, ReachedSet pReachedSet)
            throws IOException, InterruptedException {

        Map<Integer, BooleanFormula> reporting = getInvariantsForFile(pReachedSet, filename);

        try (Stream<String> lines = Files.lines(Paths.get(filename))) {
            int lineNo = 0;
            Iterator<String> it = lines.iterator();
            while (it.hasNext()) {
                String line = it.next();
                Optional<String> invariant = getInvariantForLine(lineNo, reporting);
                if (invariant.isPresent()) {
                    out.append("__VERIFIER_assume(").append(invariant.get()).append(");\n");
                }
                out.append(line).append('\n');
                lineNo++;
            }
        }
    }

    private Optional<String> getInvariantForLine(int lineNo, Map<Integer, BooleanFormula> reporting)
            throws InterruptedException {
        BooleanFormula formula = reporting.get(lineNo);
        if (formula == null) {
            return Optional.empty();
        }
        if (simplify) {
            formula = simplifyInvariant(formula);
        }
        return Optional.of(formulaToCExpressionConverter.formulaToCExpression(formula));
    }

    /**
     * @return Mapping from line numbers to states associated with the given line.
     */
    private Map<Integer, BooleanFormula> getInvariantsForFile(ReachedSet pReachedSet, String filename) {

        // One formula per reported state.
        Multimap<Integer, BooleanFormula> byState = HashMultimap.create();

        for (AbstractState state : pReachedSet) {

            CFANode loc = AbstractStates.extractLocation(state);
            if (loc != null && loc.getNumEnteringEdges() > 0) {
                CFAEdge edge = loc.getEnteringEdge(0);
                FileLocation location = edge.getFileLocation();
                FluentIterable<FormulaReportingState> reporting = AbstractStates.asIterable(state)
                        .filter(FormulaReportingState.class);

                if (location.getFileName().equals(filename) && !reporting.isEmpty()) {
                    BooleanFormula reported = bfmgr
                            .and(reporting.transform(s -> s.getFormulaApproximation(fmgr)).toList());
                    byState.put(location.getStartingLineInOrigin(), reported);
                }
            }
        }
        return Maps.transformValues(byState.asMap(), invariants -> bfmgr.or(invariants));
    }

    private BooleanFormula simplifyInvariant(BooleanFormula pInvariant) throws InterruptedException {
        return inductiveWeakeningManager.removeRedundancies(pInvariant);
    }
}