A runtime monitor enforcing a constraint on sequences of method calls on an object must keep track of the state of the sequence by updating an appropriate state machine. The present paper stems from the observation that an object's member fields must already contain an encoding of that state machine, and that a monitor essentially duplicates operations that the object performs internally. Rather than maintain a state machine in parallel, the paper puts forward the concept of "piggyback" runtime monitoring, where the monitor relies as much as possible on the object's own state variables to perform its task. Experiments on real-world benchmarks show that this approach greatly simplifies the monitoring process and drastically reduces the incurred runtime overhead compared to classical solutions.
La quantification du premier ordre en logique temporelle
A Case for "Piggyback" Runtime Monitoring
1. THE FOLLOWING TALK HAS BEEN APPROVED FOR
OPEN-MINDED AUDIENCES
S SCIENTIFIC RESEARCH CONTENT
CONTROVERSIAL IDEAS, CONJECTURES
BACKED BY PRELIMINARY EXPERIMENTAL DATA
R
6. A Case for "Piggyback"
Runtime Monitoring
Raphaël Tremblay-Lessard and Sylvain Hallé
Laboratoire d'informatique formelle
Université du Québec à Chicoutimi, Canada
Fonds de recherche
sur la nature
et les technologies NSERC
CRSNG
20. We consider a set A of method calls on a
single instance of some class C
21. We consider a set A of method calls on a
single instance of some class C
C distinguishes between “valid” and
“invalid” sequences of method calls in A
22. We consider a set A of method calls on a
single instance of some class C
C distinguishes between “valid” and
“invalid” sequences of method calls in A
C is deterministic: for every sequence
m ∈ A*, m is either always valid or
always invalid
45. aspect Monitor (MyHouse m) {
MyProgram: int state = 0;
pointcut before carLeaves() {
if (state == 0)
state = 1;
m1.carLeaves(); }
pointcut before carReturns() {
if (state == 1)
state = 0;
m2.mailman(); }
pointcut before mailman() {
if (state == 1)
m1.pickMail(); state = 2;
}
pointcut before pickMail() {
if (state == 2)
. . . state = 1;
}
46. aspect Monitor (MyHouse m) {
MyProgram: int state = 0;
pointcut before carLeaves() {
if (state == 0)
state = 1;
m1.carLeaves(); }
pointcut before carReturns() {
if (state == 1)
state = 0;
m2.mailman(); }
pointcut before mailman() {
if (state == 1)
m1.pickMail(); state = 2;
}
pointcut before pickMail() {
if (state == 2)
. . . state = 1;
}
56. class MyHouse {
aspect Monitor (MyHouse m) {
int state = 0;
boolean isHome = false;
boolean hasMail = false;
pointcut before carLeaves() {
if (state == 0)
public void carLeaves() {
state = 1;
isHome = false;
}
}
pointcut before carReturns() {
public void carReturns() {
if (state == 1)
isHome = true;
state = 0;
}
}
public void mailman() {
pointcut before mailman() {
hasMail = true;
if (state == 1)
}
state = 2;
public void pickMail() {
}
if (hasMail && !isHome)
pointcut before pickMail() {
hasMail = false;
if (state == 2)
else Do Something Bad;
state = 1;
}
}
}
57. class MyHouse {
aspect Monitor (MyHouse m) {
boolean isHome = false;
boolean hasMail = false;
public void carLeaves() {
isHome = false;
}
public void carReturns() {
isHome = true;
}
public void mailman() {
hasMail = true;
}
public void pickMail() {
if (hasMail && !isHome)
pointcut before pickMail() {
hasMail = false;
if (m.isHome || !m.hasMail)
else Do Something Bad;
// Error
}
}
}
58. class MyHouse {
aspect Monitor (MyHouse m) {
boolean isHome = false;
boolean hasMail = false;
No state to persist
public void carLeaves() {
isHome = false;
} Only one method to
public void carReturns() {
isHome = true; watch
}
public void mailman() {
hasMail = true; Same effect !
}
public void pickMail() {
if (hasMail && !isHome)
pointcut before pickMail() {
hasMail = false;
if (m.isHome || !m.hasMail)
else Do Something Bad;
// Error
}
}
}
59. Key point (again)
The first monitor observes method calls to
deduce the object's current state
The second monitor rather "piggybacks"
on the object's own state
60. Key point (again)
The first monitor observes method calls to
deduce the object's current state
The second monitor rather "piggybacks"
on the object's own state
PIGGYBACK RUNTIME
MONITORING
61. On an Iterator i, method i.next() should
only be called...
62. On an Iterator i, method i.next() should
only be called...
if it immediately
follows i.hasNext()
63. On an Iterator i, method i.next() should
only be called...
if it immediately if it has more elements
follows i.hasNext() to enumerate
64. On an Iterator i, method i.next() should
only be called...
if it immediately if it has more elements
follows i.hasNext() to enumerate
history-based
65. On an Iterator i, method i.next() should
only be called...
if it immediately if it has more elements
follows i.hasNext() to enumerate
history-based state-based
71. Let ~ be an equivalence relation between
two sequences m, m' ∈ A* of method
calls
72. Let ~ be an equivalence relation between
two sequences m, m' ∈ A* of method
calls
m ~ m' ⇔ for every m'' ∈ A*,
both mm'' and m'm'' are
either valid or invalid
[m] = equivalence class of m
73. Let S = { [m] : m ∈ A*}.
The relation ~ induces a transition
function ω : S × A → S ; namely
ω([m],m) = [mm]
C behaves like a deterministic
state machine O = 〈S,[ε],ω〉
75. ε a [m12
O b [m12]
M [m10] b
a
[m6] [m9]
a
c a a
b a
[m4] b [m2]
a b
b
c a
[m1]
[m8] [m5]
ε a
b a
a [m3]
b [m7]
[m
[m0] a
b
c [m11] ε
76. ε a [m12
O b [m12]
M [m10] b
a
[m6] [m9]
a
c a a
b a
[m4] b [m2]
a b
b
c a
[m1]
[m8] [m5]
ε a
b a
a [m3]
b [m7]
[m
[m0] a
b
c [m11] ε
77. ε a [m12
O b [m12]
M [m10] b
All states of O
a
[m9]
[m6]
are accounted for
a
a a
c
b a
[m4] b [m2]
a b
b
No state of O c a
has two colors [m1]
[m8] [m5]
ε a
b a
a [m3]
b [m7]
[m
[m0] a
b
c [m11] ε
78. ε a [m12
O b [m12]
M [m10] b
All states of O
a
[m9]
[m6]
are accounted for
a
a a
c
(δ bis total)
a
[m4] b [m2]
a b
b
No state of O c a
has two colors [m1]
[m8] [m5]
ε a
(otherwise O and M b a
disagree on some m)
a [m3]
b [m7]
[m
[m0] a
b
c [m11] ε
79. ε a [m12
O b [m12]
M [m10] b
All states of O
a There exists a [m ]
are accounted for
a mapping ]
a
[m
a
6
9
c
(δ bis total) H : S→Q
a
[m ] b [m ]
a
such that H is a b 4 2
b
No state of O graph
c a
has two colors [m ]
homomorphism ]
1
[m ] [m
a
8 5
(otherwise O and M 〈S,ω〉 →b〈Q,δ〉 a
ε
disagree on some m) (just take the color!)
a [m ]
3
b [m7]
[m
[m0] a
b
c [m11] ε
80. 1 Wait for method call m ∈ A
2 Fetch s
3 Compute q = δ(H(s), m)
4 If q = then raise error
5 Else goto 1
81. 1 Wait for method call m ∈ A
2 Fetch s
3 Compute q = δ(H(s), m)
4 If q = then raise error
5 Else goto 1
Memory-less (nothing to persist
between calls)
Only monitor calls that may
lead to
82. Collection of 13 different monitoring
properties in papers from 2001-2011
(java.util package: the “monitoring canon”)
83. Collection of 13 different monitoring
properties in papers from 2001-2011
(java.util package: the “monitoring canon”)
Given an Iterator i on a Collection c, i.next()
cannot follow any of c.add(), c.delete(), c.set()
Given an Iterator i, i.remove() should not be called
twice without a call to i.next() in between
Don’t use an InputStreamReader after its
InputStream was closed
...
84. Source code analysis of the OpenJDK 6
implementation of Java. Of the 13 properties
in the canon:
85. Source code analysis of the OpenJDK 6
implementation of Java. Of the 13 properties
in the canon:
10 can be piggyback-monitored
86. Source code analysis of the OpenJDK 6
implementation of Java. Of the 13 properties
in the canon:
10 can be piggyback-monitored
Remaining 3 either...
87. Source code analysis of the OpenJDK 6
implementation of Java. Of the 13 properties
in the canon:
10 can be piggyback-monitored
Remaining 3 either...
don't distinguish between
valid/invalid calls
88. Source code analysis of the OpenJDK 6
implementation of Java. Of the 13 properties
in the canon:
10 can be piggyback-monitored
Remaining 3 either...
don't distinguish between
valid/invalid calls
violate deterministic condition
94. The graph homomorphism
problem
Finding an homomorphism H between
two directed graphs G and G' is NP-
complete.
(Known result)
⇒ Checking if a known H “works” is
polynomial
97. cla
ss
flo B
a
A a t w;
cla int
;
ss D d j;
int C ;
B b x;
... ;
Wait a minute...
98. cla
ss
cla flo A
ss a
int t z;
flo B k;
a
A a t w;
cla int
;
ss D d j;
int C ;
B b x;
... ;
Wait a minute...
99. cla
ss
cla flo A
ss a
int t z;
flo B k;
a
A a t w;
cla int
;
ss D d j;
int C ;
B b x; cla
ss
... ;
... D
Wait a minute...
100. cla
ss
cla flo A
ss a
int t z;
flo B k;
a
A a t w;
cla int
;
ss D d j;
int C ;
B b x; cla
ss
... ;
... D
Wait a minute...
101. cla
ss
cla flo A
ss a
int t z;
flo B k;
a
A a t w;
cla int
;
ss D d j;
int C ;
B b x; cla
ss
... ;
... D
Wait a minute...
How many fields are
involved?
103. Propert y REMOVE
Traditional version
Given an Iterator i, i.remove() should
not be called twice without a call to
i.next() in between
104. Propert y REMOVE
Traditional version
Given an Iterator i, i.remove() should
not be called twice without a call to
i.next() in between
Piggyback version
Given an Iterator i, in every call to
i.remove(), it must hold that i.lastRet
must not be equal to −1
105. Propert y REMOVE
Traditional version
Given an Iterator i, i.remove() should
not be called twice without a call to
i.next() in between
Piggyback version
1
Given an Iterator i, in every call to
member field
i.remove(), it must hold that i.lastRet
involved
must not be equal to −1
107. Propert y SAFEENUM
Traditional version
Given an Iterator i on a Collection c,
i.next() cannot follow any of c.add(),
c.delete(), c.set(), etc.
108. Propert y SAFEENUM
Traditional version
Given an Iterator i on a Collection c,
i.next() cannot follow any of c.add(),
c.delete(), c.set(), etc.
Piggyback version
Given an Itr i, in every call to i.next(),
it must hold that i.expectedModCount is
equal to i$0.modCount
109. Propert y SAFEENUM
Traditional version
Given an Iterator i on a Collection c,
i.next() cannot follow any of c.add(),
c.delete(), c.set(), etc.
Piggyback version
2
Given an Itr i, in every call to i.next(),
member fields
it must hold that i.expectedModCount is
involved
equal to i$0.modCount
110. With the OpenJDK 6, the 10 piggyback
properties involved at most _______
primitive member fields inside a class
111. With the OpenJDK 6, the 10 piggyback
2
properties involved at most _______
primitive member fields inside a class
112. With the OpenJDK 6, the 10 piggyback
2
properties involved at most _______
primitive member fields inside a class
at a level of nesting of at most _______
113. With the OpenJDK 6, the 10 piggyback
2
properties involved at most _______
primitive member fields inside a class
1
at a level of nesting of at most _______
114. With the OpenJDK 6, the 10 piggyback
2
properties involved at most _______
primitive member fields inside a class
1
at a level of nesting of at most _______
H is simple and shallow
115. With the OpenJDK 6, the 10 piggyback
2
properties involved at most _______
primitive member fields inside a class
1
at a level of nesting of at most _______
H is simple and shallow
...but many fields are private and have
no accessor methods ☹
116. Propert y SAFEF ILE READER
Traditional version
Don’t use an InputStreamReader after its
InputStream was closed
Piggyback version
Given an InputStreamReader r, in every
call to r.read(), it must hold that
r.sd.isOpen is true
117. Propert y SAFEF ILE READER
Traditional version
Don’t use an InputStreamReader after its
InputStream was closed
Piggyback version
Given an InputStreamReader r, in every
call to r.read(), it must hold that
r.sd.isOpen is true
private
118. class InputStreamReader {
private InputStream sd;
public boolean isStreamOpen()
{
return sd.isOpen();
}
class InputStream {
...
private boolean isOpen;
}
public boolean isOpen()
{
return isOpen;
}
...
}
119. class InputStreamReader {
private InputStream sd;
public boolean isStreamOpen()
{
return sd.isOpen();
} MISSING class InputStream {
...
private boolean isOpen;
}
public boolean isOpen()
{
return isOpen;
}
...
}
120. class InputStreamReader {
private InputStream sd;
public boolean isStreamOpen()
{
return sd.isOpen();
} MISSING class InputStream {
...
private boolean isOpen;
}
public boolean isOpen()
{
return isOpen;
} MISSING
...
}
121. cla
ss
cla flo A
ss a
int t z;
flo B k;
a
A a t w;
cla int
;
ss D d j;
int C ;
B b x; cla
ss
... ;
... D
Wait a minute...
122. cla
ss
cla pri
vat flo A
ss e i at z
flo B nt ;
pri a k;
v A a t w;
pri cla pri ate iint ;
vat ss vat
e
nt
D d j;
ei C D
;
int
nt
xx;
Bb ; cla
ss
... ;
... D
Wait a minute...
What about information
hiding?
123. “...one begins [to decompose a system] with a
list of difficult design decisions or design
decisions that are likely to change. Each
module is then designed to hide such a
decision from the others.”
― David Lodge Parnas, 1972
124. class InputStreamReader {
private InputStream sd;
public boolean isStreamOpen()
{
return sd.isOpen();
}
class InputStream {
...
private boolean isOpen;
}
public boolean isOpen()
{
return isOpen;
}
...
}
125. class InputStreamReader {
private InputStream sd;
public boolean isStreamOpen()
{
return sd.isOpen();
}
class InputStream {
...
private boolean isOpen;
}
public boolean isOpen()
{
return isOpen;
Difficult design decision? }
Likely to change? ...
}
126. The member fields of C involved in
the homomorphism H should have
the same read access visibilit y as C
127. design for monitoring
The member fields of C involved in
the homomorphism H should have
the same read access visibilit y as C
128. design for monitoring (or just for correct use)
The member fields of C involved in
the homomorphism H should have
the same read access visibilit y as C
131. Runtime monitoring of the 10 piggyback
properties on the DaCapo benchmark
Set of open source, real world applications
with non-trivial memory load
Same benchmark used by past monitoring
papers
138. Piggyback runtime monitoring uses an
object's own, existing member fields as an
encoding of the monitor's state
Under some conditions, this encoding is
guaranteed to exist
Stateful properties become stateless
properties ; no data to persist between calls
140. Emprical evidence on real-world
benchmarks on the OpenJDK 6 reveal
that:
Most properties are piggyback-
compatible
141. Emprical evidence on real-world
benchmarks on the OpenJDK 6 reveal
that:
Most properties are piggyback-
compatible
H involves few variables
142. Emprical evidence on real-world
benchmarks on the OpenJDK 6 reveal
that:
Most properties are piggyback-
compatible
H involves few variables
Runtime overhead is reduced over
classical monitors
143. Future work and open questions:
Use annotations instead of aspects
Find H automatically
Verify a given H statically
Extend to methods with arguments
Relax hypotheses
145. Piggyback and classical monitors are
complementary
The choice of a classical monitor should be
justified, not taken for granted
146. Piggyback and classical monitors are
complementary
The choice of a classical monitor should be
justified, not taken for granted
Is overhead really what matters?