...
 
Commits (14)
MIT License
Copyright (c) 2019 Testos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# COBAP project Makefile
# file: Makefile
# author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
# date: 2019
# description: Build scripts for cobap project
TARGET=bin/cobap
.PHONY: target
......@@ -7,6 +11,7 @@ target: $(TARGET)
$(TARGET):
make -C src/
cp bin/cobap api/cobap
test: $(TARGET)
make -C tests/
......
# COBAP Generator
**CO**verage **BA**sed **P**aths generator
## Build requirements
* LLVM libraries, tested with version 7
* TINDGER (yep)[https://pajda.fit.vutbr.cz/testos/tindger] tool
\ No newline at end of file
app.cpython*.pyc
\ No newline at end of file
# python generated files
app.cpython*.pyc
# tools binaries
tindger
cobap
\ No newline at end of file
# file: app.py
# author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
# date: 2019
# details: Flask web application.
import os
import shutil
import uuid
......@@ -139,7 +144,7 @@ def start_job(args):
os.makedirs(job_dir)
shutil.copy2(os.path.join(llvm_files_dir,
args['filename']), llvm_file_path)
args = ["timeout", "10m", "../bin/cobap", "-c", args['coverage'],
args = ["timeout", "10m", "./cobap", "-c", args['coverage'],
"-s", args['size'], "-m", args['max'], "-o", out_file_name, "-w", job_dir, llvm_file_path]
print(args)
......@@ -178,12 +183,12 @@ def delete_job(job_id):
for job in jobs:
if job['id'] == job_id:
if job['state'] == "running":
return jsonify(message="Cannot delete running process"), 400
return jsonify(status="failure", message="Cannot delete running process"), 400
else:
shutil.rmtree(os.path.join(jobs_dir, job_id))
return jsonify("deleted"), 200
return jsonify(status="success", message="job information deleted"), 200
return jsonify("not found"), 404
return jsonify(status="failure", message="not found"), 404
def get_job_result(job_id, method):
......@@ -199,48 +204,48 @@ def get_job_result(job_id, method):
else:
return send_file(result_file_path, attachment_filename="paths.json", as_attachment=True)
elif job['state'] == "running":
return jsonify(message="Job has not finished yet"), 400
return jsonify(status="failure", message="Job has not finished yet"), 400
else:
return jsonify(message="Job has been cancelled"), 400
return jsonify(status="success", message="Job has been cancelled"), 400
return jsonify("not found"), 404
return jsonify(status="failure", message="not found"), 404
@app.route('/rest/job', methods=('GET', 'POST', 'DELETE'))
def job_route():
if request.method == 'POST':
args = parse_job_arguments(request)
if type(args) is tuple:
return jsonify(args[0]), args[1]
start_job(args)
return jsonify("Job started"), 200
@app.route('/api/jobs/<path:job_id>', methods=('GET', 'DELETE'))
def job_route(job_id):
print("path is")
print(job_id)
if request.method == 'GET':
job_id = request.args.get('job-id')
return get_job_result(job_id, "text")
else:
if request.method == 'GET':
job_id = request.args.get('job-id')
return get_job_result(job_id, "text")
elif request.method == 'DELETE':
if request.is_json:
if 'job-id' not in request.json:
return jsonify(message="No key 'job-id' in request JSON"), 400
else:
job_id = request.json['job-id']
if request.is_json:
if 'job-id' not in request.json:
return jsonify(message="No key 'job-id' in request JSON"), 400
else:
if 'job-id' not in request.form:
return jsonify(message="No key 'job-id' in request form"), 400
else:
job_id = request.form['job-id']
return delete_job(job_id)
job_id = request.json['job-id']
else:
return jsonify("Unhandled jobs request"), 500
if 'job-id' not in request.form:
return jsonify(message="No key 'job-id' in request form"), 400
else:
job_id = request.form['job-id']
return delete_job(job_id)
@app.route('/rest/jobs', methods=['GET'])
@app.route('/api/jobs', methods=('GET', 'POST'))
def jobs_route():
return jsonify(jobs=get_jobs_list()), 200
print("whaaaaaaaat")
if request.method == 'GET':
return jsonify(jobs=get_jobs_list()), 200
else:
args = parse_job_arguments(request)
if type(args) is tuple:
return jsonify(args[0]), args[1]
start_job(args)
return jsonify(status="success", message="Job started"), 200
# management of LLVM IR files, which can then be provided to cobap
# tool to do analysis on
......@@ -272,46 +277,48 @@ def decode_b64_to_file(b64string, file_name):
return
@app.route('/rest/llvm-files', methods=('GET', 'POST', 'DELETE'))
@app.route('/api/llvm-files', methods=['GET'])
def llvm_files_route():
if request.method == 'GET':
return jsonify(llvm_files=get_llvm_files_list())
elif request.method == 'DELETE':
return jsonify(llvm_files=get_llvm_files_list())
@app.route('/api/llvm-files/<path:filename>', methods=('POST', 'DELETE'))
def llvm_file_route(filename):
if request.method == 'DELETE':
if request.is_json:
if 'file-name' not in request.json:
return jsonify(message="No key 'file-name' in request JSON"), 400
return jsonify(status="failure", message="No key 'file-name' in request JSON"), 400
else:
file_name = request.json["file-name"]
else:
if 'file-name' not in request.form:
return jsonify(message="No key 'file-name' in request form"), 400
return jsonify(status="failure", message="No key 'file-name' in request form"), 400
else:
file_name = request.form["file-name"]
if file_name not in get_llvm_files_list():
return jsonify(message="File not found"), 404
return jsonify(status="failure", message="File not found"), 404
delete_llvm_file(file_name)
return jsonify(message="File deleted"), 200
return jsonify(status="success", message="File deleted"), 200
elif request.method == 'POST':
if 'llvm' in request.files:
file = request.files['llvm']
if 'llvm-file' in request.files:
file = request.files['llvm-file']
save_llvm_file(file)
return jsonify("File saved"), 201
return jsonify(status="success", message="File saved"), 201
elif request.is_json:
if 'file-data' not in request.json:
return jsonify(message="No key 'file-data' in request JSON"), 400
return jsonify(status="failure", message="No key 'file-data' in request JSON"), 400
if 'file-name' not in request.json:
return jsonify(message="No key 'file-name' in request JSON"), 400
return jsonify(status="failure", message="No key 'file-name' in request JSON"), 400
file_in_base64 = request.json['file-data']
file_name = request.json['file-name']
decode_b64_to_file(file_in_base64, file_name)
return jsonify("File saved"), 201
return jsonify(status="success", message="File saved"), 201
else:
return jsonify("Unhandled llvm-files request"), 500
return jsonify(status="failure", message="Unhandled llvm-files request"), 500
if __name__ == '__main__':
......
Subproject commit 43bfdf779b0908dd3f2d2ab5436eed8ff1079daa
Subproject commit 4a7a0f57b6981293c18290cef30ff1b5739eb4df
// file: BasicBlocksPath.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// details: Container for sequence of basic blocks.
#include "BasicBlocksPath.hpp"
#include <string>
......@@ -89,8 +94,7 @@ nlohmann::json BasicBlocksPath::ToJson(const llvm::Function& function,
{
{ "path", basicBlocks },
{ "metadata", json::array() },
{ "tag", pathName },
{ "fun", function.getName().str() }
{ "tag", pathName }
};
return output;
......
#pragma once
// file: BasicBlocksPath.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Container for sequence of basic blocks.
#ifndef COBAP_BASICBLOCKSPATH_HPP
#define COBAP_BASICBLOCKSPATH_HPP
#include <string>
#include <vector>
......@@ -39,4 +45,6 @@ private:
std::vector<const llvm::BasicBlock*> path;
static std::unordered_map<const llvm::BasicBlock*, int> BlockToJsonIndex;
};
} // namespace cobap
\ No newline at end of file
} // namespace cobap
#endif
\ No newline at end of file
// file: CoverageCriteria.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Base class definition for targets generators.
#ifndef COBAP_COVERAGE_CRITERIA_HPP
#define COBAP_COVERAGE_CRITERIA_HPP
......
// file: CoverageCriteriaFactory.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Create Coverage object using factory pattern.
#include "CoverageCriteriaFactory.hpp"
#include <memory>
......
// file: CoverageCriteriaFactory.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Create Coverage object using factory pattern.
#ifndef COBAP_COVERAGE_CRITERIA_FACTORY_HPP
#define COBAP_COVERAGE_CRITERIA_FACTORY_HPP
......
// file: CoverageType.hcpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Create Coverage object using factory pattern.
#ifndef COBAP_COVERAGE_TYPE_HPP
#define COBAP_COVERAGE_TYPE_HPP
......
// file: DataflowCoverageCriteria.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Dataflow coverage criteria generator.
#include "DataflowCoverageCriteria.hpp"
#include <iostream>
......
// file: DataflowCoverageCriteria.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Dataflow coverage criteria generator.
#ifndef COBAP_DATAFLOW_COVERAGE_CRITERIA_HPP
#define COBAP_DATAFLOW_COVERAGE_CRITERIA_HPP
......@@ -12,7 +17,7 @@
namespace cobap {
// ------------------------------------------------------------------ //
// ------ Helping data structures used for dataflow analysis -------- //
// ------ Helper data structures used for dataflow analysis -------- //
/// Container for variable metadata and basic blocks where it is
/// defined and/or used.
......@@ -65,7 +70,7 @@ struct DefPathKey
};
// ------ Helping data structures used for dataflow analysis -------- //
// ------ Helper data structures used for dataflow analysis -------- //
// ------------------------------------------------------------------ //
/// Abstract base class for dataflow coverage criteria.
......
// file: GraphCoverageCriteria.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Graph coverage criteria generator.
#include "GraphCoverageCriteria.hpp"
#include <llvm/IR/BasicBlock.h>
......
// file: GraphCoverageCriteria.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Graph coverage criteria generator.
#ifndef COBAP_GRAPH_COVERAGE_CRITERIA_HPP
#define COBAP_GRAPH_COVERAGE_CRITERIA_HPP
......
// file: LogicCoverageCriteria.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Logic coverage criteria generator.
#include "LogicCoverageCriteria.hpp"
#include <set>
......@@ -116,17 +121,8 @@ void Predicate::AddClause(const llvm::BasicBlock* clauseBB)
}
else
{
/*
auto clause = Clause{clauseBB, {*llvm::succ_begin(clauseBB), false}, {*llvm::succ_begin(clauseBB) + 1, false}};
clause.basicBlock = clauseBB;
clause.leftOutcome.outcomeBasicBlock = *llvm::succ_begin(clauseBB);
clause.rightOutcome.outcomeBasicBlock =
*(llvm::succ_begin(clauseBB) + 1);
clause.isLeftClause = false;
clause.isRightClause = false;
this->clauses.push_back(clause);
*/
this->clauses.emplace_back(clauseBB, *llvm::succ_begin(clauseBB), *llvm::succ_begin(clauseBB) + 1);
auto successor_it = llvm::succ_begin(clauseBB);
this->clauses.emplace_back(clauseBB, *successor_it, *(successor_it + 1));
}
}
......@@ -359,7 +355,7 @@ std::vector<Predicate> LogicCriteriaBase::FindAllPredicates() const
{
if (!pair.second.Finalize())
{
llvm::errs() << "error\n";
llvm::errs() << "ERROR: could not finalize\n";
}
predicates.push_back(pair.second);
......
// file: LogicCoverageCriteria.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Logic coverage criteria generator.
#ifndef COBAP_LOGIC_COVERAGE_CRITERIA_HPP
#define COBAP_LOGIC_COVERAGE_CRITERIA_HPP
......@@ -13,6 +18,9 @@
namespace cobap {
// ------------------------------------------------------------------ //
// ------ Helper data structures used for dataflow analysis -------- //
// forward declaration
struct Clause;
......@@ -126,6 +134,9 @@ private:
std::unordered_map<llvm::DIScope*, Predicate>& scopeToPredicateMap) const;
};
// ------ Helper data structures used for dataflow analysis -------- //
// ------------------------------------------------------------------ //
/// Predicate coverage criteria targets generator.
class PredicateCoverage : public LogicCriteriaBase
{
......
// file: Log.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Small logging library.
#ifndef COBAP_LOG_HPP
#define COBAP_LOG_HPP
......
# Makefile
# Implementation is taken from stackoverflow, and modified to work
# for cobap https://stackoverflow.com/a/30142139
# file: Makefile
# author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
# date: 2019
# description: Build scripts for cobap tool.
CXX = clang++
CXXFLAGS = -fno-rtti -DNDEBUG -fno-exceptions -Wall -Wextra -Wno-covered-switch-default -Werror -g
......
// file: PathAlternativesIterator.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: BFS based path generator implemented as an iterator.
#include "PathAlternativesIterator.hpp"
#include <llvm/IR/BasicBlock.h>
......
// file: PathAlternativesIterator.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: BFS based path generator implemented as an iterator.
#ifndef COBAP_PATH_ALTERNATIVES_ITERATOR_HPP
#define COBAP_PATH_ALTERNATIVES_ITERATOR_HPP
......@@ -10,21 +15,36 @@
namespace cobap {
/// Algorithm to search for paths between two nodes, implemented
/// as an lazy iterator, to dynamically as for additional paths.
class PathAlternativesIterator
{
public:
// Typename definitions to enable usage of such iterator in STL.
using iterator_category = std::input_iterator_tag;
using value_type = BasicBlocksPath;
using difference_type = ptrdiff_t;
using pointer = const BasicBlocksPath*;
using reference = const BasicBlocksPath&;
PathAlternativesIterator(const llvm::BasicBlock* from, const llvm::BasicBlock* to);
/// Start and end blocks are generator invariant, given in constructor.
PathAlternativesIterator(const llvm::BasicBlock* from,
const llvm::BasicBlock* to);
/// Check if iterator holds valid path.
operator bool() const;
/// Generate and move to next path.
PathAlternativesIterator& operator++();
/// Generate and move to next path.
PathAlternativesIterator operator++(int);
/// Access the BasicBlocksPath element from iterator wrapper.
BasicBlocksPath operator*() const;
/// Access the public methods and data of BasicBlocksPath
/// element from iterator wrapper.
BasicBlocksPath const* operator->() const;
private:
......@@ -36,6 +56,6 @@ private:
BasicBlocksPath GenerateOneMore();
};
}
} // namespace cobap
#endif
// file: PathVerifier.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Semantic feasibility checker.
#include "PathVerifier.hpp"
#include <cstdlib>
......@@ -10,6 +15,7 @@
#include "../../include/json/json.hpp"
#include "../BasicBlocksPath.hpp"
#include "../Log.hpp"
namespace cobap {
......@@ -22,12 +28,12 @@ PathVerifier::PathVerifier(std::string llvmFilePath,
{
if (workspaceDirectory.size() > 0)
{
this->toExternalVerifier =
workspaceDirectory + this->toExternalVerifier;
this->fromExternalVerifier =
workspaceDirectory + this->fromExternalVerifier;
}
}
this->toExternalVerifier =
workspaceDirectory + this->toExternalVerifier;
this->fromExternalVerifier =
workspaceDirectory + this->fromExternalVerifier;
}
}
std::string PathVerifier::AppendSlash(std::string path)
{
......@@ -56,8 +62,8 @@ bool PathVerifier::IsFeasible(const BasicBlocksPath& path) const
auto result = this->RunExternalVerifier();
if (result != 0)
{
llvm::outs() << "Callig external tool failed\n";
return true;
L_Error() << "Calling external tool failed!\n";
return false;
}
else
{
......@@ -67,7 +73,9 @@ bool PathVerifier::IsFeasible(const BasicBlocksPath& path) const
const auto& resultFile = loadResultFile.get();
json j = json::parse(resultFile->getBufferStart(),
resultFile->getBufferEnd());
if (j["error"].is_null())
if (j["to-solve"]["error"].is_null() ||
j["to-solve"]["error"] == "")
{
return true;
}
......@@ -85,6 +93,7 @@ bool PathVerifier::IsFeasible(const BasicBlocksPath& path) const
void PathVerifier::PrintAsJson(const BasicBlocksPath& path) const
{
L_Info() << "verify this: " << path.ToJson(this->function, "this");
using json = nlohmann::json;
json functionJson = {
{ "function", {
......
// file: PathVerifier.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Semantic feasibility checker.
#ifndef COBAP_PATH_VERIFIER_HPP
#define COBAP_PATH_VERIFIER_HPP
......
// file: Reachables.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Wrapper for accessing reachable nodes.
#include "Reachables.hpp"
#include <string>
......
// file: Reachables.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Wrapper for accessing reachable nodes.
#ifndef COBAP_REACHABLES_HPP
#define COBAP_REACHABLES_HPP
......
// file: PathsGenerator.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Functionality for generating sets of paths.
#include "PathsGenerator.hpp"
#include <deque>
......@@ -115,7 +120,7 @@ llvm::Optional<BasicBlocksPath> PathsGenerator::TryPathParts(
{
if (!prefixGenerator || !postfixGenerator)
{
L_Debug() << "No possible path found from entry block to target and to "
L_Debug() << "No possible path found from entry block to target " << target.getFirst()->getName().str() << " and to "
"exit block";
return llvm::None;
}
......@@ -153,6 +158,10 @@ llvm::Optional<BasicBlocksPath> PathsGenerator::TryPathParts(
prefixFound = true;
break;
}
else
{
L_Debug() << "Full path is not feasible, changing prefix.";
}
}
++prefixGenerator;
......@@ -168,7 +177,8 @@ llvm::Optional<BasicBlocksPath> PathsGenerator::TryPathParts(
L_Debug() << "Feasible prefix found: " << prefixGenerator->Serialize();
bool postfixFound = false;
while (postfixGenerator && !postfixFound)
while (postfixGenerator && !postfixFound &&
path.size() < this->pathMaxLength)
{
L_Debug() << "Current postfix candidate: "
<< postfixGenerator->Serialize();
......@@ -187,7 +197,17 @@ llvm::Optional<BasicBlocksPath> PathsGenerator::TryPathParts(
path = fullPath;
break;
}
else
{
L_Debug() << "Full path is not feasible, changing postfix.";
}
}
else
{
L_Debug() << "Postfix candidate is not feasible.";
}
++postfixGenerator;
}
......
// file: PathsGenerator.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Functionality for generating sets of paths.
#ifndef COBAP_PATHS_GENERATOR_HPP
#define COBAP_PATHS_GENERATOR_HPP
......
// file: Setup.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Application settings parsing.
#include "Setup.hpp"
#include <llvm/IR/LLVMContext.h>
......
// file: Setup.hpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: application settings definition
#ifndef COBAP_SETUP_HPP
#define COBAP_SETUP_HPP
......
// cobap.cpp
// Author: Daniel Kraut
// file: cobap.cpp
// author: Daniel Kraut, xkraut03@stud.fit.vutbr.cz
// date: 2019
// description: Application main function and startup.
#include <system_error>
......
int foo(int a, int b)
{
int sum = 1;
for (int i = 0; i < 2; ++i)
{
if (i == 1)
{
sum += a * b;
}
}
return sum;
}
\ No newline at end of file
int foo(int a, int b)
{
for (int i = 0; i < 2; ++i)
{
if (a > 0)
{
return a * b;
}
else
{
return b;
}
}
return 0;
}
\ No newline at end of file