Skip to content

Gillian-JS: Symbolic Test Results

We symbolically test Buckets.js, a real-world JavaScript data structure library, with the goal of obtaining 100% line coverage. The results are presented in the table below, with each row containing:

  • The name of the folder being tested, which also indicates the data structure in question
  • The number of tests required for 100% line coverage
  • The total number of GIL commands executed by running these tests
  • The total testing time (in seconds)

Testing results

Data StructureTestsGIL CommandsTime (s)
arrays9330,1472.678
bag71,343,3935.064
bstree113,751,09212.507
dictionary7401,5751.833
heap41,492,2043.411
linkedlist9588,7144.141
multidictionary61,106,6503.803
queue6407,1062.140
priorityqueue52,312,2264.121
set62,178,2224.458
stack4306,4491.625
Total7414,217,77845.781

The results are 1.3% slower and the number of executed GIL commands is 0.1% greater than reported in the submitted version—we will update accordingly. This is due to minor changes to the JS-2-GIL compiler and the JS symbolic engine.

Reproducing the results

Starting from the Gillian folder, execute the following:

bash
dune build
make js-init-env
cd Gillian-JS/environment

Then, to reproduce the results for a specific folder from the first column of the above table, execute the following:

bash
./testCosetteFolder.sh Examples/Cosette/Buckets/<folder>

In order to obtain the number of executed commands, append the count parameter to the last command. Therefore, for example, the command to run the tests for the queue data structure and obtain the number of executed commands is:

bash
./testCosetteFolder.sh Examples/Cosette/Buckets/queue count

Note: The times obtained when counting executed commands will be slower, due to the fact that the tests will be run in single-thread mode.

Detailed per-folder breakdown: Buckets.js

arrays123456789Total
Time (s)0.2590.2880.2640.2640.2590.2850.2580.5690.2322.678
GIL Commands33,90334,67534,89642,86630,48355,21034,76539,53223,817330,147
bag1234567Total
Time (s)0.5010.4530.9630.6410.5770.9231.0065.064
GIL Commands99,39560,935301,687208,336158,635200,411313,9941,343,393
bstree1234567891011Total
Time (s)0.7462.5400.6840.7631.0151.0281.0131.1310.7620.7622.06312.507
GIL Commands123,7981,254,63572,637169,155192,683192,683191,633390,919100,266177,362885,3213,751,092
dictionary1234567Total
Time (s)0.2750.2380.2170.3520.2290.2170.3051.833
GIL Commands61,16154,14044,56955,03355,91441,90488,854401,575
heap1234Total
Time (s)0.5171.4870.6290.7783.411
GIL Commands135,140804,659169,522382,8831,492,204
linkedlist123456789Total
Time (s)0.6480.5770.6030.4380.2930.2950.2570.7180.3124.141
GIL Commands43,20957,45897,72882,34563,64566,09330,79497,22550,217588,714
multidictionary123456Total
Time (s)0.5040.8130.5660.5790.6780.6633.803
GIL Commands130,145312,351166,638145,627158,934192,9551,106,650
queue123456Total
Time (s)0.3320.3450.3450.2490.4030.4662.140
GIL Commands71,51469,96245,06736,76762,624121,172407,106
priorityqueue12345Total
Time (s)0.7570.7310.4490.9931.1914.121
GIL Commands399,730287,433121,329450,5391,053,1952,312,226
set123456Total
Time (s)0.3860.6791.7430.6220.2920.7364.458
GIL Commands78,959242,3041,265,278232,77666,700292,2052,178,222
stack1234Total
Time (s)0.3430.3310.3310.6201.625
GIL Commands52,23344,95855,097154,161306,449

Reproducing the Buckets.js bugs found by Cosette and JaVerT 2.0

Starting from the Gillian folder, execute:

bash
dune build
make js-init-env
cd Gillian-JS/environment

[Cosette] multi-dictionary bug

In order to reproduce the multi-dictionary bug reported by [Cosette], execute:

bash
./testCosette.sh Examples/Cosette/Buckets/multidictionary/bug/multidictionary_bug.js

You will obtain a failing model

Assert failed with argument False.
Failing Model:
  [ (#x1: #x2) ]

The bug is caused by the library wrongly treating the case in which we try to remove a key-value pair for a key with no associated values. The code of the test is as follows:

js
var dict = new buckets.MultiDictionary()

var s = symb_string(s);
var x1 = symb_number(x1);
var x2 = symb_number(x2);

dict.set(s, x1);
dict.set(s, x2);

dict.remove(s, x1);
var res = dict.remove(s, x2);
Assert(((not (x1 = x2)) and (res = true)) or ((x1 = x2) and (res = false)));

The test puts two symbolic numbers, x1 and x2 for the same symbolic key s into an empty multi-dictionary, then removes x1, and then removes x2 and registers the value returned by remove(). Then, it asserts that that value was true if the two keys were different, and false if the two keys were the same. What the failing model says is that, when the two keys are equal, the library, in fact, throws a native JavaScript error (indicated by the argument False of the failed assert).

JaVerT 2.0 linked-list bugs

In order to reproduce the linked-list bugs reported by JaVerT 2.0, execute:

bash
./testCosette.sh Examples/Cosette/Buckets/linkedlist/bug/linkedlist_bug_1.js
./testCosette.sh Examples/Cosette/Buckets/linkedlist/bug/linkedlist_bug_2.js
./testCosette.sh Examples/Cosette/Buckets/linkedlist/bug/linkedlist_bug_3.js

All of the bugs are causes by the library treating non-integer indexing incorrectly; we explain the bug found by the first test in detail, the remaining two are analogous. For the first test, the failing model is as follows:

Assert failed with argument
  ((((#x3 == 0) /\ (#x2 == #x1)) \/
    ((#x3 == 1) /\ (#x2 == #x2))) \/
    (((! (#x3 == 0)) /\ (! (#x3 == 1))) /\ (#x2 == undefined))).
Failing Model:
  [ (#x2: 4), (#x3: 0.5), (#x1: 3) ]

The code of the test is as follows:

js
var list = new buckets.LinkedList()

var x1 = symb_number(x1);
var x2 = symb_number(x2);
var x3 = symb_number(x3);

list.add(x1)
list.add(x2)

var res = list.elementAtIndex(x3);
Assert( (((x3 = 0) and (res = x1)) or
         ((x3 = 1) and (res = x2))) or
         (((not (x3 = 0)) and (not (x3 = 1))) and (res = undefined)) );

The test inserts two symbolic numbers, x1 and x2, into an empty linked list, and then indexes the list with a third symbolic number, x3. The expected outcome is that: if x3 = 0, the indexing returns x1; if x3 = 1, the indexing returns x2; and, otherwise, the indexing returns undefined. The failing model, however, says that if x3 = 0.5, the indexing will also return x2.