Shape Analysis
via 3-Valued Logic
TVLA + Applications
Mooly Sagiv
Tel Aviv University
Shape Analysis with Applications
http://www.cs.tau.ac.il/~rumster/TVLA/
1
Outline
Basic
ideas behind TVLA
TVLA for Singly Linked Lists
Reachability
Applications (next week)
2
The TVLA System
Input:
–
–
–
–
SOS using Predicate Logic
TVP
Control Flow Graph
A set of 3-valued structures at the start node
Implementation hints
TVS
Output
– The set of 3-valued structures at every control flow
node (labeled directed graphs)
– Textual error messages
3
/* list.h */
typedef struct node {
struct node *n;
int data
} *Elements;
/* create.c */
Elements create() {
Elements *f, *x;
int i, size;
for(i=0; i<size; i++) {
f = malloc(sizeof(Elements));
f->n = x;
x = f;
}
return x;
}
c2tvp create
tvla create include\empty -d
tvla create include\empty
4
typedef struct node {
struct node *n;
int data;
} *Elements;
Elements * reverse(Elements *x) {
Elements *y, *t;
y = NULL;
while (x != NULL) {
t = y;
y = x;
x = x n;
y n = t;
}
return y;
}
c2tvp reverse
tvla reverse include\list
5
// y = NULL
/* reverse.tvp */
n_1 Set_Null_L(y) n_2
%s PVar {x, y, t}
// while (x != NULL) {
#include "include\pred.tvp"
n_2 Is_Null_Var(x) exit
%%
n_2 Is_Not_Null_Var(x) n_3
#include "include\cond.tvp"
// t = y
n_3 Copy_Var_L(t, y) n_4
#include "include\stat.tvp"
// y = x
%%
n_4 Copy_Var_L(y, x) n_5
// x = x->n
n_5 Get_Next_L(x, x) n_6
// y->n = NULL
n_6 Set_Next_Null_L(y) n_7
// y->n = t
n_7 Set_Next_L(y, t) n_2
// }
6
/* create.tvp */
// for(i=0; i<size; i++) {
%s PVar {x, f}
n_1 uninterpreted() n_2
#include "include\pred.tvp"
// f = malloc(sizeof(Elements));
%%
n_2 Malloc_L(f) n_3
#include "include\cond.tvp"
// f->n = x;
#include "include\stat.tvp"
n_3 Set_Next_Null_L(f) n_4
%%
n_4 Set_Next_L(f,x) n_5
// x = f;
n_5 Copy_Var_L(x, f) n_1
n_2 uninterpreted() exit
// }
7
/* pred.tvp */
/*************** Core Predicates *************/
foreach (z in PVar) {
%p z(v_1) unique box
}
%p n(v_1, v_2) function
/**********************************************/
/*********** Instrumentation Predicates *************/
%i is[n](v) = E(v_1, v_2) ( v_1 != v_2 & n(v_1, v) & n(v_2, v))
8
/* cond.tvp */
%action uninterpreted() {
%t "uninterpreted"
}
%action Is_Not_Null_Var(x1) {
%t x1 + " != NULL"
%f { x1(v) }
%p E(v) x1(v)
}
%action Is_Null_Var(x1) {
%t x1 + " == NULL"
%f { x1(v) }
%p !(E(v) x1(v))
}
%action Is_Eq_Var(x1, x2) {
%t x1 + " == " + x2
%f { x1(v), x2(v) }
%p A(v) x1(v) <-> x2(v)
}
%action Is_Not_Eq_Var(x1, x2)
{
%t x1 + " != " + x2
%f { x1(v), x2(v) }
%p !A(v) x1(v) <-> x2(v)
}
9
stat.tvp
%action Set_Null_L(x1) {
%t x1 + " = NULL"
%action Malloc_L(x1) {
{
%t x1 + " = (L)
x1(v) = 0
malloc(sizeof(struct node)) "
}
%new
}
{
%action Copy_Var_L(x1, x2) {
x1(v) = isNew(v)
%t x1 + " = " + x2
}
%f { x2(v) }
}
{
x1(v) = x2(v)
}
}
10
stat.tvp (2)
%action Get_Next_L(x1, x2) {
%t x1 + " = " + x2 + "->" + n
%f { E(v_1) x2(v_1) & n(v_1, v) }
%message (!E(v) x2(v)) -> "an illegal dereference
to\n" +
n + " component of " + x2 + "\n"
{
x1(v) = E(v_1) x2(v_1) & n(v_1, v)
}
}
11
stat.tvp (3)
%action Set_Next_Null_L(x1) {
%t x1 + "->" + n + " = null"
%f { x1(v) }
%message (!E(v) x1(v)) -> "an illegal dereference to\n" +
n + " component of " + x1 + "\n"
{
n(v_1, v_2) = n(v_1, v_2) & !x1(v_1)
is[n](v) = is[n](v) & (!(E(v_1) x1(v_1) & n(v_1, v)) |
E(v_1, v_2) v_1 != v_2 &
(n(v_1, v) & !x1(v_1)) & (n(v_2, v) & !x1(v_2)))
}
}
12
stat.tvp (4)
%action Set_Next_L(x1, x2) {
%t x1 + "->" + n + " = " + x2
%f { x1(v), x2(v) }
%message (E(v, v1) x1(v) & n(v, v1)) ->
"Internal Error! assume that " + x1 + "->" + n + "==NULL"
%message (!E(v) x1(v)) -> "an illegal dereference to\n" +
n + " component of " + x1 + "\n"
{
n(v_1, v_2) = n(v_1, v_2) | x1(v_1) & x2(v_2)
is[n](v) = is[n](v) | E(v_1) x2(v) & n(v_1, v)
}
}
13
Typical Garbage Collector
Program
Reachability-based
Variables
a
b
c
d
e
f
14
Typical Garbage Collector
Program
Reachability-based
Variables
a
b
c
d
e
f
15
Typical Garbage Collector
Program
Reachability-based
Variables
a
b
c
d
e
f
16
Reachability
Concrete
semantics which records reachability
from stack (global) variables
Useful for:
– Compile-time Garbage Collection
– Saving calls to Dynamic Garbage Collection
» No memory leaks
– Speeding-up static analysis
Instrumentation
predicate
r[n, x](v) = E(v1) x(v1) & n*(v1, v)
17
/* list.h */
typedef struct node {
struct node *n;
int data
} *Elements;
/* create.c */
Elements create() {
Elements *f, *x;
int i, size;
for(i=0; i<size; i++) {
f = malloc(sizeof(Elements));
f->n = x;
x = f;
}
return x;
}
c2tvp create
tvla rcreate include\empty
18
typedef struct node {
struct node *n;
int data;
} *Elements;
Elements * reverse(Elements *x) {
Elements *y, *t;
y = NULL;
while (x != NULL) {
t = y;
y = x;
x = x n;
y n = t;
}
return y;
}
c2tvp reverse
tvla rreverse include\rlist
19
Elements* reverse(Elements *x)
typedef struct node {
struct node *n;
int data;
} *Elements;
c2tvp fumble
{
Elements *y,*t;
y = NULL;
while (x!= NULL) {
t = xn;
y = x;
xn = y;
x = t;
}
return y;
tvla rfumble include\rlist
20
/* rpred.tvp */
/*************** Core Predicates *************/
foreach (z in PVar) {
%p z(v_1) unique box
}
%p n(v_1, v_2) function
/**********************************************/
/*********** Instrumentation Predicates *************/
%i is[n](v) = E(v_1, v_2) ( v_1 != v_2 & n(v_1, v) & n(v_2, v))
foreach (z in PVar) {
%i r[n,z](v) = E(v_1) (z(v_1) & n*(v_1, v))
}
%i c[n](v) = n+(v, v)
21
rstat.tvp
%action Set_Null_L(x1) {
%t x1 + " = NULL“
%message … ->
{
x1(v) = 0
r[n, x](v) = 0
}
}
%action Copy_Var_L(x1, x2) {
%t x1 + " = " + x2
%f { x2(v) }
{
x1(v) = x2(v)
r[n, x](v) = 0
}
}
%action Malloc_L(x1) {
%t x1 + " = (L)
malloc(sizeof(struct node)) "
%new
{
x1(v) = isNew(v)
r[n, x](v) = isNew(v)
}
}
22
(1) Focus on v1: x(v1) cdr(v1,v)
cdr
x
y
cdr
u1
u
x
y
x
y
x
y
cdr
u
u1
cdr
cdr
u1
r[cdr]
u
cdr
cdr
cdr
cdr
u1
u.1
u.0
23
Benefit of Reachability
Predict
memory leaks
Separate disjoint data structures
More precise semantic reduction
– x = x->n
24
Optimizations in TVLA
Order
of constrains
– Eliminate cycles
Lazy
evaluation
Functional properties
Exploit sparseness
OBDD representation
Java representation
25
TVLA Design Mistakes
The
operational semantics is written in too low
level language
–
–
–
–
–
–
No types
No local updates to specific predicate values
No constants and functions
No means for modularity
No local variables and sequencing
Combines UI with functionality
TVP can
be a high level language
TVLA3VLA
26
TVLA Experience
Quite
fast on small programs
– But runs on medium programs too
Not
a panacea
More instrumentation may lead to faster (and
more precise) analysis
27
© Copyright 2026 Paperzz