Changes between Initial Version and Version 1 of Tour


Ignore:
Timestamp:
08/31/18 17:51:30 (8 years ago)
Author:
wuwenhao
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Tour

    v1 v1  
     1= CIVL: The Concurrency Intermediate Verification Language =
     2
     3== Abstract ==
     4'''CIVL: Concurrency Intermediate Verification Language''' is a framework for the verification of multiple concurrent C dialects and libraries, such as OpenMP, MPI, Pthreads, CUDA, etc.
     5It contains transformers to transform programs of such language or libraries into CIVL-C program, which is a dialect of C with concurrent extension, and uses symbolic execution to model check the programs.
     6CIVL-C language is designed to capture the common features of concurrency so that could be used to describe a large number of concurrent dialects or libraries.
     7CIVL is open source, and is designed to be flexible to be extended for verifying more concurrent languages and libraries.
     8
     9Properties that CIVL checks include: deadlock, memory leak, array index-out-of bound, invalid pointer dereference, user-specified assertions, and functional equivalence.
     10
     11CIVL is also able to verify hybrid concurrent programs, i.e., programs containing more than one dialects or librabries, such as MPI-OpenMP, MPI-Pthreads, etc.
     12
     13== Examples ==
     14The following demonstrate some of CIVL's capabilities. This is a small sample; see the [https://vsl.cis.udel.edu/lib/sw/civl/civl-manual.pdf CIVL manual] for the full story.
     15* Dining philosopher in CIVL-C
     16* 1-dimensional wave simulator in MPI
     17* Dot product in OpenMP
     18
     19
     20=== Dining philosopher in CIVL-C ===
     21CIVL-C implementation of dining philosopher, which contains a deadlock. Suppose the file name is [https://vsl.cis.udel.edu/lib/demo/diningBad.cvl diningBad.cvl].
     22
     23{{{
     24#include <civlc.cvh>
     25
     26$input int B = 4; // upper bound on number of philosophers
     27$input int n;     // number of philosophers
     28$assume(2<=n && n<=B);
     29
     30_Bool forks[n]; // Each fork will be on the table ($true) or in a hand ($false).
     31
     32void dine(int id) {
     33  int left = id;
     34  int right = (id + 1) % n;
     35
     36  while (1) {
     37    $when (forks[left]) forks[left] = $false;
     38    $when (forks[right]) forks[right] = $false;
     39    forks[right] = $true;
     40    forks[left] = $true;
     41  }
     42}
     43
     44void main() {
     45  $for(int i: 0 .. n-1)
     46    forks[i] = $true;
     47  $parfor(int i: 0 .. n-1)
     48    dine(i);
     49}
     50}}}
     51
     52'''Command''': civl verify -inputB=4 diningBad.cvl
     53
     54The above command triggers CIVL to verify the CIVL-C program for dining philosophers, with the upper bound of number of philosophers being 4. As shown by the output below, CIVL detects a deadlock violation of the program at depth 79, i.e., after 78 trace steps.
     55
     56'''Output''':
     57{{{
     58CIVL v1.17.1+ of 2018-07-30 -- http://vsl.cis.udel.edu/civl
     59
     60Violation 0 encountered at depth 21:
     61CIVL execution violation (kind: DEADLOCK, certainty: PROVEABLE)
     62at diningBad.cvl:31.11-11
     63            dine(i);
     64
     65A deadlock is possible:
     66  Path condition: true
     67  Enabling predicate: false
     68process p0 (id=0): false
     69process p1 (id=1): false
     70process p2 (id=2): false
     71
     72Call stacks:
     73process 0:
     74  main at diningBad.cvl:31.11 ";"
     75process 1:
     76  dine at diningBad.cvl:21.4-8 "$when" called from
     77  _par_proc0 at diningBad.cvl:31.4-7 "dine"
     78process 2:
     79  dine at diningBad.cvl:21.4-8 "$when" called from
     80  _par_proc0 at diningBad.cvl:31.4-7 "dine"
     81
     82Logging new entry 0, writing trace to CIVLREP/diningBad_0.trace
     83Terminating search after finding 1 violation.
     84
     85=== Source files ===
     86diningBad.cvl  (diningBad.cvl)
     87
     88
     89=== Command ===
     90civl verify -inputB=4 diningBad.cvl
     91
     92=== Stats ===
     93   time (s)            : 1.36
     94   memory (bytes)      : 268435456
     95   max process count   : 3
     96   states              : 32
     97   states saved        : 26
     98   state matches       : 1
     99   transitions         : 30
     100   trace steps         : 21
     101   valid calls         : 104
     102   provers             : cvc4, z3
     103   prover calls        : 3
     104
     105=== Result ===
     106The program MAY NOT be correct.  See CIVLREP/diningBad_log.txt
     107}}}
     108
     109Now that we know there is a violation, we probably want to find a minimal one. We can use the option "-min" for the verification, as shown by the following command.
     110
     111'''Command''': civl verify -inputB=4 -min diningBad.cvl
     112
     113As shown in the following output, CIVL keeps reducing the search depth until it finds the minimal counterexample at depth 23, which is much smaller and is the case when there are two philosophers.
     114
     115'''Output''':
     116{{{
     117CIVL v1.17.1+ of 2018-07-30 -- http://vsl.cis.udel.edu/civl
     118
     119Violation 0 encountered at depth 21:
     120CIVL execution violation (kind: DEADLOCK, certainty: PROVEABLE)
     121at diningBad.cvl:31.11-11
     122            dine(i);
     123
     124A deadlock is possible:
     125  Path condition: true
     126  Enabling predicate: false
     127process p0 (id=0): false
     128process p1 (id=1): false
     129process p2 (id=2): false
     130
     131Call stacks:
     132process 0:
     133  main at diningBad.cvl:31.11 ";"
     134process 1:
     135  dine at diningBad.cvl:21.4-8 "$when" called from
     136  _par_proc0 at diningBad.cvl:31.4-7 "dine"
     137process 2:
     138  dine at diningBad.cvl:21.4-8 "$when" called from
     139  _par_proc0 at diningBad.cvl:31.4-7 "dine"
     140
     141Logging new entry 0, writing trace to CIVLREP/diningBad_0.trace
     142Restricting search depth to 20
     143
     144Violation 1 encountered at depth 16:
     145CIVL execution violation (kind: DEADLOCK, certainty: PROVEABLE)
     146at diningBad.cvl:31.11-11
     147            dine(i);
     148
     149A deadlock is possible:
     150  Path condition: true
     151  Enabling predicate: false
     152process p0 (id=0): false
     153process p1 (id=1): false
     154process p2 (id=2): false
     155
     156Call stacks:
     157process 0:
     158  main at diningBad.cvl:31.11 ";"
     159process 1:
     160  dine at diningBad.cvl:21.4-8 "$when" called from
     161  _par_proc0 at diningBad.cvl:31.4-7 "dine"
     162process 2:
     163  dine at diningBad.cvl:21.4-8 "$when" called from
     164  _par_proc0 at diningBad.cvl:31.4-7 "dine"
     165
     166New log entry is equivalent to previously encountered entry 0
     167Length of new trace (16) is less than length of old (21): replacing old with new...
     168Restricting search depth to 15
     169
     170=== Source files ===
     171diningBad.cvl  (diningBad.cvl)
     172
     173
     174=== Command ===
     175civl verify -inputB=4 -min diningBad.cvl
     176
     177=== Stats ===
     178   time (s)            : 1.11
     179   memory (bytes)      : 268435456
     180   max process count   : 5
     181   states              : 76
     182   states saved        : 62
     183   state matches       : 2
     184   transitions         : 73
     185   trace steps         : 51
     186   valid calls         : 256
     187   provers             : cvc4, z3
     188   prover calls        : 3
     189
     190=== Result ===
     191The program MAY NOT be correct.  See CIVLREP/diningBad_log.txt
     192}}}
     193
     194Now CIVL finds the minimal counterexample and we can use CIVL to reproduce it via the "replay" command.
     195
     196'''Command''': civl replay -showTransitions diningBad.cvl
     197
     198'''Output''':
     199{{{
     200CIVL v1.17.1+ of 2018-07-30 -- http://vsl.cis.udel.edu/civl
     201
     202Initial state:
     203
     204State (id=9)
     205| Path condition
     206| | true
     207| Dynamic scopes
     208| | dyscope d0 (parent=NULL, static=1)
     209| | | variables
     210| | | | B = NULL
     211| | | | n = NULL
     212| | | | forks = NULL
     213| Process states
     214| | process 0
     215| | | call stack
     216| | | | Frame[function=main, location=0, diningBad.cvl:9.15 "4", dyscope=d0]
     217
     218Executed by p0 from State (id=9)
     219  0->1: B=4 at diningBad.cvl:9.0-15 "$input int B = 4"
     220  1->2: n=InitialValue(n) [n:=X_n] at diningBad.cvl:10.0-11 "$input int n"
     221  2->3: $assume((2<=X_n)&&(X_n<=4)) at diningBad.cvl:11.0-20 "$assume(2<=n && n ... )"
     222  3->4: forks=InitialValue(forks) [forks:=(boolean[X_n]) ($lambda i: int. false)] at diningBad.cvl:13.0-13 "_Bool forks[n]"
     223--> State (id=18)
     224
     225Step 1: Executed by p0 from State (id=18)
     226  4->5: $elaborate_domain(($domain(1))(0..X_n-1#1)) [$assume(0==(X_n - 2))] at diningBad.cvl:28.14-21 "0 .. n-1"
     227--> State (id=22)
     228
     229Step 2: Executed by p0 from State (id=22)
     230  5->6: LOOP_BODY_ENTER (guard: ($domain(1))(0..1#1) has next for (NULL)) at diningBad.cvl:28.14-21 "0 .. n-1"
     231  6->7: NEXT of (NULL) in ($domain(1))(0..1#1) [i:=0] at diningBad.cvl:28.2-5 "$for"
     232--> State (id=26)
     233
     234Step 3: Executed by p0 from State (id=26)
     235  7->5: forks[0]=true at diningBad.cvl:29.4-civlc.cvh:10.14 "forks[i] = 1"
     236--> State (id=29)
     237
     238Step 4: Executed by p0 from State (id=29)
     239  5->6: LOOP_BODY_ENTER (guard: ($domain(1))(0..1#1) has next for (0)) at diningBad.cvl:28.14-21 "0 .. n-1"
     240  6->7: NEXT of (0) in ($domain(1))(0..1#1) [i:=1] at diningBad.cvl:28.2-5 "$for"
     241--> State (id=33)
     242
     243Step 5: Executed by p0 from State (id=33)
     244  7->5: forks[1]=true at diningBad.cvl:29.4-civlc.cvh:10.14 "forks[i] = 1"
     245--> State (id=36)
     246
     247Step 6: Executed by p0 from State (id=36)
     248  5->8: LOOP_BODY_EXIT (guard: !($domain(1))(0..1#1) has next for (1)) at diningBad.cvl:28.14-21 "0 .. n-1"
     249--> State (id=38)
     250
     251Step 7: Executed by p0 from State (id=38)
     252  8->9: $elaborate_domain(($domain(1))(0..1#1)) [$assume(true)] at diningBad.cvl:30.17-24 "0 .. n-1"
     253  9->10: $parfor(i0: ($domain(1))(0..1#1)) $spawn _par_proc0(i0) at diningBad.cvl:30.2-8 "$parfor"
     254  10->11: _civl_ir1=0 at diningBad.cvl:31.11 ";"
     255--> State (id=52)
     256
     257Step 8: Executed by p0 from State (id=52)
     258  11->12: LOOP_BODY_ENTER (guard: 0<2) at diningBad.cvl:31.11 ";"
     259--> State (id=54)
     260
     261Step 9: Executed by p1 from State (id=54)
     262  23->15: dine(0) at diningBad.cvl:31.4-10 "dine(i)"
     263  15->16: left=0 at diningBad.cvl:16.2-14 "int left = id"
     264  16->17: right=(0+1)%2 [right:=1] at diningBad.cvl:17.2-25 "int right = (id  ... n"
     265--> State (id=61)
     266
     267Step 10: Executed by p1 from State (id=61)
     268  17->18: LOOP_BODY_ENTER (guard: 1!=0) at diningBad.cvl:19.9 "1"
     269--> State (id=63)
     270
     271Step 11: Executed by p2 from State (id=63)
     272  23->15: dine(1) at diningBad.cvl:31.4-10 "dine(i)"
     273  15->16: left=1 at diningBad.cvl:16.2-14 "int left = id"
     274  16->17: right=(1+1)%2 [right:=0] at diningBad.cvl:17.2-25 "int right = (id  ... n"
     275--> State (id=70)
     276
     277Step 12: Executed by p2 from State (id=70)
     278  17->18: LOOP_BODY_ENTER (guard: 1!=0) at diningBad.cvl:19.9 "1"
     279--> State (id=72)
     280
     281Step 13: Executed by p1 from State (id=72)
     282  18->19: forks[0]=false at diningBad.cvl:20.24-civlc.cvh:12.15 "forks[left] = 0"
     283--> State (id=75)
     284
     285Step 14: Executed by p2 from State (id=75)
     286  18->19: forks[1]=false at diningBad.cvl:20.24-civlc.cvh:12.15 "forks[left] = 0"
     287--> State (id=78)
     288
     289Step 15:
     290State (id=78)
     291| Path condition
     292| | true
     293| Dynamic scopes
     294| | dyscope d0 (parent=NULL, static=1)
     295| | | variables
     296| | | | B = 4
     297| | | | n = 2
     298| | | | forks = {[0]=false, [1]=false}
     299| | dyscope d1 (parent=d0, static=4)
     300| | | variables
     301| | | | i = 1
     302| | | | __LiteralDomain_counter0__ = NULL
     303| | dyscope d2 (parent=d0, static=7)
     304| | | variables
     305| | | | _dom_size0 = 2
     306| | | | _par_procs0 = {[0]=p1, [1]=p2}
     307| | dyscope d3 (parent=d0, static=8)
     308| | | variables
     309| | | | i = 0
     310| | dyscope d4 (parent=d0, static=8)
     311| | | variables
     312| | | | i = 1
     313| | dyscope d5 (parent=d2, static=9)
     314| | | variables
     315| | | | _civl_ir1 = 0
     316| | dyscope d6 (parent=d5, static=10)
     317| | | variables
     318| | dyscope d7 (parent=d0, static=3)
     319| | | variables
     320| | | | id = 0
     321| | dyscope d8 (parent=d7, static=12)
     322| | | variables
     323| | | | left = 0
     324| | | | right = 1
     325| | dyscope d9 (parent=d0, static=3)
     326| | | variables
     327| | | | id = 1
     328| | dyscope d10 (parent=d9, static=12)
     329| | | variables
     330| | | | left = 1
     331| | | | right = 0
     332| Process states
     333| | process 0
     334| | | call stack
     335| | | | Frame[function=main, location=12, diningBad.cvl:31.11 ";", dyscope=d6]
     336| | process 1
     337| | | call stack
     338| | | | Frame[function=dine, location=19, diningBad.cvl:21.4-8 "$when", dyscope=d8]
     339| | | | Frame[function=_par_proc0, location=23, diningBad.cvl:31.4-7 "dine", dyscope=d3]
     340| | process 2
     341| | | call stack
     342| | | | Frame[function=dine, location=19, diningBad.cvl:21.4-8 "$when", dyscope=d10]
     343| | | | Frame[function=_par_proc0, location=23, diningBad.cvl:31.4-7 "dine", dyscope=d4]
     344
     345Violation of Deadlock found in (id=78):
     346A deadlock is possible:
     347  Path condition: true
     348  Enabling predicate: false
     349process p0 (id=0): false
     350process p1 (id=1): false
     351process p2 (id=2): false
     352
     353Trace ends after 15 trace steps.
     354Violation(s) found.
     355
     356=== Source files ===
     357diningBad.cvl  (diningBad.cvl)
     358
     359
     360=== Command ===
     361civl replay -showTransitions diningBad.cvl
     362
     363=== Stats ===
     364   time (s)            : 1.01
     365   memory (bytes)      : 268435456
     366   max process count   : 3
     367   states              : 27
     368   valid calls         : 98
     369   provers             : cvc4, z3
     370   prover calls        : 3
     371
     372}}}
     373
     374
     375=== 1-dimensional wave simulator in MPI ===
     376MPI implementation of 1d-wave simulator, which has a bug. The file name of this program is [https://vsl.cis.udel.edu/lib/demo/wave1d.c wave1d.c].
     377Some additional CIVL-C code has been inserted to specify the intended behavior of the program;
     378in the full source, this extra code is within preprocessor directives #ifdef _CIVL ... #endif
     379which cause the extra code to be ignored during normal compilation but used by CIVL.
     380The program starts with the string in some arbitrary initial position specified by the input variable u_init .
     381The variable oracle keeps the result of a sequential run of the simulator at every time step,
     382and at every time step of the parallel run an assertion is checked to see if the parallel result agrees with the sequential one.
     383
     384{{{
     385/* Input parameters */
     386#ifdef _CIVL
     387$input int NXB = 5;               /* upper bound on nx */
     388$input int nx;                    /* number of discrete points including endpoints */
     389$assume(2 <= nx && nx <= NXB);     /* setting bounds */
     390$input double c;                  /* physical constant to do with string */
     391$assume(c > 0.0);       
     392$input int NSTEPSB = 5;       
     393$input int nsteps;                /* number of time steps */
     394$assume(0 < nsteps && nsteps <= NSTEPSB);
     395$input int wstep = 1;             /* number of time steps between printing */
     396double oracle[nsteps + 1][nx + 2];/* result of sequential run at every time step */
     397$input double u_init[nx];         /* arbitrary initial position of string */
     398...
     399#else
     400...
     401#endif
     402
     403/* Global varibales */
     404double *u_prev, *u_curr, *u_next;
     405double k;
     406int nprocs, nxl, rank;
     407int first;                       /* global index of first cell owned by this process */
     408int left, right;                 /* ranks of left neighbor and right neighbor */
     409...
     410/* Update cells owned by processes */
     411void update() {
     412  int i;
     413  double *tmp;
     414
     415  for (i = 1; i < nxl + 1; i++){
     416    u_next[i] = 2.0*u_curr[i] - u_prev[i] +
     417      k*(u_curr[i+1] + u_curr[i-1] -2.0*u_curr[i]);
     418  }
     419  //cycle pointers:
     420  tmp = u_prev;
     421  u_prev = u_curr;
     422  u_curr = u_next;
     423  u_next = tmp;
     424}
     425
     426/* Initialization function, initializes all parameters and data array.
     427 * In CIVL mode, process 0 runs the complete problem sequentially to
     428 * create the oracle which will be compared with the results of the
     429 * parallel run.
     430 */
     431void initialization() {
     432  ...
     433  nxl = countForProc(rank);
     434  first = firstForProc(rank);
     435  u_prev = (double *)malloc((nxl + 2) * sizeof(double));
     436  assert(u_prev);
     437  u_curr = (double *)malloc((nxl + 2) * sizeof(double));
     438  assert(u_curr);
     439  u_next = (double *)malloc((nxl + 2) * sizeof(double));
     440  assert(u_next);
     441  // sets constant boundaries
     442  u_prev[0] = 0;
     443  u_curr[0] = 0;
     444  //u_next[0] = 0;
     445  u_prev[nxl + 1] = 0;
     446  u_curr[nxl + 1] = 0;
     447  //u_next[nxl + 1] = 0;
     448  // skip processes which are allocated no cells
     449  if(first != 0 && nxl != 0)
     450    left = OWNER(first - 1);
     451  else
     452    left = MPI_PROC_NULL;
     453  if(first + nxl < nx && nxl != 0)
     454    right = OWNER(first + nxl);
     455  else
     456    right = MPI_PROC_NULL;
     457}
     458
     459...
     460/* Print out the value of data cells;
     461   Do comparison in CIVL mode */
     462void printData (int time, int first, int length, double * buf) {
     463  for(int i = 0; i < length; i++){
     464    printf("u_curr[%d]=%8.8f   ", first + i, buf[i]);
     465#ifdef _CIVL
     466
     467     $assert((oracle[time + 1][first + i + 1] == buf[i]), \
     468    "Error: disagreement at time %d position %d: saw %lf, expected %lf", \
     469    time, first + i, buf[i], oracle[time + 1][first + i + 1]);
     470#endif
     471  }
     472}
     473...
     474
     475/* Exchanging ghost cells */
     476void exchange(){
     477  MPI_Sendrecv(&u_curr[1], 1, MPI_DOUBLE, left, FROMRIGHT, &u_curr[nxl+1], 1, MPI_DOUBLE,
     478               right, FROMRIGHT, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
     479  MPI_Sendrecv(&u_curr[nxl], 1, MPI_DOUBLE, right, FROMLEFT, &u_curr[0], 1,
     480               MPI_DOUBLE, left, FROMLEFT, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
     481}
     482
     483int main(int argc, char * argv[]) {
     484  int iter;
     485
     486  MPI_Init(&argc, &argv);
     487  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
     488  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
     489  initialization();
     490  ...
     491  for(iter = 0; iter < nsteps; iter++) {
     492    if(iter % wstep == 0)
     493      write_frame(iter);
     494    if(nxl != 0){
     495      exchange();
     496      update();
     497    }
     498  }
     499  free(u_curr);
     500  free(u_prev);
     501  free(u_next);
     502  MPI_Finalize();
     503  return 0;
     504}               
     505
     506}}}
     507
     508With the upper bound of the size of initial vector being 5, and the bound of number of steps of the computation being 5,
     509and the number of processes is restricted to be in the range [1, 4],
     510CIVL finds a violation of the assertion of the program in a few seconds. The violation is at depth 1082.
     511
     512'''Command''': civl verify -enablePrintf=false -input_mpi_nprocs=4 wave1d.c
     513
     514'''Output''':
     515{{{
     516CIVL v1.17.1+ of 2018-07-30 -- http://vsl.cis.udel.edu/civl
     517
     518Violation 0 encountered at depth 820:
     519CIVL execution violation in p1 (kind: ASSERTION_VIOLATION, certainty: PROVEABLE)
     520at wave1d.c:199.4-201.61
     521            $assert((oracle[time + 1][first + i + 1] == buf[i]), \
     522            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     523        ...
     524            time, first + i, buf[i], oracle[time + 1][first + i + 1]);
     525            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     526Assertion: (((oracle)[(time+1)])[((first+i)+1)]==*((buf+i)))
     527 -> -2*(((((X_u_init[1]+((-1/2)*X_u_init[2])+((-1/2)*X_u_init[0]))*(X_c^2))+((X_u_init[1]+(-2*X_u_init[0]))*(X_c^2))+((-1/2)*X_u_init[1])+X_u_init[0])*(X_c^2))+(-1*((X_u_init[1]+(-2*X_u_init[0]))*(X_c^2)))+((-1/2)*X_u_init[0]))==*(&<d5>heap.malloc6[0][1]+0)
     528 -> (-2*(((((X_u_init[1]+((-1/2)*X_u_init[2])+((-1/2)*X_u_init[0]))*(X_c^2))+((X_u_init[1]+(-2*X_u_init[0]))*(X_c^2))+((-1/2)*X_u_init[1])+X_u_init[0])*(X_c^2))+(-1*((X_u_init[1]+(-2*X_u_init[0]))*(X_c^2)))+((-1/2)*X_u_init[0])))==(-2*(((((X_u_init[1]+((-1/2)*X_u_init[2])+((-1/2)*X_u_init[0]))*(X_c^2))+((X_u_init[1]+(-2*X_u_init[0]))*(X_c^2))+((-1/2)*Hp1s5f8o0[0])+((-1/2)*X_u_init[1])+X_u_init[0])*(X_c^2))+(-1*((X_u_init[1]+(-2*X_u_init[0]))*(X_c^2)))+((-1/2)*X_u_init[0])))
     529 -> (0==((X_u_init[1] + (-1/2)*X_u_init[2] + (-1/2)*X_u_init[0])*(X_c^2) + (X_u_init[1] - 2*X_u_init[0])*(X_c^2) + (-1/2)*Hp1s5f8o0[0] + (-1/2)*X_u_init[1] + X_u_init[0] - 1*((X_u_init[1] + (-1/2)*X_u_init[2] + (-1/2)*X_u_init[0])*(X_c^2) + (X_u_init[1] - 2*X_u_init[0])*(X_c^2) + (-1/2)*X_u_init[1] + X_u_init[0])))||(0==X_c)
     530
     531Input:
     532  ...
     533  nx=5
     534  c=X_c
     535  nsteps=5
     536  wstep=1
     537  u_init=X_u_init
     538  _mpi_nprocs=4
     539  _mpi_nprocs_lo=1
     540  ...
     541Context:
     542  forall _t : dynamicType . (0 <= CIVL_SIZEOF(_t) - 1)
     543  0<X_c
     544  0<=(SIZEOF_REAL-1)
     545  0<=(X__civl_argc-1)
     546  0<=(X__mpi_nprocs_hi-4)
     547Call stacks:
     548process 0:
     549  main at MPITransformer "$parfor (int i: 0 .." inserted by MPITransformer.$parfor MPI_Process before wave1d.c:237.13-16 "argc"
     550process 1:
     551  printData at wave1d.c:199.4-10 "$assert" called from
     552  write_frame at wave1d.c:215.4-12 "printData" called from
     553  _civl_main at wave1d.c:268.6-16 "write_frame" called from
     554  _mpi_process at GeneralTransformer "_civl_argc, ((char*[" inserted by GeneralTransformer.new main function before wave1d.c:237.13-16 "argc" called from
     555  _par_proc0 at MPITransformer "i" inserted by MPITransformer.function call _mpi_process before wave1d.c:237.13-16 "argc"
     556process 2:
     557  $mpi_sendrecv at civl-mpi.cvl:272.6-18 "$comm_dequeue" called from
     558  MPI_Sendrecv at mpi.cvl:134.2-14 "$mpi_sendrecv" called from
     559  exchange at wave1d.c:233.2-13 "MPI_Sendrecv" called from
     560  _civl_main at wave1d.c:270.6-13 "exchange" called from
     561  _mpi_process at GeneralTransformer "_civl_argc, ((char*[" inserted by GeneralTransformer.new main function before wave1d.c:237.13-16 "argc" called from
     562  _par_proc0 at MPITransformer "i" inserted by MPITransformer.function call _mpi_process before wave1d.c:237.13-16 "argc"
     563process 3:
     564  $mpi_sendrecv at civl-mpi.cvl:272.6-18 "$comm_dequeue" called from
     565  MPI_Sendrecv at mpi.cvl:134.2-14 "$mpi_sendrecv" called from
     566  exchange at wave1d.c:231.2-13 "MPI_Sendrecv" called from
     567  _civl_main at wave1d.c:270.6-13 "exchange" called from
     568  _mpi_process at GeneralTransformer "_civl_argc, ((char*[" inserted by GeneralTransformer.new main function before wave1d.c:237.13-16 "argc" called from
     569  _par_proc0 at MPITransformer "i" inserted by MPITransformer.function call _mpi_process before wave1d.c:237.13-16 "argc"
     570process 4:
     571  $mpi_send at civl-mpi.cvl:223.2-7 "return" called from
     572  MPI_Send at mpi.cvl:90.9-17 "$mpi_send" called from
     573  write_frame at wave1d.c:226.4-11 "MPI_Send" called from
     574  _civl_main at wave1d.c:268.6-16 "write_frame" called from
     575  _mpi_process at GeneralTransformer "_civl_argc, ((char*[" inserted by GeneralTransformer.new main function before wave1d.c:237.13-16 "argc" called from
     576  _par_proc0 at MPITransformer "i" inserted by MPITransformer.function call _mpi_process before wave1d.c:237.13-16 "argc"
     577
     578Logging new entry 0, writing trace to CIVLREP/wave1d_0.trace
     579Terminating search after finding 1 violation.
     580
     581=== Source files ===
     582wave1d.c  (wave1d.c)
     583
     584=== Command ===
     585civl verify -enablePrintf=false -input_mpi_nprocs=4 wave1d.c
     586
     587=== Stats ===
     588   time (s)            : 6.98
     589   memory (bytes)      : 581959680
     590   max process count   : 5
     591   states              : 2058
     592   states saved        : 1231
     593   state matches       : 0
     594   transitions         : 2057
     595   trace steps         : 819
     596   valid calls         : 8903
     597   provers             : cvc4, z3
     598   prover calls        : 36
     599
     600=== Result ===
     601The program MAY NOT be correct.  See CIVLREP/wave1d_log.txt
     602}}}
     603
     604With "-min" option enabled, CIVL finds a minimal counterexample at depth 660 after 19.08 seconds.
     605With the help of the counterexample, one can be guided to fix [https://vsl.cis.udel.edu/lib/demo/wave1d.c wave1d.c] by adding statements to initialize u_next![0] and u_next[nxl+1] to zero,
     606yielding [https://vsl.cis.udel.edu/lib/demo/wave1d_fix.c wave1d_fix.c]. Then CIVL is applied again to verify the fix.
     607In fact, the erroneous [https://vsl.cis.udel.edu/lib/demo/wave1d.c wave1d.c] had been used for two years in a parallel computing course taught by one of us (Dr. Siegel),
     608but the defect was never noticed, apparently because the allocated memory was almost always initialized with 0s, something which is certainly not guaranteed by the C Standard.
     609
     610=== Dot product in OpenMP ===
     611Now let's look at a simple OpenMP program [https://vsl.cis.udel.edu/lib/demo/dotProduct_critical.c dotProduct_critical.c] that performs the dot product of two vectors.
     612The program is originally used as an example program for a parallel programming course.
     613
     614{{{
     615#include <omp.h>
     616...             
     617#define N 100
     618
     619int main (int argc, char *argv[]) {
     620  double a[N], b[N];
     621  double localsum, sum = 0.0;
     622  int i, tid, nthreads;
     623 
     624#pragma omp parallel shared(a,b,sum) private(i, localsum)
     625  {
     626    /* Get thread number */
     627    tid = omp_get_thread_num();
     628   
     629    /* Only master thread does this */
     630#pragma omp master
     631    {
     632      nthreads = omp_get_num_threads();
     633      printf("Number of threads = %d\n", nthreads);
     634    }
     635
     636    /* Initialization */
     637#pragma omp for
     638    for (i=0; i < N; i++)
     639      a[i] = b[i] = (double)i;
     640
     641    localsum = 0.0;
     642
     643    /* Compute the local sums of all products */
     644#pragma omp for
     645    for (i=0; i < N; i++)
     646      localsum = localsum + (a[i] * b[i]);
     647
     648#pragma omp critical
     649    sum = sum+localsum;
     650
     651  }  /* End of parallel region */
     652
     653  printf("   Sum = %2.1f\n",sum);
     654
     655#ifdef _CIVL
     656  assert(sum==328350);
     657#endif
     658  exit(0);
     659}
     660}}}
     661
     662CIVL transforms an OpenMP program to be purely CIVL-C before it performs verification on it, during which an input variable THREAD_MAX is introduced as the upper bound of the number of threads. To verify an OpenMP program, one needs to specify the value of THREAD_MAX . Here, we use 3 as THREAD_MAX for verification.
     663
     664'''Command''': civl verify -min -inputTHREAD_MAX=3 -enablePrintf=false dotProduct_critical.c
     665
     666'''Output''':
     667{{{
     668CIVL v1.17.1+ of 2018-07-30 -- http://vsl.cis.udel.edu/civl
     669
     670Violation 0 encountered at depth 1355:
     671CIVL execution violation in p2 (kind: ASSERTION_VIOLATION, certainty: PROVEABLE)
     672at OpenMPTransformer "_omp_tid_shared, &(_" inserted by OpenMPTransformer.tid_sharedWriteCall before civlc.cvh:31.22-27 "$scope" included from civl-stdio.cvh:3
     673Assertion: (otherTid<0)
     674 -> 0<0
     675 -> false
     676
     677Input:
     678  _omp_thread_max=3
     679Context:
     680  forall _t : dynamicType . (0 <= CIVL_SIZEOF(_t) - 1)
     681Call stacks:
     682process 0:
     683  ...
     684process 1:
     685  ...
     686process 2:
     687  $omp_write at civl-omp.cvl:238.2-8 "$assert" called from
     688  _par_proc0 at OpenMPTransformer "_omp_tid_shared, &(_" inserted by OpenMPTransformer.tid_sharedWriteCall before civlc.cvh:31.22-27 "$scope" included from civl-stdio.cvh:3
     689
     690Logging new entry 0, writing trace to CIVLREP/dotProduct_critical_0.trace
     691Restricting search depth to 1354
     692
     693  ...
     694
     695Violation 203 encountered at depth 38:
     696CIVL execution violation in p2 (kind: ASSERTION_VIOLATION, certainty: PROVEABLE)
     697
     698  ...
     699
     700=== Source files ===
     701dotProduct_critical.c  (dotProduct_critical.c)
     702
     703
     704=== Command ===
     705civl verify -min -input_omp_thread_max=3 -enablePrintf=false dotProduct_critical.c
     706
     707=== Stats ===
     708   time (s)            : 6.23
     709   memory (bytes)      : 322961408
     710   max process count   : 4
     711   states              : 31425
     712   states saved        : 15725
     713   state matches       : 0
     714   transitions         : 31625
     715   trace steps         : 11264
     716   valid calls         : 29990
     717   provers             : cvc4, z3
     718   prover calls        : 2
     719
     720=== Result ===
     721The program MAY NOT be correct.  See CIVLREP/dotProduct_critical_log.txt
     722}}}
     723
     724As shown by the above output, wihtin 10 seconds, CIVL dectecs a race condition and finds the minimal counterexample at depth 38 after detecting 204 violations,
     725which is much smaller than the first violation which is at depth 1355.
     726With the help of trace provided by CIVL replay for the minimal counterexample, one is guided to fix the error by adding the variable tid to the private list of the parallel construct,
     727yielding [https://vsl.cis.udel.edu/lib/demo/dotProduct_critical_fix.c dotProduct_critical_fix.c], which is verified by CIVL successfully.
     728