Skip to content

Commit 85a1e8f

Browse files
smowtonromainbrenguier
authored andcommitted
Add tests for array-cell sensitivity
Most are for C, then a couple are duplicated for Java to check whether its use of a structure to represent all arrays makes any difference.
1 parent aa39f07 commit 85a1e8f

File tree

34 files changed

+546
-0
lines changed

34 files changed

+546
-0
lines changed
Binary file not shown.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public class Test {
2+
3+
public static void main(int unknown) {
4+
5+
int[] x = new int[10];
6+
x[unknown] = 1;
7+
x[1] = unknown;
8+
assert (x[1] == unknown);
9+
}
10+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
CORE
2+
Test.class
3+
--function Test.main --show-vcc
4+
symex_dynamic::dynamic_2_array#2\[\[0\]\] = symex_dynamic::dynamic_2_array#2\[0\]
5+
symex_dynamic::dynamic_2_array#2\[\[1\]\] = symex_dynamic::dynamic_2_array#2\[1\]
6+
symex_dynamic::dynamic_2_array#2\[\[2\]\] = symex_dynamic::dynamic_2_array#2\[2\]
7+
symex_dynamic::dynamic_2_array#2\[\[3\]\] = symex_dynamic::dynamic_2_array#2\[3\]
8+
symex_dynamic::dynamic_2_array#2\[\[4\]\] = symex_dynamic::dynamic_2_array#2\[4\]
9+
symex_dynamic::dynamic_2_array#2\[\[5\]\] = symex_dynamic::dynamic_2_array#2\[5\]
10+
symex_dynamic::dynamic_2_array#2\[\[6\]\] = symex_dynamic::dynamic_2_array#2\[6\]
11+
symex_dynamic::dynamic_2_array#2\[\[7\]\] = symex_dynamic::dynamic_2_array#2\[7\]
12+
symex_dynamic::dynamic_2_array#2\[\[8\]\] = symex_dynamic::dynamic_2_array#2\[8\]
13+
symex_dynamic::dynamic_2_array#2\[\[9\]\] = symex_dynamic::dynamic_2_array#2\[9\]
14+
symex_dynamic::dynamic_2_array#3\[\[1\]\] = java::Test.main:\(I\)V::unknown!0@1#1
15+
^EXIT=0$
16+
^SIGNAL=0$
17+
--
18+
symex_dynamic::dynamic_2_array#3\[\[[023456789]\]\] =
19+
--
20+
This checks that a write to a Java array with an unknown index uses a whole-array
21+
write followed by array-cell expansion, but one targeting a constant index uses
22+
a single-cell symbol without expansion.
Binary file not shown.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
public class Test {
2+
3+
public int data;
4+
public Test[] children = new Test[2];
5+
6+
public static void main(int unknown) {
7+
8+
Test[] root = new Test[2];
9+
Test node1 = new Test();
10+
Test node2 = new Test();
11+
root[0] = node1;
12+
root[1] = node2;
13+
node1.children[0] = unknown % 2 == 0 ? node1 : node2;
14+
node1.children[1] = unknown % 3 == 0 ? node1 : node2;
15+
node2.children[0] = unknown % 5 == 0 ? node1 : node2;
16+
node2.children[1] = unknown % 7 == 0 ? node1 : node2;
17+
int idx1 = 0, idx2 = 1, idx3 = 1, idx4 = 0;
18+
root[idx1].children[idx2].children[idx3].children[idx4].data = 1;
19+
assert (node1.data == 1);
20+
}
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
Test.class
3+
--function Test.main --show-vcc
4+
symex_dynamic::dynamic_object6#3\.\.data =
5+
symex_dynamic::dynamic_object3#3\.\.data =
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
symex_dynamic::dynamic_object6#3\.\.data = symex_dynamic::dynamic_object6#3\.data
10+
symex_dynamic::dynamic_object3#3\.\.data = symex_dynamic::dynamic_object3#3\.data
11+
--
12+
This checks that a write using a mix of field and array accessors uses a field-sensitive
13+
symbol (the data field of the possible ultimate target objects) rather than using
14+
a whole-struct write followed by an expansion.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char **argv)
4+
{
5+
int array[10];
6+
array[argc] = 1;
7+
array[1] = argc;
8+
assert(array[1] == argc);
9+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::array!0@1#2\[\[1\]\] = main::1::array!0@1#1\[1\]
5+
main::1::array!0@1#2\[\[2\]\] = main::1::array!0@1#1\[2\]
6+
main::1::array!0@1#2\[\[3\]\] = main::1::array!0@1#1\[3\]
7+
main::1::array!0@1#2\[\[4\]\] = main::1::array!0@1#1\[4\]
8+
main::1::array!0@1#2\[\[5\]\] = main::1::array!0@1#1\[5\]
9+
main::1::array!0@1#2\[\[6\]\] = main::1::array!0@1#1\[6\]
10+
main::1::array!0@1#2\[\[7\]\] = main::1::array!0@1#1\[7\]
11+
main::1::array!0@1#2\[\[8\]\] = main::1::array!0@1#1\[8\]
12+
main::1::array!0@1#2\[\[9\]\] = main::1::array!0@1#1\[9\]
13+
main::1::array!0@1#3\[\[1\]\] =
14+
^EXIT=0$
15+
^SIGNAL=0$
16+
--
17+
main::1::array!0@1#[2-9]\[[0-9]+\]
18+
--
19+
This checks that a write with a non-constant index leads to a whole-array
20+
operation followed by expansion into individual array cells, while a write with
21+
a constant index leads to direct use of a single cell symbol
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <assert.h>
2+
3+
struct A
4+
{
5+
int x;
6+
int y;
7+
};
8+
9+
int main(int argc, char **argv)
10+
{
11+
struct A array[10];
12+
struct A *ptr = argc % 2 ? (struct A *)&argc : &array[0];
13+
ptr[argc].x = 1;
14+
ptr[1].x = argc;
15+
assert(array[1].x == argc);
16+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::array!0@1#2\[\[0\]\]..x = main::1::array!0@1#1\[0\].x
5+
main::1::array!0@1#2\[\[1\]\]..x = main::1::array!0@1#1\[1\].x
6+
main::1::array!0@1#2\[\[2\]\]..x = main::1::array!0@1#1\[2\].x
7+
main::1::array!0@1#2\[\[3\]\]..x = main::1::array!0@1#1\[3\].x
8+
main::1::array!0@1#2\[\[4\]\]..x = main::1::array!0@1#1\[4\].x
9+
main::1::array!0@1#2\[\[5\]\]..x = main::1::array!0@1#1\[5\].x
10+
main::1::array!0@1#2\[\[6\]\]..x = main::1::array!0@1#1\[6\].x
11+
main::1::array!0@1#2\[\[7\]\]..x = main::1::array!0@1#1\[7\].x
12+
main::1::array!0@1#2\[\[8\]\]..x = main::1::array!0@1#1\[8\].x
13+
main::1::array!0@1#2\[\[9\]\]..x = main::1::array!0@1#1\[9\].x
14+
main::1::array!0@1#3\[\[1\]\]..x =
15+
main::1::array!0@1#2\[\[0\]\]..y = main::1::array!0@1#1\[0\].y
16+
main::1::array!0@1#2\[\[1\]\]..y = main::1::array!0@1#1\[1\].y
17+
main::1::array!0@1#2\[\[2\]\]..y = main::1::array!0@1#1\[2\].y
18+
main::1::array!0@1#2\[\[3\]\]..y = main::1::array!0@1#1\[3\].y
19+
main::1::array!0@1#2\[\[4\]\]..y = main::1::array!0@1#1\[4\].y
20+
main::1::array!0@1#2\[\[5\]\]..y = main::1::array!0@1#1\[5\].y
21+
main::1::array!0@1#2\[\[6\]\]..y = main::1::array!0@1#1\[6\].y
22+
main::1::array!0@1#2\[\[7\]\]..y = main::1::array!0@1#1\[7\].y
23+
main::1::array!0@1#2\[\[8\]\]..y = main::1::array!0@1#1\[8\].y
24+
main::1::array!0@1#2\[\[9\]\]..y = main::1::array!0@1#1\[9\].y
25+
^EXIT=0$
26+
^SIGNAL=0$
27+
--
28+
--
29+
This checks that a write with a non-constant index leads to a whole-array
30+
operation followed by expansion into individual array cells, while a write with
31+
a constant index leads to direct use of a single cell symbol, for the case where
32+
the array element is struct-typed and accessed via a pointer.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <assert.h>
2+
3+
struct A
4+
{
5+
int x;
6+
int y;
7+
};
8+
9+
int main(int argc, char **argv)
10+
{
11+
struct A array[10];
12+
int *ptr = argc % 2 ? &argc : &array[0].y;
13+
*ptr = argc;
14+
assert(array[1].y == argc);
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::array!0@1#2\[\[0\]\]..y =
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
main::1::array!0@1#[2-9]\[\[[1-9]\]\]
9+
main::1::array!0@1#[3-9]\[\[[0-9]\]\]
10+
--
11+
This checks that an array access made via a pointer to a member of the array's
12+
element struct type is executed using a field-sensitive symbol.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <assert.h>
2+
3+
struct A
4+
{
5+
int x;
6+
int y;
7+
};
8+
9+
int main(int argc, char **argv)
10+
{
11+
struct A array[10];
12+
int *ptr = argc % 2 ? &array[0].x : &array[0].y;
13+
*ptr = argc;
14+
assert(array[0].y == argc);
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FUTURE
2+
test.c
3+
--show-vcc
4+
main::1::array!0@1#2\[\[0\]\]..x =
5+
main::1::array!0@1#2\[\[0\]\]..y =
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
main::1::array!0@1#[2-9]\[\[[1-9]\]\]
10+
main::1::array!0@1#[3-9]\[\[[0-9]\]\]
11+
--
12+
Ideally we should handle accesses to a pointer with a finite set of possible
13+
referents precisely, but because value_sett regards &array[0].x and &array[0].y
14+
as two different offsets into the same allocation and discards the precise offsets
15+
they point to, this is currently handled imprecisely with a byte_update operation.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <assert.h>
2+
3+
struct A
4+
{
5+
int data;
6+
struct A *children[2];
7+
};
8+
9+
int main(int argc, char **argv)
10+
{
11+
struct A root;
12+
struct A node1, node2;
13+
root.children[0] = argc % 2 ? &node1 : &node2;
14+
root.children[1] = argc % 3 ? &node1 : &node2;
15+
node1.children[0] = argc % 5 ? &node1 : &node2;
16+
node1.children[1] = argc % 7 ? &node1 : &node2;
17+
node2.children[0] = argc % 11 ? &node1 : &node2;
18+
node2.children[1] = argc % 13 ? &node1 : &node2;
19+
root.children[0]->children[1]->children[1]->children[0]->data = 1;
20+
assert(node1.data == argc);
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::node1!0@1#2\.\.data =
5+
main::1::node2!0@1#2\.\.data =
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
main::1::node1!0@1#[3-9]\.\.children\[\[[01]\]\] =
10+
--
11+
This checks that mixed array and field accesses are executed using a field-sensitive
12+
symbol (main::1::node1!0@1#2..data) rather than by assigning the whole struct and
13+
expanding into field symbols (which would assign main::1::node1!0@1#3..children\[\[[01]\]\])
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <assert.h>
2+
3+
struct A
4+
{
5+
int data;
6+
struct A *children[2];
7+
};
8+
9+
int main(int argc, char **argv)
10+
{
11+
struct A root;
12+
struct A node1, node2;
13+
root.children[0] = argc % 2 ? &node1 : &node2;
14+
root.children[1] = argc % 3 ? &node1 : &node2;
15+
node1.children[0] = argc % 5 ? &node1 : &node2;
16+
node1.children[1] = argc % 7 ? &node1 : &node2;
17+
node2.children[0] = argc % 11 ? &node1 : &node2;
18+
node2.children[1] = argc % 13 ? &node1 : &node2;
19+
int idx1 = 0, idx2 = 1, idx3 = 1, idx4 = 0;
20+
root.children[idx1]->children[idx2]->children[idx3]->children[idx4]->data = 1;
21+
assert(node1.data == argc);
22+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::node1!0@1#2\.\.data =
5+
main::1::node2!0@1#2\.\.data =
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
main::1::node1!0@1#[3-9]\.\.children\[\[[01]\]\] =
10+
--
11+
This checks that mixed array and field accesses are executed using a field-sensitive
12+
symbol (main::1::node1!0@1#2..data) rather than by assigning the whole struct and
13+
expanding into field symbols (which would assign main::1::node1!0@1#3..children\[\[[01]\]\]),
14+
for the case where the array indices only become constant after propagation.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char **argv)
4+
{
5+
int array[argc];
6+
array[argc - 1] = 1;
7+
array[1] = argc;
8+
assert(array[1] == argc);
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::array!0@1#2 = with\(main::1::array!0@1#1, cast\(-1 \+ main::argc!0@1#1, signedbv\[64\]\), 1\)
5+
main::1::array!0@1#3 = with\(main::1::array!0@1#2, 1, main::argc!0@1#1\)
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
\[\[[0-9]+\]\]
10+
--
11+
This checks that arrays of uncertain size are always treated as aggregates and
12+
are not expanded into individual cell symbols (which use the [[index]] notation
13+
to distinguish them from the index operator (array[index]))
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char **argv)
4+
{
5+
int array[10];
6+
int *ptr = argc % 2 ? &argc : &array[0];
7+
ptr[argc] = 1;
8+
ptr[1] = argc;
9+
assert(array[1] == argc);
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::array!0@1#2\[\[0]\] = main::1::array!0@1#1\[0\]
5+
main::1::array!0@1#2\[\[1\]\] = main::1::array!0@1#1\[1\]
6+
main::1::array!0@1#2\[\[2\]\] = main::1::array!0@1#1\[2\]
7+
main::1::array!0@1#2\[\[3\]\] = main::1::array!0@1#1\[3\]
8+
main::1::array!0@1#2\[\[4\]\] = main::1::array!0@1#1\[4\]
9+
main::1::array!0@1#2\[\[5\]\] = main::1::array!0@1#1\[5\]
10+
main::1::array!0@1#2\[\[6\]\] = main::1::array!0@1#1\[6\]
11+
main::1::array!0@1#2\[\[7\]\] = main::1::array!0@1#1\[7\]
12+
main::1::array!0@1#2\[\[8\]\] = main::1::array!0@1#1\[8\]
13+
main::1::array!0@1#2\[\[9\]\] = main::1::array!0@1#1\[9\]
14+
main::1::array!0@1#3\[\[1\]\] =
15+
^EXIT=0$
16+
^SIGNAL=0$
17+
--
18+
main::1::array!0@1#[2-9]\[[0-9]+\]
19+
--
20+
This checks that a write with a non-constant index leads to a whole-array
21+
operation followed by expansion into individual array cells, while a write with
22+
a constant index leads to direct use of a single cell symbol, even when the
23+
array is accessed via a pointer with other possible aliases.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <assert.h>
2+
3+
int main(int argc, char **argv)
4+
{
5+
int array[10];
6+
int x = 1;
7+
array[argc] = 1;
8+
array[x] = argc;
9+
assert(array[1] == argc);
10+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
CORE
2+
test.c
3+
--show-vcc
4+
main::1::array!0@1#2\[\[1\]\] = main::1::array!0@1#1\[1\]
5+
main::1::array!0@1#2\[\[2\]\] = main::1::array!0@1#1\[2\]
6+
main::1::array!0@1#2\[\[3\]\] = main::1::array!0@1#1\[3\]
7+
main::1::array!0@1#2\[\[4\]\] = main::1::array!0@1#1\[4\]
8+
main::1::array!0@1#2\[\[5\]\] = main::1::array!0@1#1\[5\]
9+
main::1::array!0@1#2\[\[6\]\] = main::1::array!0@1#1\[6\]
10+
main::1::array!0@1#2\[\[7\]\] = main::1::array!0@1#1\[7\]
11+
main::1::array!0@1#2\[\[8\]\] = main::1::array!0@1#1\[8\]
12+
main::1::array!0@1#2\[\[9\]\] = main::1::array!0@1#1\[9\]
13+
main::1::array!0@1#3\[\[1\]\] =
14+
^EXIT=0$
15+
^SIGNAL=0$
16+
--
17+
--
18+
This checks that a write with a non-constant index leads to a whole-array
19+
operation followed by expansion into individual array cells, while a write with
20+
a constant index leads to direct use of a single cell symbol, even when the
21+
constant index is only revealed as constant after propagation.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
int main(int argc, char **argv)
5+
{
6+
int *array = malloc(sizeof(int) * 10);
7+
array[argc] = 1;
8+
array[1] = argc;
9+
assert(array[1] == argc);
10+
}

0 commit comments

Comments
 (0)