Skip to content

Feature/context sensitive ait merge 1 #2596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/analyses/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
SRC = ai.cpp \
ai_domain.cpp \
call_graph.cpp \
call_graph_helpers.cpp \
constant_propagator.cpp \
Expand Down
69 changes: 0 additions & 69 deletions src/analyses/ai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,80 +15,11 @@ Author: Daniel Kroening, [email protected]
#include <memory>
#include <sstream>

#include <util/simplify_expr.h>
#include <util/std_expr.h>
#include <util/std_code.h>

#include "is_threaded.h"

jsont ai_domain_baset::output_json(
const ai_baset &ai,
const namespacet &ns) const
{
std::ostringstream out;
output(out, ai, ns);
json_stringt json(out.str());
return json;
}

xmlt ai_domain_baset::output_xml(
const ai_baset &ai,
const namespacet &ns) const
{
std::ostringstream out;
output(out, ai, ns);
xmlt xml("abstract_state");
xml.data=out.str();
return xml;
}

/// Use the information in the domain to simplify the expression on the LHS of
/// an assignment. This for example won't simplify symbols to their values, but
/// does simplify indices in arrays, members of structs and dereferencing of
/// pointers
/// \param condition: the expression to simplify
/// \param ns: the namespace
/// \return True if condition did not change. False otherwise. condition will be
/// updated with the simplified condition if it has worked
bool ai_domain_baset::ai_simplify_lhs(
exprt &condition, const namespacet &ns) const
{
// Care must be taken here to give something that is still writable
if(condition.id()==ID_index)
{
index_exprt ie=to_index_expr(condition);
bool no_simplification=ai_simplify(ie.index(), ns);
if(!no_simplification)
condition=simplify_expr(ie, ns);

return no_simplification;
}
else if(condition.id()==ID_dereference)
{
dereference_exprt de=to_dereference_expr(condition);
bool no_simplification=ai_simplify(de.pointer(), ns);
if(!no_simplification)
condition=simplify_expr(de, ns); // So *(&x) -> x

return no_simplification;
}
else if(condition.id()==ID_member)
{
member_exprt me=to_member_expr(condition);
// Since simplify_ai_lhs is required to return an addressable object
// (so remains a valid left hand side), to simplify
// `(something_simplifiable).b` we require that `something_simplifiable`
// must also be addressable
bool no_simplification=ai_simplify_lhs(me.compound(), ns);
if(!no_simplification)
condition=simplify_expr(me, ns);

return no_simplification;
}
else
return true;
}

void ai_baset::output(
const namespacet &ns,
const goto_functionst &goto_functions,
Expand Down
100 changes: 1 addition & 99 deletions src/analyses/ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,105 +23,7 @@ Author: Daniel Kroening, [email protected]

#include <goto-programs/goto_model.h>

// forward reference
class ai_baset;

// don't use me -- I am just a base class
// please derive from me
class ai_domain_baset
{
public:
// The constructor is expected to produce 'false'
// or 'bottom'
ai_domain_baset()
{
}

virtual ~ai_domain_baset()
{
}

typedef goto_programt::const_targett locationt;

// how function calls are treated:
// a) there is an edge from each call site to the function head
// b) there is an edge from the last instruction (END_FUNCTION)
// of the function to the instruction _following_ the call site
// (this also needs to set the LHS, if applicable)
//
// "this" is the domain before the instruction "from"
// "from" is the instruction to be interpretted
// "to" is the next instruction (for GOTO, FUNCTION_CALL, END_FUNCTION)
//
// PRECONDITION(from.is_dereferenceable(), "Must not be _::end()")
// PRECONDITION(to.is_dereferenceable(), "Must not be _::end()")
// PRECONDITION(are_comparable(from,to) ||
// (from->is_function_call() || from->is_end_function())

virtual void transform(
locationt from,
locationt to,
ai_baset &ai,
const namespacet &ns) = 0;

virtual void output(
std::ostream &out,
const ai_baset &ai,
const namespacet &ns) const
{
}

virtual jsont output_json(
const ai_baset &ai,
const namespacet &ns) const;

virtual xmlt output_xml(
const ai_baset &ai,
const namespacet &ns) const;

// no states
virtual void make_bottom()=0;

// all states -- the analysis doesn't use this,
// and domains may refuse to implement it.
virtual void make_top()=0;

// a reasonable entry-point state
virtual void make_entry()=0;

virtual bool is_bottom() const=0;

virtual bool is_top() const=0;

// also add
//
// bool merge(const T &b, locationt from, locationt to);
//
// This computes the join between "this" and "b".
// Return true if "this" has changed.
// In the usual case, "b" is the updated state after "from"
// and "this" is the state before "to".
//
// PRECONDITION(from.is_dereferenceable(), "Must not be _::end()")
// PRECONDITION(to.is_dereferenceable(), "Must not be _::end()")

// This method allows an expression to be simplified / evaluated using the
// current state. It is used to evaluate assertions and in program
// simplification

// return true if unchanged
virtual bool ai_simplify(
exprt &condition,
const namespacet &ns) const
{
return true;
}

// Simplifies the expression but keeps it as an l-value
virtual bool ai_simplify_lhs(
exprt &condition,
const namespacet &ns) const;
};
#include "ai_domain.h"

// don't use me -- I am just a base class
// use ait instead
Expand Down
79 changes: 79 additions & 0 deletions src/analyses/ai_domain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*******************************************************************\

Module: Abstract Interpretation

Author: Daniel Kroening, [email protected]

\*******************************************************************/

/// \file
/// Abstract Interpretation Domain

#include "ai_domain.h"

#include <util/simplify_expr.h>

jsont ai_domain_baset::output_json(const ai_baset &ai, const namespacet &ns)
const
{
std::ostringstream out;
output(out, ai, ns);
json_stringt json(out.str());
return json;
}

xmlt ai_domain_baset::output_xml(const ai_baset &ai, const namespacet &ns) const
{
std::ostringstream out;
output(out, ai, ns);
xmlt xml("abstract_state");
xml.data = out.str();
return xml;
}

/// Use the information in the domain to simplify the expression on the LHS of
/// an assignment. This for example won't simplify symbols to their values, but
/// does simplify indices in arrays, members of structs and dereferencing of
/// pointers
/// \param condition: the expression to simplify
/// \param ns: the namespace
/// \return True if condition did not change. False otherwise. condition will be
/// updated with the simplified condition if it has worked
bool ai_domain_baset::ai_simplify_lhs(exprt &condition, const namespacet &ns)
const
{
// Care must be taken here to give something that is still writable
if(condition.id() == ID_index)
{
index_exprt ie = to_index_expr(condition);
bool no_simplification = ai_simplify(ie.index(), ns);
if(!no_simplification)
condition = simplify_expr(ie, ns);

return no_simplification;
}
else if(condition.id() == ID_dereference)
{
dereference_exprt de = to_dereference_expr(condition);
bool no_simplification = ai_simplify(de.pointer(), ns);
if(!no_simplification)
condition = simplify_expr(de, ns); // So *(&x) -> x

return no_simplification;
}
else if(condition.id() == ID_member)
{
member_exprt me = to_member_expr(condition);
// Since simplify_ai_lhs is required to return an addressable object
// (so remains a valid left hand side), to simplify
// `(something_simplifiable).b` we require that `something_simplifiable`
// must also be addressable
bool no_simplification = ai_simplify_lhs(me.compound(), ns);
if(!no_simplification)
condition = simplify_expr(me, ns);

return no_simplification;
}
else
return true;
}
122 changes: 122 additions & 0 deletions src/analyses/ai_domain.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*******************************************************************\

Module: Abstract Interpretation

Author: Daniel Kroening, [email protected]

\*******************************************************************/

/// \file
/// Abstract Interpretation Domain

#ifndef CPROVER_ANALYSES_AI_DOMAIN_H
#define CPROVER_ANALYSES_AI_DOMAIN_H

#include <util/expr.h>
#include <util/json.h>
#include <util/make_unique.h>
#include <util/xml.h>

#include <goto-programs/goto_model.h>

// forward reference the abstract interpreter interface
class ai_baset;

/// The interface offered by a domain, allows code to manipulate domains without
/// knowing their exact type. Derive from this to implement domains.
class ai_domain_baset
{
protected:
/// The constructor is expected to produce 'false' or 'bottom'
ai_domain_baset()
{
}

public:
virtual ~ai_domain_baset()
{
}

typedef goto_programt::const_targett locationt;

/// how function calls are treated:
/// a) there is an edge from each call site to the function head
/// b) there is an edge from the last instruction (END_FUNCTION)
/// of the function to the instruction _following_ the call site
/// (this also needs to set the LHS, if applicable)
///
/// "this" is the domain before the instruction "from"
/// "from" is the instruction to be interpretted
/// "to" is the next instruction (for GOTO, FUNCTION_CALL, END_FUNCTION)
///
/// PRECONDITION(from.is_dereferenceable(), "Must not be _::end()")
/// PRECONDITION(to.is_dereferenceable(), "Must not be _::end()")
/// PRECONDITION(are_comparable(from,to) ||
/// (from->is_function_call() || from->is_end_function())

virtual void transform(
locationt from,
locationt to,
ai_baset &ai,
const namespacet &ns) = 0;

virtual void
output(std::ostream &out, const ai_baset &ai, const namespacet &ns) const
{
}

virtual jsont output_json(const ai_baset &ai, const namespacet &ns) const;

virtual xmlt output_xml(const ai_baset &ai, const namespacet &ns) const;

/// no states
virtual void make_bottom() = 0;

/// all states -- the analysis doesn't use this,
/// and domains may refuse to implement it.
virtual void make_top() = 0;

/// a reasonable entry-point state
virtual void make_entry() = 0;

virtual bool is_bottom() const = 0;

virtual bool is_top() const = 0;

/// also add
///
/// bool merge(const T &b, locationt from, locationt to);
///
/// This computes the join between "this" and "b".
/// Return true if "this" has changed.
/// In the usual case, "b" is the updated state after "from"
/// and "this" is the state before "to".
///
/// PRECONDITION(from.is_dereferenceable(), "Must not be _::end()")
/// PRECONDITION(to.is_dereferenceable(), "Must not be _::end()")

/// This method allows an expression to be simplified / evaluated using the
/// current state. It is used to evaluate assertions and in program
/// simplification

/// return true if unchanged
virtual bool ai_simplify(exprt &condition, const namespacet &ns) const
{
return true;
}

/// Simplifies the expression but keeps it as an l-value
virtual bool ai_simplify_lhs(exprt &condition, const namespacet &ns) const;

/// Gives a Boolean condition that is true for all values represented by the
/// domain. This allows domains to be converted into program invariants.
virtual exprt to_predicate(void) const
{
if(is_bottom())
return false_exprt();
else
return true_exprt();
}
};

#endif