2004-08-15 12:55:22 +01:00
|
|
|
/**
|
|
|
|
* Handle bindings for Arache engine.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "list.h"
|
2004-08-18 20:43:58 +01:00
|
|
|
#include "role.h"
|
2004-08-27 20:06:15 +01:00
|
|
|
#include "label.h"
|
2004-08-15 12:55:22 +01:00
|
|
|
#include "system.h"
|
|
|
|
#include "binding.h"
|
2004-08-15 15:57:50 +01:00
|
|
|
#include "warshall.h"
|
2004-08-15 12:55:22 +01:00
|
|
|
#include "memory.h"
|
2004-08-15 17:08:53 +01:00
|
|
|
#include "debug.h"
|
2004-08-17 12:03:18 +01:00
|
|
|
#include "term.h"
|
2004-08-27 20:06:15 +01:00
|
|
|
#include "termmap.h"
|
2005-05-19 15:43:32 +01:00
|
|
|
#include "arachne.h"
|
2005-06-07 16:02:27 +01:00
|
|
|
#include "switches.h"
|
2004-12-08 16:25:27 +00:00
|
|
|
#include <malloc.h>
|
2004-08-15 12:55:22 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
static System sys; //!< local storage of system pointer
|
|
|
|
int *graph = NULL; //!< graph data
|
|
|
|
int nodes = 0; //!< number of nodes in the graph
|
2004-12-08 16:25:27 +00:00
|
|
|
int graph_uordblks = 0;
|
2004-08-15 12:55:22 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
extern Protocol INTRUDER; //!< The intruder protocol
|
|
|
|
extern Role I_M; //!< special role; precedes all other events always
|
2004-08-18 20:43:58 +01:00
|
|
|
|
2004-12-09 13:23:26 +00:00
|
|
|
/*
|
|
|
|
* Forward declarations
|
|
|
|
*/
|
|
|
|
|
|
|
|
void goal_graph_destroy ();
|
|
|
|
|
2004-08-15 12:55:22 +01:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Assist stuff
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
//! Create mem for binding
|
|
|
|
Binding
|
2004-08-17 16:52:52 +01:00
|
|
|
binding_create (Term term, int run_to, int ev_to)
|
2004-08-15 12:55:22 +01:00
|
|
|
{
|
|
|
|
Binding b;
|
|
|
|
|
|
|
|
b = memAlloc (sizeof (struct binding));
|
2004-08-17 16:52:52 +01:00
|
|
|
b->done = 0;
|
2005-01-14 18:18:40 +00:00
|
|
|
b->blocked = 0;
|
2004-08-17 16:52:52 +01:00
|
|
|
b->run_from = -1;
|
|
|
|
b->ev_from = -1;
|
2004-08-15 12:55:22 +01:00
|
|
|
b->run_to = run_to;
|
|
|
|
b->ev_to = ev_to;
|
2005-05-17 19:45:01 +01:00
|
|
|
goal_graph_destroy ();
|
2004-08-17 12:03:18 +01:00
|
|
|
b->term = term;
|
2004-08-20 11:52:40 +01:00
|
|
|
b->level = 0;
|
2004-08-15 12:55:22 +01:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Remove mem for binding
|
|
|
|
void
|
|
|
|
binding_destroy (Binding b)
|
|
|
|
{
|
2004-08-17 16:52:52 +01:00
|
|
|
if (b->done)
|
2004-08-15 15:07:34 +01:00
|
|
|
{
|
2004-08-18 10:57:01 +01:00
|
|
|
goal_unbind (b);
|
2004-08-15 15:07:34 +01:00
|
|
|
}
|
2004-08-15 12:55:22 +01:00
|
|
|
memFree (b, sizeof (struct binding));
|
|
|
|
}
|
|
|
|
|
2005-08-12 13:13:50 +01:00
|
|
|
//! Test whether one event is ordered before another
|
|
|
|
/**
|
|
|
|
* Is only guaranteed to yield trustworthy results after a new graph is created, using
|
|
|
|
* goal_graph_create ()
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
isOrderedBefore (const int run1, const int ev1, const int run2, const int ev2)
|
|
|
|
{
|
|
|
|
return graph[graph_nodes (nodes, run2, ev2, run2, ev2)];
|
|
|
|
}
|
|
|
|
|
2004-08-15 12:55:22 +01:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Main
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
//! Init module
|
|
|
|
void
|
|
|
|
bindingInit (const System mysys)
|
|
|
|
{
|
|
|
|
sys = mysys;
|
|
|
|
sys->bindings = NULL;
|
2004-12-08 16:25:27 +00:00
|
|
|
graph = NULL;
|
|
|
|
nodes = 0;
|
|
|
|
graph_uordblks = 0;
|
2004-08-15 12:55:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Close up
|
|
|
|
void
|
|
|
|
bindingDone ()
|
|
|
|
{
|
|
|
|
int delete (Binding b)
|
|
|
|
{
|
|
|
|
binding_destroy (b);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
list_iterate (sys->bindings, delete);
|
|
|
|
list_destroy (sys->bindings);
|
|
|
|
}
|
|
|
|
|
2004-08-18 10:57:01 +01:00
|
|
|
//! Destroy graph
|
2004-08-18 15:06:14 +01:00
|
|
|
void
|
|
|
|
goal_graph_destroy ()
|
2004-08-18 10:57:01 +01:00
|
|
|
{
|
|
|
|
if (graph != NULL)
|
|
|
|
{
|
2004-12-08 16:25:27 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
struct mallinfo mi_free;
|
|
|
|
int mem_free;
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
mi_free = mallinfo ();
|
2004-12-08 16:25:27 +00:00
|
|
|
mem_free = mi_free.uordblks;
|
|
|
|
#endif
|
2004-08-18 10:57:01 +01:00
|
|
|
memFree (graph, (nodes * nodes) * sizeof (int));
|
|
|
|
graph = NULL;
|
2004-12-08 16:25:27 +00:00
|
|
|
#ifdef DEBUG
|
2005-05-17 19:45:01 +01:00
|
|
|
mi_free = mallinfo ();
|
2004-12-08 16:25:27 +00:00
|
|
|
if (mem_free - mi_free.uordblks != graph_uordblks)
|
2005-05-17 19:45:01 +01:00
|
|
|
error ("Freeing gave a weird result.");
|
2004-12-08 16:25:27 +00:00
|
|
|
#endif
|
|
|
|
graph_uordblks = 0;
|
|
|
|
nodes = 0;
|
2004-08-18 10:57:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
//! Compute unclosed graph
|
2004-08-18 15:06:14 +01:00
|
|
|
void
|
|
|
|
goal_graph_create ()
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
|
|
|
int run, ev;
|
2004-08-18 20:43:58 +01:00
|
|
|
int last_m;
|
2004-08-17 16:52:52 +01:00
|
|
|
List bl;
|
|
|
|
|
|
|
|
goal_graph_destroy ();
|
2004-08-18 15:06:14 +01:00
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
// Setup graph
|
|
|
|
nodes = node_count ();
|
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
{
|
|
|
|
struct mallinfo create_mi;
|
|
|
|
int create_mem_before;
|
|
|
|
|
|
|
|
if (graph_uordblks != 0)
|
|
|
|
error
|
|
|
|
("Trying to create graph stuff without 0 uordblks for it first, but it is %i.",
|
|
|
|
graph_uordblks);
|
|
|
|
create_mi = mallinfo ();
|
|
|
|
create_mem_before = create_mi.uordblks;
|
|
|
|
graph = memAlloc ((nodes * nodes) * sizeof (int));
|
|
|
|
create_mi = mallinfo ();
|
|
|
|
graph_uordblks = create_mi.uordblks - create_mem_before;
|
|
|
|
}
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
{
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
graph_fill (graph, nodes, 0);
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
// Setup run order
|
|
|
|
run = 0;
|
|
|
|
last_m = -1; // last I_M run
|
|
|
|
while (run < sys->maxruns)
|
|
|
|
{
|
|
|
|
ev = 1;
|
|
|
|
//!@todo This now reference to step, but we intend "length" as in Arachne.
|
|
|
|
while (ev < sys->runs[run].step)
|
|
|
|
{
|
|
|
|
graph[graph_nodes (nodes, run, ev - 1, run, ev)] = 1;
|
|
|
|
ev++;
|
|
|
|
}
|
|
|
|
// Enforce I_M ordering
|
|
|
|
if (sys->runs[run].protocol == INTRUDER && sys->runs[run].role == I_M)
|
|
|
|
{
|
|
|
|
if (last_m != -1)
|
|
|
|
{
|
|
|
|
graph[graph_nodes (nodes, last_m, 0, run, 0)] = 1;
|
|
|
|
}
|
|
|
|
last_m = run;
|
|
|
|
}
|
|
|
|
// Next
|
|
|
|
run++;
|
|
|
|
}
|
|
|
|
// Setup bindings order
|
|
|
|
bl = sys->bindings;
|
|
|
|
while (bl != NULL)
|
|
|
|
{
|
|
|
|
Binding b;
|
2004-12-08 16:25:27 +00:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
b = (Binding) bl->data;
|
|
|
|
if (valid_binding (b))
|
|
|
|
{
|
2004-08-17 16:52:52 +01:00
|
|
|
#ifdef DEBUG
|
2005-05-17 19:45:01 +01:00
|
|
|
if (graph_nodes
|
|
|
|
(nodes, b->run_from, b->ev_from, b->run_to,
|
|
|
|
b->ev_to) >= (nodes * nodes))
|
|
|
|
error ("Node out of scope for %i,%i -> %i,%i.\n", b->run_from,
|
|
|
|
b->ev_from, b->run_to, b->ev_to);
|
2004-08-17 16:52:52 +01:00
|
|
|
#endif
|
2005-05-17 19:45:01 +01:00
|
|
|
graph[graph_nodes
|
|
|
|
(nodes, b->run_from, b->ev_from, b->run_to, b->ev_to)] = 1;
|
|
|
|
}
|
|
|
|
bl = bl->next;
|
|
|
|
}
|
|
|
|
// Setup local constants order
|
|
|
|
run = 0;
|
|
|
|
while (run < sys->maxruns)
|
|
|
|
{
|
|
|
|
if (sys->runs[run].protocol != INTRUDER)
|
|
|
|
{
|
|
|
|
int run2;
|
|
|
|
|
|
|
|
run2 = 0;
|
|
|
|
while (run2 < sys->maxruns)
|
|
|
|
{
|
|
|
|
if (sys->runs[run].protocol != INTRUDER && run != run2)
|
|
|
|
{
|
|
|
|
// For these two runs, we check whether run has any variables that are mapped
|
|
|
|
// to constants from run2
|
|
|
|
Termlist tl;
|
|
|
|
|
|
|
|
tl = sys->runs[run].locals;
|
|
|
|
while (tl != NULL)
|
|
|
|
{
|
|
|
|
Term t;
|
|
|
|
|
|
|
|
t = tl->term;
|
|
|
|
if (t->type == VARIABLE && TermRunid (t) == run
|
|
|
|
&& t->subst != NULL)
|
|
|
|
{
|
|
|
|
// t is a variable of run
|
|
|
|
Termlist tl2;
|
|
|
|
|
|
|
|
tl2 = sys->runs[run2].locals;
|
|
|
|
while (tl2 != NULL)
|
|
|
|
{
|
|
|
|
Term t2;
|
|
|
|
|
|
|
|
t2 = tl2->term;
|
|
|
|
if (realTermLeaf (t2) && t2->type != VARIABLE
|
|
|
|
&& TermRunid (t2) == run2)
|
|
|
|
{
|
|
|
|
// t2 is a constant of run2
|
|
|
|
if (isTermEqual (t, t2))
|
|
|
|
{
|
|
|
|
// Indeed, run depends on the run2 constant t2. Thus we must store this order.
|
|
|
|
// The first send of t2 in run2 must be before the first (read) event in run with t2.
|
|
|
|
int ev2;
|
|
|
|
int done;
|
|
|
|
Roledef rd2;
|
|
|
|
|
|
|
|
done = 0;
|
|
|
|
ev2 = 0;
|
|
|
|
rd2 = sys->runs[run2].start;
|
|
|
|
while (!done
|
|
|
|
&& ev2 < sys->runs[run2].step)
|
|
|
|
{
|
|
|
|
if (rd2->type == SEND
|
|
|
|
&& termSubTerm (rd2->message,
|
|
|
|
t2))
|
|
|
|
{
|
|
|
|
// Allright, we send it here at ev2 first
|
|
|
|
int ev;
|
|
|
|
Roledef rd;
|
|
|
|
|
|
|
|
ev = 0;
|
|
|
|
rd = sys->runs[run].start;
|
|
|
|
while (!done
|
|
|
|
&& ev <
|
|
|
|
sys->runs[run].step)
|
|
|
|
{
|
|
|
|
if (termSubTerm
|
|
|
|
(rd->message, t2))
|
|
|
|
{
|
|
|
|
// Term occurs here in run
|
|
|
|
if (rd->type == READ)
|
|
|
|
{
|
|
|
|
// It's read here first.
|
|
|
|
// Order and be done with it.
|
|
|
|
graph[graph_nodes
|
|
|
|
(nodes,
|
|
|
|
run2, ev2,
|
|
|
|
run, ev)] =
|
|
|
|
1;
|
2004-12-08 16:25:27 +00:00
|
|
|
#ifdef DEBUG
|
2005-05-17 19:45:01 +01:00
|
|
|
if (DEBUGL (5))
|
|
|
|
{
|
|
|
|
eprintf
|
|
|
|
("* [local originator] term ");
|
|
|
|
termPrint
|
|
|
|
(t2);
|
|
|
|
eprintf
|
|
|
|
(" is bound using %i, %i before %i,%i\n",
|
|
|
|
run2, ev2,
|
|
|
|
run, ev);
|
|
|
|
}
|
2004-08-30 14:57:16 +01:00
|
|
|
#endif
|
2005-05-17 19:45:01 +01:00
|
|
|
done = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// It doesn't occur first in a READ, which shouldn't be happening
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.
|
|
|
|
output ==
|
2005-05-17 19:45:01 +01:00
|
|
|
PROOF)
|
|
|
|
{
|
|
|
|
eprintf
|
|
|
|
("Term ");
|
|
|
|
termPrint
|
|
|
|
(t2);
|
|
|
|
eprintf
|
|
|
|
(" from run %i occurs in run %i, term ",
|
|
|
|
run2, run);
|
|
|
|
termPrint (t);
|
|
|
|
eprintf
|
|
|
|
(" before it is read?\n");
|
|
|
|
}
|
|
|
|
// Thus, we create an artificial loop
|
|
|
|
if (sys->runs[0].
|
|
|
|
step > 1)
|
|
|
|
{
|
|
|
|
// This forces a loop, and thus prunes
|
|
|
|
graph
|
|
|
|
[graph_nodes
|
|
|
|
(nodes, 0,
|
|
|
|
1, 0,
|
|
|
|
0)] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rd = rd->next;
|
|
|
|
ev++;
|
|
|
|
}
|
|
|
|
done = 1;
|
|
|
|
}
|
|
|
|
rd2 = rd2->next;
|
|
|
|
ev2++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tl2 = tl2->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tl = tl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
run2++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
run++;
|
|
|
|
}
|
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-15 12:55:22 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Externally available functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2004-08-15 15:07:34 +01:00
|
|
|
//! Yield node count
|
|
|
|
int
|
|
|
|
node_count ()
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
int run;
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
for (run = 0; run < sys->maxruns; run++)
|
|
|
|
{
|
|
|
|
//!@todo This now reference to step, but we intend "length" as in Arachne.
|
|
|
|
count = count + sys->runs[run].step;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Yield node number given run, ev
|
|
|
|
__inline__ int
|
|
|
|
node_number (int run, int ev)
|
|
|
|
{
|
|
|
|
int node;
|
|
|
|
|
|
|
|
node = ev;
|
|
|
|
while (run > 0)
|
|
|
|
{
|
2004-08-15 15:57:50 +01:00
|
|
|
run--;
|
2004-08-15 15:07:34 +01:00
|
|
|
//!@todo This now reference to step, but we intend "length" as in Arachne.
|
|
|
|
node = node + sys->runs[run].step;
|
|
|
|
}
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Yield graph index, given node1, node2 numbers
|
|
|
|
__inline__ int
|
2004-08-17 16:52:52 +01:00
|
|
|
graph_index (const int node1, const int node2)
|
2004-08-15 15:07:34 +01:00
|
|
|
{
|
|
|
|
return ((node1 * nodes) + node2);
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Yield graph index, given (node1), (node2) tuples
|
|
|
|
__inline__ int
|
|
|
|
graph_nodes (const int nodes, const int run1, const int ev1, const int run2,
|
|
|
|
const int ev2)
|
|
|
|
{
|
|
|
|
int node1;
|
|
|
|
int node2;
|
|
|
|
|
|
|
|
node1 = node_number (run1, ev1);
|
2004-08-16 14:18:04 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (node1 < 0 || node1 >= nodes)
|
|
|
|
error ("node_number %i out of scope %i for %i,%i.", node1, nodes, run1,
|
|
|
|
ev1);
|
|
|
|
#endif
|
2004-08-15 15:07:34 +01:00
|
|
|
node2 = node_number (run2, ev2);
|
2004-08-16 14:18:04 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (node2 < 0 || node2 >= nodes)
|
|
|
|
error ("node_number %i out of scope %i for %i,%i.", node2, nodes, run2,
|
|
|
|
ev2);
|
|
|
|
#endif
|
2004-08-17 16:52:52 +01:00
|
|
|
return graph_index (node1, node2);
|
2004-08-15 15:07:34 +01:00
|
|
|
}
|
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
//! Print a binding (given a binding list pointer)
|
2004-08-15 15:07:34 +01:00
|
|
|
int
|
2004-08-18 15:06:14 +01:00
|
|
|
binding_print (const Binding b)
|
2004-08-15 15:07:34 +01:00
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
if (b->done)
|
|
|
|
eprintf ("Binding (%i,%i) --( ", b->run_from, b->ev_from);
|
|
|
|
else
|
|
|
|
eprintf ("Unbound --( ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf (" )->> (%i,%i)", b->run_to, b->ev_to);
|
2005-01-14 18:18:40 +00:00
|
|
|
if (b->blocked)
|
|
|
|
eprintf ("[blocked]");
|
2004-08-17 16:52:52 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2004-08-15 15:07:34 +01:00
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
|
|
|
|
//! Add a goal
|
2004-08-20 11:52:40 +01:00
|
|
|
/**
|
|
|
|
* The int parameter 'level' is just to store additional info. Here, it stores priorities for a goal.
|
|
|
|
* Higher level goals will be selected first. Typically, a normal goal is level 0, a key is 1.
|
|
|
|
*/
|
2004-10-18 14:04:34 +01:00
|
|
|
int
|
2004-08-20 11:52:40 +01:00
|
|
|
goal_add (Term term, const int run, const int ev, const int level)
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
|
|
|
term = deVar (term);
|
2004-08-18 16:46:33 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (term == NULL)
|
2004-08-18 20:43:58 +01:00
|
|
|
error ("Trying to add an emtpy goal term");
|
2004-08-18 16:46:33 +01:00
|
|
|
if (run >= sys->maxruns)
|
2004-08-18 20:43:58 +01:00
|
|
|
error ("Trying to add a goal for a run that does not exist.");
|
2004-08-18 16:46:33 +01:00
|
|
|
if (ev >= sys->runs[run].step)
|
2004-08-18 20:43:58 +01:00
|
|
|
error
|
|
|
|
("Trying to add a goal for an event that is not in the semistate yet.");
|
2004-08-18 16:46:33 +01:00
|
|
|
#endif
|
2004-08-17 16:52:52 +01:00
|
|
|
if (realTermTuple (term))
|
2004-08-15 15:07:34 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
return goal_add (TermOp1 (term), run, ev, level) +
|
|
|
|
goal_add (TermOp2 (term), run, ev, level);
|
2004-08-15 15:07:34 +01:00
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
else
|
2004-08-15 15:07:34 +01:00
|
|
|
{
|
2004-10-18 14:04:34 +01:00
|
|
|
// Determine whether we already had it
|
|
|
|
int nope;
|
2004-08-15 15:07:34 +01:00
|
|
|
|
2004-10-18 14:04:34 +01:00
|
|
|
int testSame (void *data)
|
2004-11-16 12:07:55 +00:00
|
|
|
{
|
|
|
|
Binding b;
|
|
|
|
|
|
|
|
b = (Binding) data;
|
|
|
|
if (isTermEqual (b->term, term) && run == b->run_to && ev == b->ev_to)
|
|
|
|
{ // abort scan, report
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // proceed with scan
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2004-10-18 14:04:34 +01:00
|
|
|
|
|
|
|
nope = list_iterate (sys->bindings, testSame);
|
|
|
|
if (nope)
|
|
|
|
{
|
|
|
|
// Add a new binding
|
|
|
|
Binding b;
|
|
|
|
b = binding_create (term, run, ev);
|
|
|
|
b->level = level;
|
|
|
|
sys->bindings = list_insert (sys->bindings, b);
|
2005-05-17 19:45:01 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (3))
|
|
|
|
{
|
|
|
|
eprintf ("Adding new binding for ");
|
|
|
|
termPrint (term);
|
|
|
|
eprintf (" to run %i, ev %i.\n", run, ev);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 1;
|
2004-10-18 14:04:34 +01:00
|
|
|
}
|
2004-08-15 15:07:34 +01:00
|
|
|
}
|
2005-05-17 19:45:01 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Add a goal, and bind it immediately.
|
|
|
|
// If the result is negative, no goals will have been added, as the resulting state must be pruned (cycle) */
|
|
|
|
int
|
|
|
|
goal_add_fixed (Term term, const int run, const int ev, const int fromrun,
|
|
|
|
const int fromev)
|
|
|
|
{
|
|
|
|
int newgoals, n;
|
|
|
|
List l;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
newgoals = goal_add (term, run, ev, 0);
|
|
|
|
l = sys->bindings;
|
|
|
|
n = newgoals;
|
|
|
|
res = 1;
|
|
|
|
while (res != 0 && n > 0 && l != NULL)
|
|
|
|
{
|
|
|
|
Binding b;
|
|
|
|
|
|
|
|
b = (Binding) l->data;
|
|
|
|
if (b->done)
|
|
|
|
{
|
|
|
|
globalError++;
|
|
|
|
binding_print (b);
|
|
|
|
error (" problem with new fixed binding!");
|
|
|
|
}
|
|
|
|
res = goal_bind (b, fromrun, fromev); // returns 0 if it must be pruned
|
|
|
|
l = l->next;
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
if (res != 0)
|
|
|
|
{
|
|
|
|
return newgoals;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
goal_remove_last (newgoals);
|
|
|
|
return -1;
|
|
|
|
}
|
2004-08-15 15:07:34 +01:00
|
|
|
}
|
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
//! Remove a goal
|
|
|
|
void
|
2004-10-18 14:04:34 +01:00
|
|
|
goal_remove_last (int n)
|
2004-08-15 18:50:41 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
while (n > 0)
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
if (sys->bindings != NULL)
|
|
|
|
{
|
|
|
|
Binding b;
|
2004-10-18 14:04:34 +01:00
|
|
|
|
2005-05-17 19:45:01 +01:00
|
|
|
b = (Binding) sys->bindings->data;
|
|
|
|
binding_destroy (b);
|
|
|
|
sys->bindings = list_delete (sys->bindings);
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error
|
|
|
|
("goal_remove_last error: trying to remove %i too many bindings.",
|
|
|
|
n);
|
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
}
|
2004-08-15 18:50:41 +01:00
|
|
|
}
|
2004-08-15 15:07:34 +01:00
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
//! Bind a goal (0 if it must be pruned)
|
2004-08-15 12:55:22 +01:00
|
|
|
int
|
2004-08-17 16:52:52 +01:00
|
|
|
goal_bind (const Binding b, const int run, const int ev)
|
2004-08-15 12:55:22 +01:00
|
|
|
{
|
2005-01-14 18:18:40 +00:00
|
|
|
if (b->blocked)
|
|
|
|
{
|
|
|
|
error ("Trying to bind a blocked goal.");
|
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
if (!b->done)
|
2004-08-15 17:08:53 +01:00
|
|
|
{
|
2004-08-18 16:46:33 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (run >= sys->maxruns || sys->runs[run].step <= ev)
|
|
|
|
error ("Trying to bind to something not yet in the semistate.");
|
|
|
|
#endif
|
2004-08-17 16:52:52 +01:00
|
|
|
b->done = 1;
|
|
|
|
b->run_from = run;
|
|
|
|
b->ev_from = ev;
|
2005-01-14 18:18:40 +00:00
|
|
|
goal_graph_create ();
|
2004-08-17 16:52:52 +01:00
|
|
|
return warshall (graph, nodes);
|
2004-08-15 17:08:53 +01:00
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
else
|
|
|
|
{
|
2005-05-17 19:45:01 +01:00
|
|
|
globalError++;
|
|
|
|
binding_print (b);
|
2004-08-17 16:52:52 +01:00
|
|
|
error ("Trying to bind a bound goal again.");
|
|
|
|
}
|
|
|
|
}
|
2004-08-15 15:07:34 +01:00
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
//! Unbind a goal
|
|
|
|
void
|
|
|
|
goal_unbind (const Binding b)
|
|
|
|
{
|
|
|
|
if (b->done)
|
2004-08-16 14:18:04 +01:00
|
|
|
{
|
2004-08-17 16:52:52 +01:00
|
|
|
goal_graph_destroy (b);
|
|
|
|
b->done = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error ("Trying to unbind an unbound goal again.");
|
2004-08-16 14:18:04 +01:00
|
|
|
}
|
2004-08-15 12:55:22 +01:00
|
|
|
}
|
|
|
|
|
2005-01-14 18:18:40 +00:00
|
|
|
//! Bind a goal as a dummy (block)
|
|
|
|
/**
|
|
|
|
* Especially made for tuple expansion
|
|
|
|
*/
|
2005-05-17 19:45:01 +01:00
|
|
|
int
|
|
|
|
binding_block (Binding b)
|
2005-01-14 18:18:40 +00:00
|
|
|
{
|
|
|
|
if (!b->blocked)
|
|
|
|
{
|
|
|
|
b->blocked = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error ("Trying to block a goal again.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Unblock a binding
|
2005-05-17 19:45:01 +01:00
|
|
|
int
|
|
|
|
binding_unblock (Binding b)
|
2005-01-14 18:18:40 +00:00
|
|
|
{
|
|
|
|
if (b->blocked)
|
|
|
|
{
|
|
|
|
b->blocked = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
error ("Trying to unblock a non-blocked goal.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-27 20:06:15 +01:00
|
|
|
//! Determine whether some label set is ordered w.r.t. send/read order.
|
|
|
|
/**
|
|
|
|
* Assumes all these labels exist in the system, within length etc, and that the run mappings are valid.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
labels_ordered (Termmap runs, Termlist labels)
|
|
|
|
{
|
|
|
|
goal_graph_create ();
|
2004-10-28 16:23:16 +01:00
|
|
|
if (warshall (graph, nodes) == 0)
|
|
|
|
{
|
|
|
|
error ("Testing ordering of label set for a graph with a cycle.");
|
|
|
|
}
|
2004-08-28 14:47:37 +01:00
|
|
|
|
2004-08-27 20:06:15 +01:00
|
|
|
while (labels != NULL)
|
|
|
|
{
|
|
|
|
// Given this label, and the mapping of runs, we want to know if the order is okay. Thus, we need to know sendrole and readrole
|
|
|
|
Labelinfo linfo;
|
|
|
|
int send_run, send_ev, read_run, read_ev;
|
|
|
|
|
|
|
|
int get_index (const int run)
|
|
|
|
{
|
|
|
|
Roledef rd;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
rd = sys->runs[run].start;
|
|
|
|
while (rd != NULL && !isTermEqual (rd->label, labels->term))
|
|
|
|
{
|
|
|
|
rd = rd->next;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (rd == NULL)
|
|
|
|
error
|
|
|
|
("Could not locate send or read for label, after niagree holds, to test for order.");
|
|
|
|
#endif
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
linfo = label_find (sys->labellist, labels->term);
|
|
|
|
send_run = termmapGet (runs, linfo->sendrole);
|
|
|
|
read_run = termmapGet (runs, linfo->readrole);
|
|
|
|
send_ev = get_index (send_run);
|
|
|
|
read_ev = get_index (read_run);
|
|
|
|
if (graph[graph_nodes (nodes, send_run, send_ev, read_run, read_ev)] ==
|
|
|
|
0)
|
|
|
|
{
|
|
|
|
// Not ordered; false
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Proceed
|
|
|
|
labels = labels->next;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-01-14 18:18:40 +00:00
|
|
|
//! Check whether the binding denotes a sensible thing such that we can use run_from and ev_from
|
2005-05-17 19:45:01 +01:00
|
|
|
int
|
|
|
|
valid_binding (Binding b)
|
2005-01-14 18:18:40 +00:00
|
|
|
{
|
|
|
|
if (b->done && !b->blocked)
|
2005-05-17 19:45:01 +01:00
|
|
|
return 1;
|
2005-01-14 18:18:40 +00:00
|
|
|
else
|
2005-05-17 19:45:01 +01:00
|
|
|
return 0;
|
2005-01-14 18:18:40 +00:00
|
|
|
}
|
|
|
|
|
2005-10-08 21:57:39 +01:00
|
|
|
//! Check for unique origination
|
|
|
|
/*
|
|
|
|
* Contrary to a previous version, we simply check for unique origination.
|
|
|
|
* This immediately takes care of any 'occurs before' things. Complexity is N
|
|
|
|
* log N.
|
|
|
|
*
|
|
|
|
* Each term should originate only at one point (thus in one binding)
|
|
|
|
*
|
|
|
|
*@returns True, if it's okay. If false, it needs to be pruned.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
unique_origination ()
|
|
|
|
{
|
|
|
|
List bl;
|
|
|
|
|
|
|
|
bl = sys->bindings;
|
|
|
|
|
|
|
|
while (bl != NULL)
|
|
|
|
{
|
|
|
|
Binding b;
|
|
|
|
|
|
|
|
b = (Binding) bl->data;
|
|
|
|
// Check for a valid binding; it has to be 'done' and sensibly bound (not as in tuple expanded stuff)
|
|
|
|
if (valid_binding (b))
|
|
|
|
{
|
|
|
|
Termlist terms;
|
|
|
|
|
|
|
|
terms = tuple_to_termlist (b->term);
|
|
|
|
if (terms != NULL)
|
|
|
|
{
|
|
|
|
/* Apparently this is a good term.
|
|
|
|
* Now we check whether it occurs in any previous bindings as well.
|
|
|
|
*/
|
|
|
|
|
|
|
|
List bl2;
|
|
|
|
|
|
|
|
bl2 = sys->bindings;
|
|
|
|
while (bl2 != bl)
|
|
|
|
{
|
|
|
|
Binding b2;
|
|
|
|
|
|
|
|
b2 = (Binding) bl2->data;
|
|
|
|
if (valid_binding (b2))
|
|
|
|
{
|
|
|
|
Termlist terms2, sharedterms;
|
|
|
|
|
|
|
|
terms2 = tuple_to_termlist (b2->term);
|
|
|
|
sharedterms = termlistConjunct (terms, terms2);
|
|
|
|
|
|
|
|
// Compare terms
|
|
|
|
if (sharedterms != NULL)
|
|
|
|
{
|
|
|
|
// Apparently, this binding shares a term.
|
|
|
|
// Equal terms should originate at the same point
|
|
|
|
if (b->run_from != b2->run_from ||
|
|
|
|
b->ev_from != b2->ev_from)
|
|
|
|
{
|
|
|
|
// Not equal: thus no unique origination.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
termlistDelete (terms2);
|
|
|
|
termlistDelete (sharedterms);
|
|
|
|
}
|
|
|
|
bl2 = bl2->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
termlistDelete (terms);
|
|
|
|
}
|
|
|
|
bl = bl->next;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
//! Prune invalid state w.r.t. <=C minimal requirement
|
2004-08-15 12:55:22 +01:00
|
|
|
/**
|
2004-08-17 16:52:52 +01:00
|
|
|
* Intuition says this can be done a lot more efficient. Luckily this is the prototype.
|
|
|
|
*
|
|
|
|
*@returns True, if it's okay. If false, it needs to be pruned.
|
2004-08-15 12:55:22 +01:00
|
|
|
*/
|
2004-08-18 15:06:14 +01:00
|
|
|
int
|
|
|
|
bindings_c_minimal ()
|
2004-08-15 12:55:22 +01:00
|
|
|
{
|
2004-08-17 16:52:52 +01:00
|
|
|
List bl;
|
2004-08-15 12:55:22 +01:00
|
|
|
|
2006-02-22 08:55:42 +00:00
|
|
|
if (switches.experimental & 1 > 0)
|
2005-10-08 21:57:39 +01:00
|
|
|
{
|
|
|
|
if (unique_origination () == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-08 14:51:40 +01:00
|
|
|
// Ensure a fresh state graph
|
|
|
|
goal_graph_create ();
|
|
|
|
// Recompute closure; does that work?
|
|
|
|
if (!warshall (graph, nodes))
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
2005-06-08 14:51:40 +01:00
|
|
|
List l;
|
2005-05-17 19:45:01 +01:00
|
|
|
|
2005-06-08 14:51:40 +01:00
|
|
|
globalError++;
|
|
|
|
l = sys->bindings;
|
|
|
|
while (l != NULL)
|
|
|
|
{
|
|
|
|
Binding b;
|
2005-05-17 19:45:01 +01:00
|
|
|
|
2005-06-08 14:51:40 +01:00
|
|
|
b = (Binding) l->data;
|
|
|
|
binding_print (b);
|
|
|
|
eprintf ("\n");
|
|
|
|
l = l->next;
|
2004-08-18 15:06:14 +01:00
|
|
|
}
|
2005-06-08 14:51:40 +01:00
|
|
|
error ("Detected a cycle when testing for c-minimality");
|
2004-08-18 15:06:14 +01:00
|
|
|
}
|
|
|
|
|
2004-08-17 16:52:52 +01:00
|
|
|
// For all goals
|
|
|
|
bl = sys->bindings;
|
|
|
|
while (bl != NULL)
|
2004-08-15 13:24:27 +01:00
|
|
|
{
|
2004-08-17 16:52:52 +01:00
|
|
|
Binding b;
|
|
|
|
|
|
|
|
b = (Binding) bl->data;
|
2005-01-14 18:18:40 +00:00
|
|
|
// Check for a valid binding; it has to be 'done' and sensibly bound (not as in tuple expanded stuff)
|
2005-05-17 19:45:01 +01:00
|
|
|
if (valid_binding (b))
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
int run;
|
|
|
|
int node_from;
|
2004-08-17 16:52:52 +01:00
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
node_from = node_number (b->run_from, b->ev_from);
|
|
|
|
// Find all preceding events
|
2004-08-18 16:46:33 +01:00
|
|
|
for (run = 0; run < sys->maxruns; run++)
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
int ev;
|
2004-08-17 16:52:52 +01:00
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
//!@todo hardcoded reference to step, should be length
|
2004-08-18 16:46:33 +01:00
|
|
|
for (ev = 0; ev < sys->runs[run].step; ev++)
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
int node_comp;
|
2004-08-17 16:52:52 +01:00
|
|
|
|
2004-08-18 15:06:14 +01:00
|
|
|
node_comp = node_number (run, ev);
|
|
|
|
if (graph[graph_index (node_comp, node_from)] > 0)
|
2004-08-17 16:52:52 +01:00
|
|
|
{
|
2004-08-18 15:06:14 +01:00
|
|
|
// this node is *before* the from node
|
|
|
|
Roledef rd;
|
|
|
|
|
|
|
|
rd = roledef_shift (sys->runs[run].start, ev);
|
2004-08-18 19:41:49 +01:00
|
|
|
if (termInTerm (rd->message, b->term))
|
2004-08-18 15:06:14 +01:00
|
|
|
{
|
|
|
|
// This term already occurs as interm in a previous node!
|
2005-05-19 15:43:32 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (4))
|
|
|
|
{
|
|
|
|
// Report this
|
|
|
|
indentPrint ();
|
|
|
|
eprintf ("Binding for ");
|
|
|
|
termPrint (b->term);
|
|
|
|
eprintf
|
|
|
|
(" at r%i i%i is not c-minimal because it occurred before at r%i i%i in ",
|
|
|
|
b->run_from, b->ev_from, run, ev);
|
|
|
|
termPrint (rd->message);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
#endif
|
2004-08-18 15:06:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bl = bl->next;
|
2004-08-15 13:24:27 +01:00
|
|
|
}
|
2004-08-17 16:52:52 +01:00
|
|
|
return 1;
|
2004-08-15 12:55:22 +01:00
|
|
|
}
|