Download - Final field semantics
Semantics of final fields in java
Vladimir Sitnikov, Valentin [email protected], @VladimirSitnikv
NetCracker
September 2014
Introduction
Examples
2 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Why final is required inJMM?
3 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String safety
String s = ...
if (checkAccess(s)) {
return readFile(s);
}
Is this a valid security check?
4 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String unsafety in 1.4
String s = ...
if (checkAccess(s)) {
return readFile(s);
}
The answer depends on the java version, and in java 1.4 the code isinsecure
5 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String unsafety in 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
For instance: HackThread executes .substring(4) and transfers itvia data race to the checker thread
6 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String unsafety in 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
In java 1.4 result of substring references the same char array, andthe value depends on String#offset and String#size
7 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String unsafety in 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
race
race
Since no synchronization is in place, reader might observenot-fully-initialized String
8 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String unsafety in 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
race
race
checkAccess might observe "/tmp/etc/passwd", and even thenreadFile might observe "/etc/passwd"
Even synchronization on s and volatile will not help!
9 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String unsafety in 1.4
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
race
race
checkAccess might observe "/tmp/etc/passwd", and even thenreadFile might observe "/etc/passwd"Even synchronization on s and volatile will not help!
10 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
String safety in java 1.5+
String s = GLOBAL;
if (checkAccess(s)) {
return readFile(s);
}
HackThread
GLOBAL =
"/tmp/etc/passwd"
.substring (4);
hb
hb
In java 1.5+ final protects from such non-initialized objects fromHackThread
11 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Зачем нам JMM?
12 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Quiz
int x = 1;
public int neverTryThisAtHome () {
int i = this.x; // it is 1, isn’t it?
this.setX (2); // just updates x to 2
return this.x - i; // 2 - 1 == ...?
}
What is the result? 1? 0? -1?
13 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Quiz
int x = 1;
public int neverTryThisAtHome () {
int i = this.x; // it is 1, isn’t it?
this.setX (2); // just updates x to 2
return this.x - i; // 2 - 1 == ...?
}
OK, the result is 1
14 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Quiz
final int x = 1;
public int neverTryThisAtHome () {
int i = this.x; // it is 1, isn’t it?
this.setX (2); // just updates x to 2
return this.x - i; // 2 - 1 == ...?
}
Let’s add some final
15 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Quiz
final int x = 1;
public int neverTryThisAtHome () {
int i = this.x; // it is 1, isn’t it?
this.setX (2); // just updates x to 2
return this.x - i; // 2 - 1 == ...?
}
The specification allows all the cases: 1, 0, and even -1! (see alsoexample 17.5.3-1)
16 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
A bit of theory
17 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Program order
I Program order is a total order among inter-thread actions ofeach thread in source code order
I Compiler is forbidden to reorder/alter/ignore operations ifobservable behavior violates program order
I It does not mean the program is executed in program orderI For instance: program order is not defined for operations onlocal variables
18 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Program order
I Program order is a total order among inter-thread actions ofeach thread in source code order
I Compiler is forbidden to reorder/alter/ignore operations ifobservable behavior violates program order
I It does not mean the program is executed in program orderI For instance: program order is not defined for operations onlocal variables
19 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Program order
I Program order is a total order among inter-thread actions ofeach thread in source code order
I Compiler is forbidden to reorder/alter/ignore operations ifobservable behavior violates program order
I It does not mean the program is executed in program order
I For instance: program order is not defined for operations onlocal variables
20 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Program order
I Program order is a total order among inter-thread actions ofeach thread in source code order
I Compiler is forbidden to reorder/alter/ignore operations ifobservable behavior violates program order
I It does not mean the program is executed in program orderI For instance: program order is not defined for operations onlocal variables
21 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Partial order
I In section 17 JLS "partial order" is mentioned 8 times
I Partial order ishb−−→ a binary relation that is:
I Reflexive: for each element x , xhb−−→ x
I Antisymmetric: if xhb−−→ y and y
hb−−→ x , then x and y are the same
element
I Transitive: if xhb−−→ y and y
hb−−→ z , then x
hb−−→ z
22 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Partial order
I In section 17 JLS "partial order" is mentioned 8 times
I Partial order ishb−−→ a binary relation that is:
I Reflexive: for each element x , xhb−−→ x
I Antisymmetric: if xhb−−→ y and y
hb−−→ x , then x and y are the same
element
I Transitive: if xhb−−→ y and y
hb−−→ z , then x
hb−−→ z
23 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Partial order
I In section 17 JLS "partial order" is mentioned 8 times
I Partial order ishb−−→ a binary relation that is:
I Reflexive: for each element x , xhb−−→ x
I Antisymmetric: if xhb−−→ y and y
hb−−→ x , then x and y are the same
element
I Transitive: if xhb−−→ y and y
hb−−→ z , then x
hb−−→ z
24 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Partial order
I In section 17 JLS "partial order" is mentioned 8 times
I Partial order ishb−−→ a binary relation that is:
I Reflexive: for each element x , xhb−−→ x
I Antisymmetric: if xhb−−→ y and y
hb−−→ x , then x and y are the same
element
I Transitive: if xhb−−→ y and y
hb−−→ z , then x
hb−−→ z
25 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Partial order
I In section 17 JLS "partial order" is mentioned 8 times
I Partial order ishb−−→ a binary relation that is:
I Reflexive: for each element x , xhb−−→ x
I Antisymmetric: if xhb−−→ y and y
hb−−→ x , then x and y are the same
element
I Transitive: if xhb−−→ y and y
hb−−→ z , then x
hb−−→ z
26 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I General idea of JMM: let’s consider all the executions and forbid"bad" ones
I Happens-before is a partial order that selects allowable readsI A read either sees the latest write (in hb order)I Or any write via data race when multiple writes are
hb -unordered with the readI It must still obey other rules, especially: 17.4.8 executions andcausality requirements
27 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I General idea of JMM: let’s consider all the executions and forbid"bad" ones
I Happens-before is a partial order that selects allowable reads
I A read either sees the latest write (in hb order)I Or any write via data race when multiple writes are
hb -unordered with the readI It must still obey other rules, especially: 17.4.8 executions andcausality requirements
28 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I General idea of JMM: let’s consider all the executions and forbid"bad" ones
I Happens-before is a partial order that selects allowable readsI A read either sees the latest write (in hb order)
I Or any write via data race when multiple writes arehb -unordered with the read
I It must still obey other rules, especially: 17.4.8 executions andcausality requirements
29 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I General idea of JMM: let’s consider all the executions and forbid"bad" ones
I Happens-before is a partial order that selects allowable readsI A read either sees the latest write (in hb order)I Or any write via data race when multiple writes are
hb -unordered with the read
I It must still obey other rules, especially: 17.4.8 executions andcausality requirements
30 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Happens-before
I General idea of JMM: let’s consider all the executions and forbid"bad" ones
I Happens-before is a partial order that selects allowable readsI A read either sees the latest write (in hb order)I Or any write via data race when multiple writes are
hb -unordered with the readI It must still obey other rules, especially: 17.4.8 executions andcausality requirements
31 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Semantics of final fields
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I w and r2 – the read and the write in question
I f – freeze of a final field, that is read in r1
32 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Semantics of final fields
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I w and r2 – the read and the write in questionI f – freeze of a final field, that is read in r1
33 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Semantics of final fields
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I If the only path from write to read follows all this arrows, thenwe must not see earlier writes
I If multiple paths exist, you need to go deeperI We use hb∗ notation to distinguish it from hb and since "thishappens-before ordering does not transitively close with otherhappens-before orderings"
34 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Semantics of final fields
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I If the only path from write to read follows all this arrows, thenwe must not see earlier writes
I If multiple paths exist, you need to go deeper
I We use hb∗ notation to distinguish it from hb and since "thishappens-before ordering does not transitively close with otherhappens-before orderings"
35 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Semantics of final fields
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
I If the only path from write to read follows all this arrows, thenwe must not see earlier writes
I If multiple paths exist, you need to go deeperI We use hb∗ notation to distinguish it from hb and since "thishappens-before ordering does not transitively close with otherhappens-before orderings"
36 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Freeze action w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Field
Freezes of a final field occur both at the end of the constructor, andimmediately after each modification
37 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Freeze action w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Freeze action
Field
Freezes of a final field occur both at the end of the constructor, andimmediately after each modification
38 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Freeze action w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Freeze actionField
Freezes of a final field occur both at the end of the constructor, andimmediately after each modification39 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
I r2 reads a field of an object
I Current thread did not create the objectI Hence, we must read an address of the object somewhere
I This is called r1dr−→ r2
40 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
I r2 reads a field of an objectI Current thread did not create the object
I Hence, we must read an address of the object somewhere
I This is called r1dr−→ r2
41 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
I r2 reads a field of an objectI Current thread did not create the objectI Hence, we must read an address of the object somewhere
I This is called r1dr−→ r2
42 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; r1
int localX = local.x; r2
dr
I r2 reads a field of an objectI Current thread did not create the objectI Hence, we must read an address of the object somewhere
I This is called r1dr−→ r2
43 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain in two threads w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T localA = new T();
GLOBAL = localA;
Thread 2
T localB = GLOBAL; r1
if (localB != null) {
int localX = localB.x; r2
}
dr
r1dr−→ r2 (thread 2 reads a field of object created in a foreign thread)
44 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain in two threads w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T localA = new T(); a
GLOBAL = localA;
Thread 2
T localB = GLOBAL; r1
if (localB != null) {
int localX = localB.x; r2
}
dr
dr?
Is there adr−→ r2?
45 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain in two threads w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T localA = new T(); a
GLOBAL = localA;
Thread 2
T localB = GLOBAL; r1
if (localB != null) {
int localX = localB.x; r2
}
dr
dr?
dr does not appear between actions of different threads!
46 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: double-check w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; ra
local = GLOBAL; rb
int localX = local.x; r2
Is there a dr ?
47 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Dereference chain: double-check w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T local = GLOBAL; ra
local = GLOBAL; rb
int localX = local.x; r2
dr?
dr?
One of radr−→ r2 or rb
dr−→ r2 must exist, however no one can tell
which one48 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T o = new T();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o;
Thread 3
T o = GL2;
int r = o.x;
mc
If a read sees write, then w1mc−−→ r1
49 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T o = new T();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2;
int r = o.x;
mc
mc
If a thread writes the address of an object that was initialized in
another thread, then r1mc−−→ w2
50 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T o = new T();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x;
mc
mc
mc
r3 sees w2 ⇒ w2mc−−→ r3
51 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T o = new T();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x; r4
mc
mc
mc dr
r3dr−→ r4 (read of a object’s field)
⇒ r3mc−−→ r4
52 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T o = new T();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x; r4
mc
mc
mc dr
mc
r3dr−→ r4 (read of a object’s field) ⇒ r3
mc−−→ r4
53 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Memory chain: what is that? w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T o = new T();
GL = o; w1
Thread 2
T o = GL; r1
GL2 = o; w2
Thread 3
T o = GL2; r3
int r = o.x; r4
mc
mc
mc dr
mc
mc
mc is transitive (it is a partial order) ⇒ w1mc−−→ r4
54 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Introduction
Examples
55 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Disclaimer
I All the examples contain data races (why bother otherwise?)
I We do not consider cases when null is observed (those cases arenot interesting)
I Lots of brains were hurt when preparing the slides
56 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Disclaimer
I All the examples contain data races (why bother otherwise?)I We do not consider cases when null is observed (those cases arenot interesting)
I Lots of brains were hurt when preparing the slides
57 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Disclaimer
I All the examples contain data races (why bother otherwise?)I We do not consider cases when null is observed (those cases arenot interesting)
I Lots of brains were hurt when preparing the slides
58 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}};
GLOBAL = l;
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r2
}
Can result become 0?
59 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx;
}
hb
hb
Actions in a thread form happens-before:
whb−−→ f , f
hb−−→ a
60 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL; r0
if (o != null) {
int result = o.fx;
}
hb
hb
mc
r0 sees write a :
amc−−→ r0
61 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL; r0
if (o != null) {
int result = o.fx; r1
}
hb
hb
mc
dr
Thread 2 did not create the object, r1 reads its field, and r is theonly read of the address, thus we have dereference chain:
r0dr−→ r1
62 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL; r0
if (o != null) {
int result = o.fx; r1
}
hb
hb
mc
dr
mc
r0dr−→ r1⇒ r0
mc−−→ r1
63 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL; r0
if (o != null) {
int result = o.fx; r1
}
hb
hb
mc
mc
mc
amc−−→ r1 ( mc is transitive)
64 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r1 r2
}
hb
hb
mc
dr
Let’s pick r2 = r1, then r1dr−→ r2 ( dr is reflexive)
65 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r1 r2
}
hb
hb
mc
dr
hb*
Here all the requirements for HB∗:
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
66 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Trivial final (1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
}}; f
GLOBAL = l; a
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r1 r2
}
hb
hb
mc
dr
hb*
(whb∗
−−→ r2)⇒ result ∈ {42}
67 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array in a final field (2) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
u[0] = 42; w
fx = u;
}};
GLOBAL = l;
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx;
int result = lfx [0]; r2
}
Can result become 0?
68 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array in a final field (2) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
u[0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx;
int result = lfx [0]; r2
}
hb
hb
Actions in a thread form happens-before:
whb−−→ f , f
hb−−→ a
69 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array in a final field (2) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
u[0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
r1 sees write a (it reads a regular final field):
amc−−→ r1
70 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array in a final field (2) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
u[0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
Thread 2 did not create array, r2 reads an element of the array, r1 isthe only read of the address of the array, thus dereference chain:
r1dr−→ r2
71 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array in a final field (2) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
u[0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
hb*
Here are all the requirements for HB∗:
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2
72 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array in a final field (2) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
u[0] = 42; w
fx = u;
}}; f
GLOBAL = l; a
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx; r1
int result = lfx [0]; r2
}
hb
hb
mc
dr
hb*
(whb∗
−−→ r2)⇒ result ∈ {42}
73 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array reversed (2.1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
fx = u; // (!)
u[0] = 42; w
}};
GLOBAL = l;
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx;
int result = lfx [0];
}
Can result become 0?
74 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array reversed (2.1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
fx = u; // (!)
u[0] = 42; w
}}; f
GLOBAL = l; a
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx; r1
int result = lfx [0]; r2
}
hbhb
mc
dr
hb∗
We compose hb∗ exactly as in the previous example
75 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Array reversed (2.1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T l = new T() {{
int[] u = new int [1];
fx = u; // (!)
u[0] = 42; w
}}; f
GLOBAL = l; a
T o = GLOBAL;
if (o != null) {
int[] lfx = o.fx; r1
int result = lfx [0]; r2
}
hbhb
mc
dr
hb∗
(whb∗
−−→ r2)⇒ result ∈ {42}The result does not depend on the order of assignment to final fields!
76 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
this leaks (3) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this;
}};
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r2
}
Can result become 0?
77 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
this leaks (3) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this; a
}}; f
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r2
}
hb
hb
Actions in thread form happens-before:
whb−−→ f , a
hb−−→ f
78 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
this leaks (3) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this; a
}}; f
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r2
}
hb
hb
hb?
For hb∗ we need fhb−−→ a!
79 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
this leaks (3) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this; a
}}; f
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r2
}
hb
hb
hb?
If ahb−−→ f and f
hb−−→ a, thus a = f (anti-symmetry of hb )
However a is cannot be a freeze action!
80 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
this leaks (3) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLOBAL = this; a
}}; f
Thread 2
T o = GLOBAL;
if (o != null) {
int result = o.fx; r2
}
hb
hb
hb?
There is no hb∗ , thus all the cases are possible: result ∈ {0, 42}
81 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Unintentional this leak (4) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this;
}};
GLa = l;
Thread 2
T u = GLb;
T o = GLa;
if (o != null) {
int result = o.fx; r2
}
Can result become 0?
82 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Unintentional this leak (4) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this; b
}}; f
GLa = l; a
Thread 2
T u = GLb;
T o = GLa;
if (o != null) {
int result = o.fx;
}
hb
hb
hb?
Actions in a thread form happens-before:
whb−−→ f , f
hb−−→ a
83 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Unintentional this leak (4) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this; b
}}; f
GLa = l; a
Thread 2
T u = GLb;
T o = GLa; ra
if (o != null) {
int result = o.fx;
}
hb
hb
hb?
mc
Suppose thread 2 sees GLa, thus amc−−→ ra!
84 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Unintentional this leak (4) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this; b
}}; f
GLa = l; a
Thread 2
T u = GLb; rb
T o = GLa; ra
if (o != null) {
int result = o.fx; r1
}
hb
hb
hb?
mc
dr?
dr?
There should be dr somewhere: rbdr−→ r1 or ra
dr−→ r1
85 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Unintentional this leak (4) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this; b
}}; f
GLa = l; a
Thread 2
T u = GLb; rb
T o = GLa; ra
if (o != null) {
int result = o.fx; r1
}
hb
hb
hb?
mc
dr?
dr
If rbdr−→ r1, then we fail, since w
hb∗
−−→ r1 can not be completed
86 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Unintentional this leak (4) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
T l = new T() {{
fx = 42; w
GLb = this; b
}}; f
GLa = l; a
Thread 2
T u = GLb; rb
T o = GLa; ra
if (o != null) {
int result = o.fx; r1
}
hb
hb
hb?
mc
dr?
dr
Conclusion: if a thread had ever seen object with unfrozen fields,then there is no final semantics for that object!
87 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Reflection in action (5) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T t = new T() {{
fu = new U();
fu.x = 1; w1
}};
GLOBAL = t;
U w = new U();
w.x = 42; w2
reflectSet(t.fu , w);
Thread 2
T t = GLOBAL;
if (t != null) {
U u = t.fu;
int result = u.x; r2
}
Can result become 0?88 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Reflection in action (5) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T t = new T() {{
fu = new U();
fu.x = 1;
}};
GLOBAL = t;
U w = new U();
w.x = 42; w2
reflectSet(t.fu , w);
Thread 2
T t = GLOBAL;
if (t != null) {
U u = t.fu;
int result = u.x; r2
}
hb*?
We’d better have w2hb∗
−−→ r2 (otherwise we must not see the writeof 0 in w.x)
89 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Reflection in action (5) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T t = new T() {{
fu = new U();
fu.x = 1;
}};
GLOBAL = t;
U w = new U();
w.x = 42; w2
reflectSet(t.fu , w); f2
Thread 2
T t = GLOBAL;
if (t != null) {
U u = t.fu;
int result = u.x; r2
}
hb*?
f2 does not work for hb∗ : there is no suitable f 2hb−−→ a
90 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Reflection in action (5) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T t = new T() {{
fu = new U();
fu.x = 1;
}}; f1
GLOBAL = t;
U w = new U();
w.x = 42; w2
reflectSet(t.fu , w); f2
Thread 2
T t = GLOBAL;
if (t != null) {
U u = t.fu;
int result = u.x; r2
}
hb*?
hb?
f1 does not work for hb∗ as well: it must be w2hb−−→ f 1
91 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Reflection in action (5) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T t = new T() {{
fu = new U();
fu.x = 1;
}}; f1
GLOBAL = t;
U w = new U();
w.x = 42; w2
reflectSet(t.fu , w); f2
Thread 2
T t = GLOBAL;
if (t != null) {
U u = t.fu;
int result = u.x; r2
}
hb*?
hb?
It turns out r2 is not denied to observe 0
92 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Reflection in action (5) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T t = new T() {{
fu = new U();
fu.x = 1;
}}; f1
GLOBAL = t; a
U w = new U();
w.x = 42; w2
reflectSet(t.fu , w); f2
Thread 2
T t = GLOBAL;
if (t != null) {
U u = t.fu;
int result = u.x; r2
}
hb*?
hb?
Conclusion: do not alter the final field after you publish its contentsresult ∈ {0, 1, 42}
93 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Let’s fix reflection (5.1) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
T t = new T() {{
fu = new U();
fu.x = 1;
}};
U w = new U();
w.x = 42;
reflectSet(t.fu , w);
GLOBAL = t; a
Thread 2
T t = GLOBAL;
if (t != null) {
U u = t.fu;
int result = u.x;
}
If we publish the object after all modifications of final fields, thepublication is safe: result ∈ {1, 42}
94 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a;
Thread 2
A a = GL;
B = new B() {{
fb = o;
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb;
int r = a.fx; r2
Can result become 0?
95 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
rb sees wb ⇒ wbmc−−→ rb
ra sees wa : wamc−−→ ra
96 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mc
Thread 2 writes an address of a foreign-created object, thus
ramc−−→ wb
97 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mcdr
Therad 3 did not create object A, r reads its field, and rb is theonly read of A’s address, thus dereference chain:
rbdr−→ r1
98 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mcdr
mc
rbdr−→ r1⇒ rb
mc−−→ r1
99 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}};
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1
mc
mc
mc
mc
mc
mc is transitive (since it is a partial order) ⇒ wamc−−→ r1
100 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}}; f
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1 r2
mc
dr
Let’s pick r2 = r1, thus r1dr−→ r2 ( dr is reflexive)
101 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}}; f
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1 r2
mc
dr
hb
hb
hb*
Here are all the requirements for HB∗:
whb−−→ f
hb−−→ a
mc−−→ r1
dr−→ r2⇒ w
hb∗
−−→ r2102 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Final wrapper (6) w hb−→ f hb−→ a mc−→ r1 dr−→ r2
Thread 1
A a = new O() {{
fx = 42; w
}}; f
GL = a; wa
Thread 2
A a = GL; ra
B = new B() {{
fb = o; wb
}};
GL2 = b;
Thread 3
B B = GL2;
A a = b.fb; rb
int r = a.fx; r1 r2
mc
dr
hb
hb
hb*
(whb∗
−−→ r2)⇒ result ∈ {42}
103 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved
Questions?
104 / 104 (c) Copyright 2014, NetCracker Technology Corp. All rights reserved