2004-05-15 16:26:21 +01:00
|
|
|
/**
|
|
|
|
*@file main.c
|
|
|
|
* \brief The main file.
|
|
|
|
*
|
|
|
|
* Contains the main switch handling, and passes everything to the core logic.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \mainpage
|
|
|
|
*
|
|
|
|
* \section intro Introduction
|
|
|
|
*
|
|
|
|
* Scyther is a model checker for security protocols.
|
|
|
|
*
|
|
|
|
* \section install Installation
|
|
|
|
*
|
|
|
|
* How to install Scyther.
|
2004-05-15 16:45:08 +01:00
|
|
|
*
|
2004-05-26 20:40:40 +01:00
|
|
|
* \section exit Exit codes
|
|
|
|
*
|
|
|
|
* 0 Okay No attack found, claims encountered
|
2004-07-28 13:22:40 +01:00
|
|
|
*
|
2004-07-28 13:03:42 +01:00
|
|
|
* 1 Error Something went wrong (error) E.g. switch error, or scenario ran out.
|
2004-07-28 13:22:40 +01:00
|
|
|
*
|
2004-05-26 20:40:40 +01:00
|
|
|
* 2 Okay No attack found (because) no claims encountered
|
2004-07-28 13:22:40 +01:00
|
|
|
*
|
2004-05-26 20:40:40 +01:00
|
|
|
* 3 Okay Attack found
|
|
|
|
*
|
2004-07-28 13:22:40 +01:00
|
|
|
* However, if the --scenario=-1 switch is used, the exit code is used to return the number of scenarios.
|
|
|
|
*
|
2004-05-26 20:40:40 +01:00
|
|
|
* \section coding Coding conventions
|
2004-05-15 16:45:08 +01:00
|
|
|
*
|
|
|
|
* Usually, each source file except main.c has an myfileInit() and myfileDone() function
|
|
|
|
* available. These allow any initialisation and destruction of required structures.
|
|
|
|
*
|
|
|
|
* GNU indent rules are used, but K&R derivatives are allowed as well. Conversion can
|
|
|
|
* be done for any style using the GNU indent program.
|
2004-05-15 16:26:21 +01:00
|
|
|
*/
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <limits.h>
|
2004-07-24 16:08:35 +01:00
|
|
|
#include "system.h"
|
2004-04-23 11:58:43 +01:00
|
|
|
#include "debug.h"
|
|
|
|
#include "modelchecker.h"
|
|
|
|
#include "memory.h"
|
2004-07-24 20:07:29 +01:00
|
|
|
#include "symbol.h"
|
2004-04-23 11:58:43 +01:00
|
|
|
#include "pheading.h"
|
2004-07-24 20:07:29 +01:00
|
|
|
#include "symbol.h"
|
2004-05-21 20:31:42 +01:00
|
|
|
#include "parser.h"
|
2004-04-23 11:58:43 +01:00
|
|
|
#include "tac.h"
|
2005-01-05 15:29:27 +00:00
|
|
|
#include "timer.h"
|
2004-04-23 11:58:43 +01:00
|
|
|
#include "compiler.h"
|
|
|
|
#include "latex.h"
|
|
|
|
#include "output.h"
|
2004-08-15 12:55:22 +01:00
|
|
|
#include "binding.h"
|
2005-04-10 16:30:47 +01:00
|
|
|
#include "switches.h"
|
2005-06-16 15:10:07 +01:00
|
|
|
#include "specialterm.h"
|
2005-12-28 15:27:22 +00:00
|
|
|
#include "color.h"
|
2006-01-02 21:06:08 +00:00
|
|
|
#include "error.h"
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
//! The global system state pointer
|
2004-08-09 22:43:55 +01:00
|
|
|
System sys;
|
|
|
|
|
2006-01-02 21:06:08 +00:00
|
|
|
//! Pointer to the tac node container
|
2004-04-23 11:58:43 +01:00
|
|
|
extern struct tacnode *spdltac;
|
2006-01-02 21:06:08 +00:00
|
|
|
//! Match mode
|
2004-08-15 17:44:54 +01:00
|
|
|
extern int mgu_match;
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
void scanner_cleanup (void);
|
|
|
|
void strings_cleanup (void);
|
|
|
|
int yyparse (void);
|
|
|
|
|
|
|
|
void MC_incRuns (const System sys);
|
|
|
|
void MC_incTraces (const System sys);
|
|
|
|
void MC_single (const System sys);
|
|
|
|
int modelCheck (const System sys);
|
|
|
|
|
2004-05-14 18:29:26 +01:00
|
|
|
//! The main body, as called by the environment.
|
2004-04-23 11:58:43 +01:00
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
|
|
|
{
|
|
|
|
int nerrors;
|
2004-08-24 14:09:39 +01:00
|
|
|
int exitcode = EXIT_NOATTACK;
|
2004-04-23 11:58:43 +01:00
|
|
|
|
|
|
|
/* Initialize memory routines */
|
|
|
|
memInit ();
|
|
|
|
|
|
|
|
/* initialize symbols */
|
|
|
|
termsInit ();
|
2004-06-14 10:15:42 +01:00
|
|
|
termmapsInit ();
|
2004-04-23 11:58:43 +01:00
|
|
|
termlistsInit ();
|
|
|
|
knowledgeInit ();
|
|
|
|
symbolsInit ();
|
|
|
|
tacInit ();
|
|
|
|
|
2004-07-28 12:39:08 +01:00
|
|
|
/*
|
|
|
|
* ------------------------------------------------
|
2004-08-09 11:05:58 +01:00
|
|
|
* generate system
|
2004-07-28 12:39:08 +01:00
|
|
|
* ------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
/* process any command-line switches */
|
|
|
|
switchesInit (argc, argv);
|
2004-07-29 14:15:29 +01:00
|
|
|
|
2005-12-28 15:27:22 +00:00
|
|
|
/* process colors */
|
|
|
|
colorInit ();
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
/* start system */
|
|
|
|
sys = systemInit ();
|
2004-07-26 13:43:19 +01:00
|
|
|
|
2005-04-10 16:30:47 +01:00
|
|
|
/* init compiler for this system */
|
|
|
|
compilerInit (sys);
|
2004-07-19 10:32:12 +01:00
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
sys->know = emptyKnowledge ();
|
|
|
|
|
2004-08-09 10:42:58 +01:00
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
/* parse input */
|
|
|
|
|
|
|
|
yyparse ();
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (1))
|
|
|
|
tacPrint (spdltac);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* compile */
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.engine != ARACHNE_ENGINE)
|
2004-08-16 15:49:41 +01:00
|
|
|
{
|
|
|
|
// Compile as many runs as possible
|
2005-06-07 16:02:27 +01:00
|
|
|
compile (spdltac, switches.runs);
|
2004-08-16 15:49:41 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Compile no runs for Arachne
|
|
|
|
compile (spdltac, 0);
|
|
|
|
}
|
2004-04-23 11:58:43 +01:00
|
|
|
scanner_cleanup ();
|
|
|
|
|
2004-06-14 23:08:47 +01:00
|
|
|
/* preprocess */
|
|
|
|
preprocess (sys);
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (1))
|
|
|
|
{
|
|
|
|
printf ("\nCompilation yields:\n\n");
|
|
|
|
printf ("untrusted agents: ");
|
|
|
|
termlistPrint (sys->untrusted);
|
|
|
|
printf ("\n");
|
|
|
|
knowledgePrint (sys->know);
|
|
|
|
printf ("inverses: ");
|
|
|
|
knowledgeInversesPrint (sys->know);
|
|
|
|
printf ("\n");
|
|
|
|
locVarPrint (sys->locals);
|
|
|
|
protocolsPrint (sys->protocols);
|
|
|
|
|
|
|
|
printf ("\nInstantiated runs:\n\n");
|
|
|
|
runsPrint (sys);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* allocate memory for traces, based on runs */
|
|
|
|
systemStart (sys);
|
|
|
|
sys->traceKnow[0] = sys->know; // store initial knowledge
|
|
|
|
|
|
|
|
/* add parameters to system */
|
|
|
|
|
2004-07-29 11:13:13 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ---------------------------------------
|
|
|
|
* Switches consistency checking.
|
|
|
|
* ---------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Latex only makes sense for attacks */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.latex && switches.output != ATTACK)
|
2004-07-29 11:13:13 +01:00
|
|
|
{
|
|
|
|
error ("Scyther can only generate LaTeX output for attacks.");
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
2004-10-18 14:49:20 +01:00
|
|
|
if (DEBUGL (4))
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
warning ("Selected output method is %i", switches.output);
|
2004-10-18 14:49:20 +01:00
|
|
|
}
|
2004-07-29 11:13:13 +01:00
|
|
|
#endif
|
2004-08-11 12:22:20 +01:00
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.engine == ARACHNE_ENGINE)
|
2004-08-11 12:22:20 +01:00
|
|
|
{
|
2004-08-11 15:09:12 +01:00
|
|
|
arachneInit (sys);
|
2004-08-11 12:22:20 +01:00
|
|
|
}
|
2004-07-29 11:13:13 +01:00
|
|
|
/*
|
|
|
|
* ---------------------------------------
|
|
|
|
* Start real stuff
|
|
|
|
* ---------------------------------------
|
|
|
|
*/
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2005-05-03 10:45:54 +01:00
|
|
|
/* xml init */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.xml)
|
2005-05-03 10:45:54 +01:00
|
|
|
xmlOutInit ();
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
/* latex header? */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.latex)
|
2004-04-23 11:58:43 +01:00
|
|
|
latexInit (sys, argc, argv);
|
|
|
|
|
|
|
|
/* model check system */
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (DEBUGL (1))
|
2004-07-29 11:13:13 +01:00
|
|
|
warning ("Start modelchecking system.");
|
2004-04-23 11:58:43 +01:00
|
|
|
#endif
|
2005-04-10 16:30:47 +01:00
|
|
|
MC_single (sys);
|
2004-08-09 11:05:58 +01:00
|
|
|
|
2004-08-09 11:41:25 +01:00
|
|
|
/*
|
|
|
|
* ---------------------------------------
|
|
|
|
* After checking the system, results
|
|
|
|
* ---------------------------------------
|
|
|
|
*/
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
/* Display shortest attack, if any */
|
|
|
|
|
|
|
|
if (sys->attack != NULL && sys->attack->length != 0)
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == ATTACK)
|
2004-07-29 11:13:13 +01:00
|
|
|
{
|
2004-08-09 11:05:58 +01:00
|
|
|
attackDisplay (sys);
|
2004-07-29 11:13:13 +01:00
|
|
|
}
|
2004-05-26 20:40:40 +01:00
|
|
|
/* mark exit code */
|
2004-08-24 14:09:39 +01:00
|
|
|
exitcode = EXIT_ATTACK;
|
2004-05-26 20:40:40 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-07-29 13:04:53 +01:00
|
|
|
/* check if there is a claim type that was never reached */
|
|
|
|
Claimlist cl_scan;
|
|
|
|
|
|
|
|
cl_scan = sys->claimlist;
|
|
|
|
while (cl_scan != NULL)
|
2004-05-26 20:40:40 +01:00
|
|
|
{
|
2004-08-09 11:05:58 +01:00
|
|
|
if (cl_scan->failed == STATES0)
|
2004-07-29 13:04:53 +01:00
|
|
|
{
|
2004-08-09 11:05:58 +01:00
|
|
|
/* mark exit code */
|
2004-08-24 14:09:39 +01:00
|
|
|
exitcode = EXIT_NOCLAIM;
|
2004-07-29 13:04:53 +01:00
|
|
|
}
|
|
|
|
cl_scan = cl_scan->next;
|
2004-05-26 20:40:40 +01:00
|
|
|
}
|
2004-07-29 13:04:53 +01:00
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* latex closeup */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.latex)
|
2004-04-23 11:58:43 +01:00
|
|
|
latexDone (sys);
|
|
|
|
|
2005-05-03 10:45:54 +01:00
|
|
|
/* xml closeup */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.xml)
|
2005-05-03 10:45:54 +01:00
|
|
|
xmlOutDone ();
|
|
|
|
|
2004-07-28 13:23:42 +01:00
|
|
|
/* Transfer any scenario counting to the exit code,
|
|
|
|
* assuming that there is no error. */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (exitcode != EXIT_ERROR && switches.scenario < 0)
|
2004-07-28 13:22:40 +01:00
|
|
|
{
|
|
|
|
exitcode = sys->countScenario;
|
|
|
|
}
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
/*
|
|
|
|
* Now we clean up any memory that was allocated.
|
|
|
|
*/
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.engine == ARACHNE_ENGINE)
|
2004-08-11 12:22:20 +01:00
|
|
|
{
|
|
|
|
arachneDone ();
|
2004-08-15 12:55:22 +01:00
|
|
|
bindingDone ();
|
2004-08-11 12:22:20 +01:00
|
|
|
}
|
2004-04-23 11:58:43 +01:00
|
|
|
knowledgeDestroy (sys->know);
|
|
|
|
systemDone (sys);
|
2005-12-28 15:27:22 +00:00
|
|
|
colorDone ();
|
2004-08-09 10:42:58 +01:00
|
|
|
compilerDone ();
|
2004-04-23 11:58:43 +01:00
|
|
|
|
|
|
|
/* done symbols */
|
|
|
|
tacDone ();
|
|
|
|
symbolsDone ();
|
|
|
|
knowledgeDone ();
|
|
|
|
termlistsDone ();
|
2004-06-14 10:15:42 +01:00
|
|
|
termmapsDone ();
|
2004-04-23 11:58:43 +01:00
|
|
|
termsDone ();
|
|
|
|
|
|
|
|
/* memory clean up? */
|
|
|
|
strings_cleanup ();
|
|
|
|
memDone ();
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return exitcode;
|
|
|
|
}
|
|
|
|
|
2005-12-28 15:27:22 +00:00
|
|
|
//! Print something bad
|
|
|
|
void
|
|
|
|
printBad (char *s)
|
|
|
|
{
|
|
|
|
eprintf ("%s%s%s", COLOR_Red, s, COLOR_Reset);
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Print something good
|
|
|
|
void
|
|
|
|
printGood (char *s)
|
|
|
|
{
|
|
|
|
eprintf ("%s%s%s", COLOR_Green, s, COLOR_Reset);
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Print state (existState, isAttack)
|
|
|
|
/**
|
|
|
|
* Fail == ( existState xor isAttack )
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
printOkFail (int existState, int isAttack)
|
|
|
|
{
|
|
|
|
if (existState != isAttack)
|
|
|
|
{
|
|
|
|
printGood ("Ok");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printBad ("Fail");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-14 18:29:26 +01:00
|
|
|
//! Display time and state space size information using ASCII.
|
|
|
|
/**
|
|
|
|
* Displays also whether an attack was found or not.
|
|
|
|
*/
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
void
|
|
|
|
timersPrint (const System sys)
|
|
|
|
{
|
2004-07-29 13:04:53 +01:00
|
|
|
Claimlist cl_scan;
|
|
|
|
int anyclaims;
|
|
|
|
|
2004-06-13 22:15:26 +01:00
|
|
|
// #define NOTIMERS
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2004-07-29 14:08:27 +01:00
|
|
|
/* display stats */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output != SUMMARY)
|
2004-07-29 14:08:27 +01:00
|
|
|
{
|
|
|
|
globalError++;
|
|
|
|
}
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
//**********************************************************************
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
/* states traversed */
|
2004-08-09 11:05:58 +01:00
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
if (switches.engine == POR_ENGINE)
|
2004-07-30 13:04:38 +01:00
|
|
|
{
|
2005-12-26 16:28:45 +00:00
|
|
|
eprintf ("states\t");
|
|
|
|
statesPrintShort (sys);
|
2004-07-30 13:04:38 +01:00
|
|
|
eprintf ("\n");
|
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
/* scenario info */
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
if (switches.scenario > 0)
|
|
|
|
{
|
|
|
|
eprintf ("scen_st\t");
|
|
|
|
statesFormat (sys->statesScenario);
|
|
|
|
eprintf ("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flag
|
|
|
|
*
|
|
|
|
* L n Attack of length <n>
|
|
|
|
* None failed claim
|
|
|
|
* NoClaim no claims
|
|
|
|
*/
|
|
|
|
|
|
|
|
eprintf ("attack\t");
|
|
|
|
if (sys->claims == STATES0)
|
|
|
|
{
|
|
|
|
eprintf ("NoClaim\n");
|
|
|
|
}
|
2004-04-23 11:58:43 +01:00
|
|
|
else
|
2005-12-26 16:28:45 +00:00
|
|
|
{
|
|
|
|
if (sys->failed != STATES0)
|
|
|
|
eprintf ("L:%i\n", attackLength (sys->attack));
|
|
|
|
else
|
|
|
|
eprintf ("None\n");
|
|
|
|
}
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2004-07-29 14:08:27 +01:00
|
|
|
#ifndef NOTIMERS
|
2005-12-26 16:28:45 +00:00
|
|
|
/* print time */
|
2004-07-29 14:08:27 +01:00
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
double seconds;
|
|
|
|
seconds = (double) clock () / CLOCKS_PER_SEC;
|
|
|
|
eprintf ("time\t%.3e\n", seconds);
|
2004-07-29 14:08:27 +01:00
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
/* states per second */
|
2004-04-23 11:58:43 +01:00
|
|
|
|
2005-12-26 16:28:45 +00:00
|
|
|
eprintf ("st/sec\t");
|
|
|
|
if (seconds > 0)
|
|
|
|
{
|
|
|
|
eprintf ("%.3e\n", statesDouble (sys->states) / seconds);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eprintf ("<inf>\n");
|
|
|
|
}
|
2004-05-26 13:17:09 +01:00
|
|
|
#endif
|
2005-12-26 16:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************
|
2004-07-29 13:04:53 +01:00
|
|
|
|
2004-07-29 14:08:27 +01:00
|
|
|
/* Print also individual claims */
|
|
|
|
/* Note that if the output is set to empty, the claim output is redirected to stdout (for e.g. processing)
|
|
|
|
*/
|
|
|
|
cl_scan = sys->claimlist;
|
2005-12-28 11:50:17 +00:00
|
|
|
anyclaims = false;
|
2004-07-29 14:08:27 +01:00
|
|
|
while (cl_scan != NULL)
|
2004-07-29 13:04:53 +01:00
|
|
|
{
|
2005-06-16 12:59:44 +01:00
|
|
|
if (!isTermEqual (cl_scan->type, CLAIM_Empty))
|
|
|
|
{
|
2005-12-28 11:50:17 +00:00
|
|
|
Protocol protocol;
|
|
|
|
Term pname;
|
|
|
|
Term rname;
|
|
|
|
Termlist labellist;
|
2005-12-28 15:27:22 +00:00
|
|
|
int isAttack; // stores whether this claim failure constitutes an attack or not
|
2005-12-28 11:50:17 +00:00
|
|
|
|
2005-12-28 15:27:22 +00:00
|
|
|
if (isTermEqual (cl_scan->type, CLAIM_Reachable))
|
|
|
|
{
|
|
|
|
// An attack on reachable is not really an attack, we're just generating the state space
|
|
|
|
isAttack = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
isAttack = true;
|
|
|
|
}
|
2005-12-28 11:50:17 +00:00
|
|
|
anyclaims = true;
|
2004-07-29 14:08:27 +01:00
|
|
|
|
2005-06-16 12:59:44 +01:00
|
|
|
eprintf ("claim\t");
|
2004-10-14 14:19:36 +01:00
|
|
|
|
2005-12-28 11:50:17 +00:00
|
|
|
protocol = (Protocol) cl_scan->protocol;
|
|
|
|
pname = protocol->nameterm;
|
|
|
|
rname = cl_scan->rolename;
|
|
|
|
|
|
|
|
labellist = tuple_to_termlist (cl_scan->label);
|
|
|
|
|
|
|
|
/* maybe the label contains duplicate info: if so, we remove it here */
|
|
|
|
{
|
|
|
|
Termlist tl;
|
|
|
|
tl = labellist;
|
|
|
|
while (tl != NULL)
|
|
|
|
{
|
|
|
|
if (isTermEqual (tl->term, pname)
|
|
|
|
|| isTermEqual (tl->term, rname))
|
|
|
|
{
|
|
|
|
tl = termlistDelTerm (tl);
|
|
|
|
labellist = tl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tl = tl->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
termPrint (pname);
|
|
|
|
eprintf (",");
|
|
|
|
termPrint (rname);
|
|
|
|
eprintf ("\t");
|
|
|
|
/* second print event_label */
|
|
|
|
termPrint (cl_scan->type);
|
|
|
|
|
|
|
|
eprintf ("_");
|
|
|
|
if (labellist != NULL)
|
|
|
|
{
|
|
|
|
Termlist tl;
|
|
|
|
|
|
|
|
tl = labellist;
|
|
|
|
while (tl != NULL)
|
|
|
|
{
|
|
|
|
termPrint (tl->term);
|
|
|
|
tl = tl->next;
|
|
|
|
if (tl != NULL)
|
|
|
|
{
|
|
|
|
eprintf (",");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* clean up */
|
|
|
|
termlistDelete (labellist);
|
|
|
|
labellist = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eprintf ("?");
|
|
|
|
}
|
|
|
|
/* add parameter */
|
|
|
|
eprintf ("\t");
|
|
|
|
if (cl_scan->parameter != NULL)
|
2004-07-29 13:36:24 +01:00
|
|
|
{
|
2005-12-28 11:50:17 +00:00
|
|
|
termPrint (cl_scan->parameter);
|
2004-07-29 13:36:24 +01:00
|
|
|
}
|
2004-08-19 14:09:35 +01:00
|
|
|
else
|
|
|
|
{
|
2005-12-28 11:50:17 +00:00
|
|
|
eprintf ("-");
|
2005-06-16 12:59:44 +01:00
|
|
|
}
|
2005-12-27 12:24:12 +00:00
|
|
|
|
|
|
|
/* now report the status */
|
2005-12-28 11:50:17 +00:00
|
|
|
eprintf ("\t");
|
2005-12-27 12:24:12 +00:00
|
|
|
if (cl_scan->count > 0 && cl_scan->failed > 0)
|
|
|
|
{
|
2005-12-28 15:27:22 +00:00
|
|
|
/* there is a state */
|
|
|
|
printOkFail (true, isAttack);
|
2005-12-28 14:42:46 +00:00
|
|
|
|
|
|
|
eprintf ("\t");
|
2005-12-28 11:50:17 +00:00
|
|
|
/* are these all attacks? */
|
2005-12-28 14:42:46 +00:00
|
|
|
eprintf ("[");
|
2005-12-28 11:50:17 +00:00
|
|
|
if (cl_scan->complete)
|
|
|
|
{
|
|
|
|
eprintf ("exactly");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eprintf ("at least");
|
|
|
|
}
|
2005-12-28 15:27:22 +00:00
|
|
|
eprintf (" %i ", cl_scan->failed);
|
|
|
|
if (isAttack)
|
|
|
|
{
|
|
|
|
eprintf ("attack");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eprintf ("variant");
|
|
|
|
}
|
2005-12-28 14:42:46 +00:00
|
|
|
if (cl_scan->failed != 1)
|
|
|
|
{
|
|
|
|
eprintf ("s");
|
|
|
|
}
|
|
|
|
eprintf ("]");
|
2005-12-27 12:24:12 +00:00
|
|
|
}
|
|
|
|
else
|
2005-06-16 12:59:44 +01:00
|
|
|
{
|
2005-12-28 15:27:22 +00:00
|
|
|
/* no state */
|
|
|
|
printOkFail (false, isAttack);
|
|
|
|
eprintf ("\t");
|
2005-12-27 12:24:12 +00:00
|
|
|
|
|
|
|
/* subcases */
|
|
|
|
if (cl_scan->count == 0)
|
2005-01-14 13:01:31 +00:00
|
|
|
{
|
2005-12-27 12:24:12 +00:00
|
|
|
/* not encountered */
|
2005-12-28 14:42:46 +00:00
|
|
|
eprintf ("[does not occur]");
|
2005-01-14 13:01:31 +00:00
|
|
|
}
|
2004-08-19 14:09:35 +01:00
|
|
|
else
|
2005-01-14 13:01:31 +00:00
|
|
|
{
|
2005-12-27 12:24:12 +00:00
|
|
|
/* does occur */
|
2005-06-16 12:59:44 +01:00
|
|
|
if (cl_scan->complete)
|
|
|
|
{
|
2005-12-27 12:24:12 +00:00
|
|
|
/* complete proof */
|
2005-12-29 13:36:01 +00:00
|
|
|
eprintf ("[proof of correctness]");
|
2005-06-16 12:59:44 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-12-27 12:24:12 +00:00
|
|
|
/* only due to bounds */
|
2005-12-28 14:42:46 +00:00
|
|
|
eprintf ("[no attack within bounds]");
|
2005-06-16 12:59:44 +01:00
|
|
|
if (cl_scan->timebound)
|
|
|
|
eprintf ("\ttime=%i", get_time_limit ());
|
|
|
|
}
|
2005-01-14 13:01:31 +00:00
|
|
|
}
|
2004-08-19 14:09:35 +01:00
|
|
|
}
|
2005-12-27 12:24:12 +00:00
|
|
|
|
2005-12-27 13:44:12 +00:00
|
|
|
/* any warnings */
|
|
|
|
if (cl_scan->warnings)
|
|
|
|
{
|
2005-12-28 14:42:46 +00:00
|
|
|
eprintf ("\t[read the warnings for more information]");
|
2005-12-27 13:44:12 +00:00
|
|
|
}
|
|
|
|
|
2005-12-27 12:24:12 +00:00
|
|
|
/* proceed to next claim */
|
2005-06-16 12:59:44 +01:00
|
|
|
eprintf ("\n");
|
2004-07-29 13:04:53 +01:00
|
|
|
}
|
2004-07-29 14:08:27 +01:00
|
|
|
cl_scan = cl_scan->next;
|
|
|
|
}
|
|
|
|
if (!anyclaims)
|
|
|
|
{
|
|
|
|
warning ("No claims in system.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset globalError */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output != SUMMARY)
|
2004-07-29 14:08:27 +01:00
|
|
|
{
|
|
|
|
globalError--;
|
2004-07-29 13:04:53 +01:00
|
|
|
}
|
2004-04-23 11:58:43 +01:00
|
|
|
}
|
|
|
|
|
2004-05-14 18:29:26 +01:00
|
|
|
//! Analyse the model by incremental runs.
|
2004-04-23 11:58:43 +01:00
|
|
|
/*
|
|
|
|
* This procedure considers mainly incremental searches, and settings
|
|
|
|
* parameters for that. The real work is handled by modelCheck.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
MC_incRuns (const System sys)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* incremental runs check
|
|
|
|
*
|
|
|
|
* note: we assume that at least one run needs to be checked.
|
|
|
|
*/
|
|
|
|
int maxruns = sys->maxruns;
|
|
|
|
int runs = 1;
|
|
|
|
int flag = 1;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
systemReset (sys);
|
|
|
|
sys->maxruns = runs;
|
2004-07-28 12:39:08 +01:00
|
|
|
systemRuns (sys);
|
2004-08-09 11:05:58 +01:00
|
|
|
fprintf (stderr, "%i of %i runs in incremental runs search.\n",
|
|
|
|
runs, maxruns);
|
2004-04-23 11:58:43 +01:00
|
|
|
res = modelCheck (sys);
|
2004-05-25 10:28:40 +01:00
|
|
|
fprintf (stderr, "\n");
|
2004-04-23 11:58:43 +01:00
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
/* Apparently a violation occurred. If we are searching
|
|
|
|
* the whole space, then we just continue. However, if
|
|
|
|
* we're looking to prune, ``the buck stops here''. */
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.prune != 0)
|
2004-04-23 11:58:43 +01:00
|
|
|
{
|
|
|
|
flag = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
runs++;
|
|
|
|
}
|
|
|
|
while (flag && runs <= maxruns);
|
2004-08-10 16:02:37 +01:00
|
|
|
sys->maxruns = maxruns;
|
2004-04-23 11:58:43 +01:00
|
|
|
}
|
|
|
|
|
2004-05-14 18:29:26 +01:00
|
|
|
//! Analyse the model by incremental trace lengths.
|
|
|
|
/*
|
|
|
|
* This procedure considers mainly incremental searches, and settings
|
|
|
|
* parameters for that. The real work is handled by modelCheck.
|
|
|
|
*/
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
void
|
|
|
|
MC_incTraces (const System sys)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* incremental traces check
|
|
|
|
*
|
|
|
|
* note: we assume that at least one run needs to be checked.
|
|
|
|
*/
|
|
|
|
int maxtracelen;
|
|
|
|
int tracelen;
|
|
|
|
int tracestep;
|
2004-05-26 09:52:15 +01:00
|
|
|
int flag;
|
|
|
|
int res;
|
2004-04-23 11:58:43 +01:00
|
|
|
|
|
|
|
tracestep = 3; /* what is a sensible stepping size? */
|
2004-05-26 13:17:09 +01:00
|
|
|
flag = 1;
|
|
|
|
|
2004-04-23 11:58:43 +01:00
|
|
|
maxtracelen = getMaxTraceLength (sys);
|
|
|
|
tracelen = maxtracelen - tracestep;
|
|
|
|
while (tracelen > 6) /* what is a reasonable minimum? */
|
|
|
|
tracelen -= tracestep;
|
|
|
|
|
2004-05-26 09:52:15 +01:00
|
|
|
flag = 1;
|
2004-04-23 11:58:43 +01:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
systemReset (sys);
|
|
|
|
sys->maxtracelength = tracelen;
|
2004-07-28 12:39:08 +01:00
|
|
|
systemRuns (sys);
|
2004-08-09 11:05:58 +01:00
|
|
|
fprintf (stderr,
|
|
|
|
"%i of %i trace length in incremental trace length search.\n",
|
|
|
|
tracelen, maxtracelen);
|
2004-04-23 11:58:43 +01:00
|
|
|
res = modelCheck (sys);
|
2004-05-25 10:28:40 +01:00
|
|
|
fprintf (stderr, "\n");
|
2004-04-23 11:58:43 +01:00
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
/* Apparently a violation occurred. If we are searching
|
|
|
|
* the whole space, then we just continue. However, if
|
|
|
|
* we're looking to prune, ``the buck stops here''. */
|
|
|
|
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.prune != 0)
|
2004-04-23 11:58:43 +01:00
|
|
|
{
|
|
|
|
flag = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tracelen += tracestep;
|
|
|
|
}
|
|
|
|
while (flag && tracelen <= maxtracelen);
|
|
|
|
}
|
|
|
|
|
2004-05-14 18:29:26 +01:00
|
|
|
//! Analyse the model with a fixed scenario.
|
|
|
|
/**
|
|
|
|
* Traditional handywork.
|
2004-04-23 11:58:43 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
MC_single (const System sys)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* simple one-time check
|
|
|
|
*/
|
|
|
|
|
|
|
|
systemReset (sys); // reset any globals
|
2004-07-28 12:39:08 +01:00
|
|
|
systemRuns (sys); // init runs data
|
2004-04-23 11:58:43 +01:00
|
|
|
modelCheck (sys);
|
|
|
|
}
|
|
|
|
|
2004-05-14 18:29:26 +01:00
|
|
|
//! Model check the system, given all parameters.
|
2004-04-23 11:58:43 +01:00
|
|
|
/*
|
|
|
|
* Precondition: the system was reset with the corresponding parameters.
|
2004-05-15 16:26:21 +01:00
|
|
|
* Reports time and states traversed.
|
|
|
|
* Note that the return values doubles as the number of failed claims.
|
|
|
|
*@return True iff any claim failed, and thus an attack was found.
|
2004-04-23 11:58:43 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
modelCheck (const System sys)
|
|
|
|
{
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == STATESPACE)
|
2004-07-12 14:58:41 +01:00
|
|
|
{
|
|
|
|
graphInit (sys);
|
|
|
|
}
|
2004-07-21 11:35:39 +01:00
|
|
|
|
|
|
|
/* modelcheck the system */
|
2005-06-07 16:02:27 +01:00
|
|
|
switch (switches.engine)
|
2004-08-11 10:51:17 +01:00
|
|
|
{
|
|
|
|
case POR_ENGINE:
|
2005-04-22 17:03:58 +01:00
|
|
|
if (sys->maxruns > 0)
|
|
|
|
traverse (sys);
|
|
|
|
else
|
|
|
|
warning ("Model checking system with empty scenario.");
|
2004-08-11 10:51:17 +01:00
|
|
|
break;
|
|
|
|
case ARACHNE_ENGINE:
|
2004-08-11 15:09:12 +01:00
|
|
|
arachne ();
|
2004-08-11 10:51:17 +01:00
|
|
|
break;
|
|
|
|
default:
|
2005-06-07 16:02:27 +01:00
|
|
|
error ("Unknown engine type %i.", switches.engine);
|
2004-08-11 10:51:17 +01:00
|
|
|
}
|
2004-07-21 11:35:39 +01:00
|
|
|
|
|
|
|
/* clean up any states display */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.reportStates > 0)
|
2004-07-21 11:35:39 +01:00
|
|
|
{
|
2004-07-21 12:03:49 +01:00
|
|
|
// States: 1.000e+06
|
|
|
|
fprintf (stderr, " \r");
|
2004-07-21 11:35:39 +01:00
|
|
|
}
|
|
|
|
|
2004-05-21 13:32:57 +01:00
|
|
|
timersPrint (sys);
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.output == STATESPACE)
|
2004-07-12 14:58:41 +01:00
|
|
|
{
|
|
|
|
graphDone (sys);
|
|
|
|
}
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.scenario > 0)
|
2004-07-28 13:03:42 +01:00
|
|
|
{
|
|
|
|
/* Traversing a scenario. Maybe we ran out. */
|
2005-06-07 16:02:27 +01:00
|
|
|
if (switches.scenario > sys->countScenario)
|
2004-07-28 13:03:42 +01:00
|
|
|
{
|
|
|
|
/* Signal as error */
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
}
|
2004-07-21 11:35:39 +01:00
|
|
|
return (sys->failed != STATES0);
|
2004-04-23 11:58:43 +01:00
|
|
|
}
|