View
6
Download
0
Category
Preview:
Citation preview
Vérification par Model Checking deProgrammes Concurrents Paramétréssur des Modèles de Mémoire Faibles
David Declerck
Fatiha Zaïdi Directrice de ThèseSylvain Conchon Co-encadrant de Thèse
Plan
1 Vue d’ensemble des travaux réalisés
2 Principaux points techniques
3 Résultats
4 Conclusion et perspectives
1 / 66
Exemple d’introduction
Voici un programme d’exclusion mutuelle (spinlock, Linux 2.4) :
; Initialement, X = 1L1: lock dec [X]L2: jns CSL3: cmp [X], 0L4: jle L3L5: jmp L1CS: ; section critique
mov [X], 1L6: jmp L1
2 / 66
Objectif
On veut prouver la correction de ce programme, c’est-à-dire :
Propriété de sûretéQuel que soit le nombre de processus qui exécutent le spinlock, iln’existe pas deux processus qui soient tous deux en section critique
3 / 66
Comment vérifier cet algorithme ?
Nombreuses méthodes de vérification (preuve déductive, interpréta-tion abstraite, model checking...)
On souhaite utiliser une méthode :
• automatique
• applicable aux systèmes exécutés par un nombre arbitraire deprocessusIModel Checking Paramétré
On s’appuie sur Cubicle, développé au LRI dans l’équipe VALS par S.Conchon, A. Mebsout et F. Zaïdi [CAV 2012, FMCAD 2013]
4 / 66
Le Model Checker Cubicle
Cubicle est un Model Checker qui implémente le framework duModel Checking Modulo Theories (MCMT) développé par S. Ghilardiet S. Ranise [IJCAR 2008, LMCS 2010]
Principales caractéristiques :
• langage d’entrée = systèmes de transitions
• transitions de type garde/actions
• manipule des variables et tableaux
• paramétré
5 / 66
Traduction x86-TSO vers Cubicle
PMCx86 : outil de traduction de x86 vers Cubicle
Supporte un sous-ensemble du langage x86 :
• variables de type entier
• chargement/rangement : mov
• arithmétique : add, sub, inc, dec
• échange : xadd, xchg, cmpxchg
• comparaison : cmp
• branchements : jmp, jCC
• instruction atomiques : préfixe lock
http://www.lri.fr/~declerck/pmcx86/
6 / 66
Traduction x86-TSO vers Cubicle
; Initialement, X = 1L1: lock dec [X]L2: jns CSL3: cmp [X], 0L4: jle L3L5: jmp L1CS: ; section critique
mov [X], 1L6: jmp L1
CS L3
L1
X:=X-1ZF
L2
L6 L4 L5
X:=1
i:=X-1
ZFiZFi
ZFi:=X-0
�0 <0
ZFi �0
ZFi >0
code du
processus i
7 / 66
Traduction x86-TSO vers Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp (p)requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov (p)requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp (p)requires { EIP[p] = L6 }{ EIP[p] := L1 }
8 / 66
Traduction x86-TSO vers Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp (p)requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov (p)requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp (p)requires { EIP[p] = L6 }{ EIP[p] := L1 }
8 / 66
Traduction x86-TSO vers Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp (p)requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov (p)requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp (p)requires { EIP[p] = L6 }{ EIP[p] := L1 }
8 / 66
Traduction x86-TSO vers Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp (p)requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov (p)requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp (p)requires { EIP[p] = L6 }{ EIP[p] := L1 }
8 / 66
Traduction x86-TSO vers Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp (p)requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov (p)requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp (p)requires { EIP[p] = L6 }{ EIP[p] := L1 }
8 / 66
Traduction x86-TSO vers Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp (p)requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov (p)requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp (p)requires { EIP[p] = L6 }{ EIP[p] := L1 }
8 / 66
Résultat de l’analyse avec Cubicle
Cubicle prouve la correction du spinlock en 0.06s
Hypothèse : modèle de mémoire séquentiellement cohérent (SC)
t1 () requires { ... } { X := 1 }t2 () requires { ... } { X := 2 }t3 () requires { X = ? } { ... }
t1 ; t2 ; t3
I la lecture de X dans t3 lit nécessairement X = 2 de t2
9 / 66
Résultat de l’analyse avec Cubicle
Cubicle prouve la correction du spinlock en 0.06s
Hypothèse : modèle de mémoire séquentiellement cohérent (SC)
t1 () requires { ... } { X := 1 }t2 () requires { ... } { X := 2 }t3 () requires { X = ? } { ... }
t1 ; t2 ; t3
I la lecture de X dans t3 lit nécessairement X = 2 de t2
9 / 66
Résultat de l’analyse avec Cubicle
Cubicle prouve la correction du spinlock en 0.06s
Hypothèse : modèle de mémoire séquentiellement cohérent (SC)
t1 () requires { ... } { X := 1 }t2 () requires { ... } { X := 2 }t3 () requires { X = ? } { ... }
t1 ; t2 ; t3
I la lecture de X dans t3 lit nécessairement X = 2 de t2
9 / 66
Modèles de mémoire faibles
En pratique, les processeurs ne se comportent pas de cette façon :
• tampons d’écriture
• exécution spéculative
• pipeline complexe
• ...
t1 () requires { ... } { X := 1 }t2 () requires { ... } { X := 2 }t3 () requires { X = ? } { ... }
t1 ; t2 ; t3
I la lecture de X dans t3 peut lire X = 1 de t1
I On parle alors de modèle de mémoire faible
10 / 66
Modèles de mémoire faibles
En pratique, les processeurs ne se comportent pas de cette façon :
• tampons d’écriture
• exécution spéculative
• pipeline complexe
• ...t1 () requires { ... } { X := 1 }t2 () requires { ... } { X := 2 }t3 () requires { X = ? } { ... }
t1 ; t2 ; t3
I la lecture de X dans t3 peut lire X = 1 de t1
I On parle alors de modèle de mémoire faible
10 / 66
Modèles de mémoire faibles
En pratique, les processeurs ne se comportent pas de cette façon :
• tampons d’écriture
• exécution spéculative
• pipeline complexe
• ...t1 () requires { ... } { X := 1 }t2 () requires { ... } { X := 2 }t3 () requires { X = ? } { ... }
t1 ; t2 ; t3
I la lecture de X dans t3 peut lire X = 1 de t1
I On parle alors de modèle de mémoire faible
10 / 66
Modèles de mémoire faibles
En pratique, les processeurs ne se comportent pas de cette façon :
• tampons d’écriture
• exécution spéculative
• pipeline complexe
• ...t1 () requires { ... } { X := 1 }t2 () requires { ... } { X := 2 }t3 () requires { X = ? } { ... }
t1 ; t2 ; t3
I la lecture de X dans t3 peut lire X = 1 de t1
I On parle alors de modèle de mémoire faible
10 / 66
Le modèle de mémoire TSO
Processeurs Intel x86 : modèle TSO = Total Store Order
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mov eax, [y] mov ebx, [x]
Résultat possible dans (t1:eax, t2:ebx) :
• Evident : (0, 1), (1, 0), (1, 1)
• Mais aussi : (0, 0)
11 / 66
Le modèle de mémoire TSO
Processeurs Intel x86 : modèle TSO = Total Store Order
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mov eax, [y] mov ebx, [x]
Résultat possible dans (t1:eax, t2:ebx) :
• Evident : (0, 1), (1, 0), (1, 1)
• Mais aussi : (0, 0)
11 / 66
Le modèle de mémoire TSO
Processeurs Intel x86 : modèle TSO = Total Store Order
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mov eax, [y] mov ebx, [x]
Résultat possible dans (t1:eax, t2:ebx) :
• Evident : (0, 1), (1, 0), (1, 1)
• Mais aussi : (0, 0)
11 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1
mov eax, [y]mov [y], 1
mov ebx, [x]eax = 0 ebx = 0
X = 0 Y = 0
12 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1mov eax, [y]
mov [y], 1mov ebx, [x]
eax = 0 ebx = 0
X = 0 Y = 0
X← 1
12 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1
mov eax, [y]mov [y], 1
mov ebx, [x]eax = 0 ebx = 0
X = 0 Y = 0
X← 1 Y← 1
12 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1
mov eax, [y]mov [y], 1
mov ebx, [x]eax = 0 ebx = 0
X = 0 Y = 0
X← 1 Y← 1
12 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1
mov eax, [y]mov [y], 1
mov ebx, [x]eax = 0 ebx = 0
X = 0 Y = 0
X← 1 Y← 1
12 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1
mov eax, [y]mov [y], 1
mov ebx, [x]eax = 0 ebx = 0
X = 1 Y = 0
Y← 1
12 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1
mov eax, [y]mov [y], 1
mov ebx, [x]eax = 0 ebx = 0
X = 1 Y = 1
12 / 66
Le modèle de mémoire TSO
Thread 1 Thread 2mov [x], 1
mov eax, [y]mov [y], 1
mov ebx, [x]eax = 0 ebx = 0
X = 1 Y = 1
12 / 66
Eliminer les comportements TSO
• Ces nouveaux comportements ne sont pas nécessairementincorrects
• Si on veut en exclure certains, on peut utiliser des barrièresmémoires
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
Insertion automatique de barrières :• Alglave, Maranget, Sarkar, Sewell [CAV 2010]
• Bouajjani, Derevenetc, Meyer [ESOP 2013]
• Abdulla, Atig, Chen, Leonardsson, Rezine [TACAS 2013]• ...
13 / 66
Eliminer les comportements TSO
• Ces nouveaux comportements ne sont pas nécessairementincorrects
• Si on veut en exclure certains, on peut utiliser des barrièresmémoires
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
Insertion automatique de barrières :• Alglave, Maranget, Sarkar, Sewell [CAV 2010]
• Bouajjani, Derevenetc, Meyer [ESOP 2013]
• Abdulla, Atig, Chen, Leonardsson, Rezine [TACAS 2013]• ...
13 / 66
Eliminer les comportements TSO
• Ces nouveaux comportements ne sont pas nécessairementincorrects
• Si on veut en exclure certains, on peut utiliser des barrièresmémoires
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
Insertion automatique de barrières :• Alglave, Maranget, Sarkar, Sewell [CAV 2010]
• Bouajjani, Derevenetc, Meyer [ESOP 2013]
• Abdulla, Atig, Chen, Leonardsson, Rezine [TACAS 2013]• ...
13 / 66
Qu’en est-il des instructions atomiques ?
Les instructions atomiques, telles que le lock dec utilisé dans lespinlock, ont également un fonctionnement particulier en TSO :
• un processus ne peut l’exécuter que quand son tampon estvide
• un processus ne peut passer à l’instruction suivante qu’unefois son tampon vide
14 / 66
Le spinlock sous le modèle TSO
; Initialement, X = 1L1: lock dec [X]L2: jns CSL3: cmp [X], 0L4: jle L3L5: jmp L1CS: ; section critique
mov [X], 1L6: jmp L1
15 / 66
Cubicle-W
Objectif : développer une nouvelle version de Cubicle pour analyserdes programmes s’exécutant sur des modèles de mémoire faibles
Extensions de syntaxe :
• weak : déclarer une variable "faible"
• fence : barrière mémoire
• transition t ([p] ...) : processus effectuant lesopérations mémoires
16 / 66
Extension du langage de Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intweak var X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec ([p])requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk ([p])requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk ([p])requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp ([p])requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk ([p])requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk ([p])requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp ([p])requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov ([p])requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp ([p])requires { EIP[p] = L6 }{ EIP[p] := L1 }
17 / 66
Extension du langage de Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intweak var X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec ([p])requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk ([p])requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk ([p])requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp ([p])requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk ([p])requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk ([p])requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp ([p])requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov ([p])requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp ([p])requires { EIP[p] = L6 }{ EIP[p] := L1 }
17 / 66
Extension du langage de Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intweak var X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec ([p])requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk ([p])requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk ([p])requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp ([p])requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk ([p])requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk ([p])requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp ([p])requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov ([p])requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp ([p])requires { EIP[p] = L6 }{ EIP[p] := L1 }
17 / 66
Extension du langage de Cubicle
type loc = L1 | L2 | L3 | L4 | L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intweak var X : int
init (p) {EIP[p] = L1 && X = 1 }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec ([p])requires { EIP[p] = L1 }{ EIP[p] := L2; X := X - 1; ZF[p] := X - 1 }
transition t_L2_CS_jns_tk ([p])requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk ([p])requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp ([p])requires { EIP[p] = L3 }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L4_L3_jle_tk ([p])requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk ([p])requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp ([p])requires { EIP[p] = L5 }{ EIP[p] := L1 }
transition t_CS_L6_mov ([p])requires { EIP[p] = CS }{ EIP[p] := L6; X := 1 }
transition t_L6_L1_jmp ([p])requires { EIP[p] = L6 }{ EIP[p] := L1 }
17 / 66
Comment vérifier un programme Cubicle-W ?
Approche par tampons explicites
18 / 66
Encodage direct en Cubicle
Idée immédiate : réaliser un encodage avec des tampons
• Utilisation des tableaux non bornés de Cubicle pourreprésenter les tampons
• Paramétricité à la fois sur le nombre de processus et la tailledes tampons
... ...pb
∅ (”X”, V1) (”Y”, V2) (”Z”, V3) ∅
array Var[proc,int] : stringarray Val[proc,int] : int
Var[p,b] = "X"Val[p,b] = V1
19 / 66
Encodage direct en Cubicle
Ecriture X ← V1 : ajout de (X, V1) en tête de file
... ...pb
∅ ∅ (”Y”, V2) (”Z”, V3) ∅
... ...p
b
∅ (”X”, V1) (”Y”, V2) (”Z”, V3) ∅
transition t_write_X (p b)requires { Var[p,b] = "" &&
∀ k. k < b → Var[p,k] = "" }{ Var[p,b] := "X"; Val[p,b] := V1 }
19 / 66
Encodage direct en Cubicle
Propagation : retrait en queue de file et mise à jour de la variable
... ...pb
∅ (”X”, V1) (”Y”, V2) (”Z”, V3) ∅
... ...p
b
∅ (”X”, V1) (”Y”, V2) ∅ ∅
transition t_flush_Y (p b)requires { Var[p,b] = "Z" &&
∀ k. b < k → Var[p,k] = "" }{ Var[p,b] := ""; Z := Val[p,b] }
19 / 66
Encodage direct en Cubicle
Lecture depuis le tampon
... ...pb
∅ (”X”, V1) (”X”, V2) (”X”, V3) ∅
transition t_read_X_buf (p b)requires { Var[p,b] = "X" &&
∀ k. k < b → Var[p,k] <> "X" }{ R[p] := Val[p,b] }
19 / 66
Encodage direct en Cubicle
Lecture depuis la mémoire
... ...p ∅ (”Y”, V1) (”Y”, V2) (”Z”, V3) ∅
transition t_read_X_mem (p)requires { ∀ k. Var[p,k] <> "X" }{ R[p] := X }
19 / 66
Encodage direct en Cubicle : exemple
type loc = L1 | L2 | L3 | L4| L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
array Var[proc,int] : stringarray Val[proc,int] : int
init (p b) {EIP[p] = L1 && X = 1 &&Var[p,b] = "" }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 &&
forall_other k. Var[p,k] = "" }{ EIP[p] := L2; X := X - 1;
ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp_mem (p)requires { EIP[p] = L3 &&
forall_other k. Var[p,k] <> "X" }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L3_L4_cmp_buf (p b)requires { EIP[p] = L3 && Var[p,b] = "X" &&
forall_other k. (b < k || Var[p,k] <> "X") }{ EIP[p] := L4; ZF[p] := Val[p,b] - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
...
20 / 66
Encodage direct en Cubicle : exemple
type loc = L1 | L2 | L3 | L4| L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
array Var[proc,int] : stringarray Val[proc,int] : int
init (p b) {EIP[p] = L1 && X = 1 &&Var[p,b] = "" }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 &&
forall_other k. Var[p,k] = "" }{ EIP[p] := L2; X := X - 1;
ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp_mem (p)requires { EIP[p] = L3 &&
forall_other k. Var[p,k] <> "X" }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L3_L4_cmp_buf (p b)requires { EIP[p] = L3 && Var[p,b] = "X" &&
forall_other k. (b < k || Var[p,k] <> "X") }{ EIP[p] := L4; ZF[p] := Val[p,b] - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
...
20 / 66
Encodage direct en Cubicle : exemple
type loc = L1 | L2 | L3 | L4| L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
array Var[proc,int] : stringarray Val[proc,int] : int
init (p b) {EIP[p] = L1 && X = 1 &&Var[p,b] = "" }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 &&
forall_other k. Var[p,k] = "" }{ EIP[p] := L2; X := X - 1;
ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp_mem (p)requires { EIP[p] = L3 &&
forall_other k. Var[p,k] <> "X" }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L3_L4_cmp_buf (p b)requires { EIP[p] = L3 && Var[p,b] = "X" &&
forall_other k. (b < k || Var[p,k] <> "X") }{ EIP[p] := L4; ZF[p] := Val[p,b] - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
...
20 / 66
Encodage direct en Cubicle : exemple
type loc = L1 | L2 | L3 | L4| L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
array Var[proc,int] : stringarray Val[proc,int] : int
init (p b) {EIP[p] = L1 && X = 1 &&Var[p,b] = "" }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 &&
forall_other k. Var[p,k] = "" }{ EIP[p] := L2; X := X - 1;
ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp_mem (p)requires { EIP[p] = L3 &&
forall_other k. Var[p,k] <> "X" }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L3_L4_cmp_buf (p b)requires { EIP[p] = L3 && Var[p,b] = "X" &&
forall_other k. (b < k || Var[p,k] <> "X") }{ EIP[p] := L4; ZF[p] := Val[p,b] - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
...
20 / 66
Encodage direct en Cubicle : exemple
type loc = L1 | L2 | L3 | L4| L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
array Var[proc,int] : stringarray Val[proc,int] : int
init (p b) {EIP[p] = L1 && X = 1 &&Var[p,b] = "" }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 &&
forall_other k. Var[p,k] = "" }{ EIP[p] := L2; X := X - 1;
ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp_mem (p)requires { EIP[p] = L3 &&
forall_other k. Var[p,k] <> "X" }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L3_L4_cmp_buf (p b)requires { EIP[p] = L3 && Var[p,b] = "X" &&
forall_other k. (b < k || Var[p,k] <> "X") }{ EIP[p] := L4; ZF[p] := Val[p,b] - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
...
20 / 66
Encodage direct en Cubicle : exemple
type loc = L1 | L2 | L3 | L4| L5 | L6 | CS
array EIP[proc] : locarray ZF[proc] : intvar X : int
array Var[proc,int] : stringarray Val[proc,int] : int
init (p b) {EIP[p] = L1 && X = 1 &&Var[p,b] = "" }
unsafe (p1 p2) {EIP[p1] = CS && EIP[p2] = CS }
transition t_L1_L2_ldec (p)requires { EIP[p] = L1 &&
forall_other k. Var[p,k] = "" }{ EIP[p] := L2; X := X - 1;
ZF[p] := X - 1 }
transition t_L2_CS_jns_tk (p)requires { EIP[p] = L2 && 0 <= ZF[p] }{ EIP[p] := CS }
transition t_L2_L3_jns_ntk (p)requires { EIP[p] = L2 && ZF[p] < 0 }{ EIP[p] := L3 }
transition t_L3_L4_cmp_mem (p)requires { EIP[p] = L3 &&
forall_other k. Var[p,k] <> "X" }{ EIP[p] := L4; ZF[p] := X - 0 }
transition t_L3_L4_cmp_buf (p b)requires { EIP[p] = L3 && Var[p,b] = "X" &&
forall_other k. (b < k || Var[p,k] <> "X") }{ EIP[p] := L4; ZF[p] := Val[p,b] - 0 }
transition t_L4_L3_jle_tk (p)requires { EIP[p] = L4 && ZF[p] <= 0 }{ EIP[p] := L3 }
transition t_L4_L5_jle_ntk (p)requires { EIP[p] = L4 && 0 < ZF[p] }{ EIP[p] := L5 }
transition t_L5_L1_jmp (p)requires { EIP[p] = L5 }{ EIP[p] := L1 }
...
20 / 66
Encodage direct en Cubicle
Cubicle prouve que le programme est correct...
Pourtant :
• Programme simple
• Une seule variable partagée
• Opération atomique
Les tampons augmentent la complexité de l’approche :
• Deux dimensions de paramétricité
• Propagation non déterministe
• Lecture interne depuis le tampon
21 / 66
Encodage direct en Cubicle
Cubicle prouve que le programme est correct en 4m40
Pourtant :
• Programme simple
• Une seule variable partagée
• Opération atomique
Les tampons augmentent la complexité de l’approche :
• Deux dimensions de paramétricité
• Propagation non déterministe
• Lecture interne depuis le tampon
21 / 66
Encodage direct en Cubicle
Cubicle prouve que le programme est correct en 4m40
Pourtant :
• Programme simple
• Une seule variable partagée
• Opération atomique
Les tampons augmentent la complexité de l’approche :
• Deux dimensions de paramétricité
• Propagation non déterministe
• Lecture interne depuis le tampon
21 / 66
Encodage direct en Cubicle
Cubicle prouve que le programme est correct en 4m40
Pourtant :
• Programme simple
• Une seule variable partagée
• Opération atomique
Les tampons augmentent la complexité de l’approche :
• Deux dimensions de paramétricité
• Propagation non déterministe
• Lecture interne depuis le tampon
21 / 66
Peut-on éviter de modéliser des tampons ?
Constat :
• Beaucoup de configurations de tampons pour descomportements identiques
• Inutile de connaître le contenu exact des tampons
• Uniquement besoin de savoir depuis quelles écritures leslectures prennent leur valeur
I Utilisation d’un modèle dit "axiomatique"
• Raisonne sur les comportements d’un programme
• Modèles très étudiés :I Shasha, Snir [TOPLAS 1988]I Sarkar, Sewell, Nardelli, Owens, Ridge, Braibant, O. Myreen, Alglave [POPL 2009]I Atig, Bouajjani, Burckhardt, Sighireanu [POPL 2010]I Alglave, Maranget, Tautschnig [TOPLAS 2014]I Abdulla, Aronis, Atig, Jonsson, Leonardsson, Sagonas [TACAS 2015]I ...
22 / 66
Peut-on éviter de modéliser des tampons ?
Constat :
• Beaucoup de configurations de tampons pour descomportements identiques
• Inutile de connaître le contenu exact des tampons
• Uniquement besoin de savoir depuis quelles écritures leslectures prennent leur valeur
I Utilisation d’un modèle dit "axiomatique"
• Raisonne sur les comportements d’un programme
• Modèles très étudiés :I Shasha, Snir [TOPLAS 1988]I Sarkar, Sewell, Nardelli, Owens, Ridge, Braibant, O. Myreen, Alglave [POPL 2009]I Atig, Bouajjani, Burckhardt, Sighireanu [POPL 2010]I Alglave, Maranget, Tautschnig [TOPLAS 2014]I Abdulla, Aronis, Atig, Jonsson, Leonardsson, Sagonas [TACAS 2015]I ...
22 / 66
Peut-on éviter de modéliser des tampons ?
Constat :
• Beaucoup de configurations de tampons pour descomportements identiques
• Inutile de connaître le contenu exact des tampons
• Uniquement besoin de savoir depuis quelles écritures leslectures prennent leur valeur
I Utilisation d’un modèle dit "axiomatique"
• Raisonne sur les comportements d’un programme
• Modèles très étudiés :I Shasha, Snir [TOPLAS 1988]I Sarkar, Sewell, Nardelli, Owens, Ridge, Braibant, O. Myreen, Alglave [POPL 2009]I Atig, Bouajjani, Burckhardt, Sighireanu [POPL 2010]I Alglave, Maranget, Tautschnig [TOPLAS 2014]I Abdulla, Aronis, Atig, Jonsson, Leonardsson, Sagonas [TACAS 2015]I ...
22 / 66
Comment vérifier un programme Cubicle-W ?
Approche axiomatique
23 / 66
Généralités sur les modèles mémoires axiomatiques
Modèle mémoire axiomatique :
• événements (lecture, écriture)
• raisonnement sur les relations entre événementsI po : ordre selon le code sourceI ppo : ordre préservé par le processeurI fence : paires séparées par une barrièreI rf : relie les écritures aux lecturesI co : cohérence des écritures par variableI fr : dérivée de rf et co
• relation global happens-before (ghb)
I Une exécution sera réalisable si on peut construire une relationghb acyclique (+ conditions auxilliaires)
24 / 66
Généralités sur les modèles mémoires axiomatiques
Modèle mémoire axiomatique :
• événements (lecture, écriture)
• raisonnement sur les relations entre événementsI po : ordre selon le code sourceI ppo : ordre préservé par le processeurI fence : paires séparées par une barrièreI rf : relie les écritures aux lecturesI co : cohérence des écritures par variableI fr : dérivée de rf et co
• relation global happens-before (ghb)
I Une exécution sera réalisable si on peut construire une relationghb acyclique (+ conditions auxilliaires)
24 / 66
Modèle TSO Axiomatique
type proctype event
logic Rx : event,proc -> proplogic Wx : event,proc -> prop
...
logic val : event -> int
logic is_read : event -> proplogic is_write : event -> proplogic same_proc : event,event -> prop
logic po : event,event -> proplogic ppo : event,event -> proplogic fences : event,event -> proplogic rf : event,event -> proplogic rfe : event,event -> proplogic co : event,event -> proplogic fr : event,event -> proplogic ghb : event,event -> prop
axiom ppo :forall p : e1, e2 : event.
po(e1, e2) and not(is_write(e1) and is_read(e2))
-> ppo(e1, e2)
axiom rfe :forall e1, e2 : event.
rf(e1, e2) and not same_proc(e1,e2)-> rfe(e1, e2)
axiom fr :forall e1, e2, e3 : event.
rf(e1, e2) and co(e1, e3)-> fr(e2, e3)
...
axiom ghb :forall e1, e2 : event.
ppo(e1, e2) or fence(e1, e2) orrfe(e1, e2) or co(e1, e2) orfr(e1, e2)
-> ghb(e2, e3)
25 / 66
Modèle TSO Axiomatique
EvénementsLes opérations mémoires produisent des événements. On note El’ensemble des événements produits pour une exécution donnée.
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
vale1 0e2 0e3 1e4 ?e5 1e6 ?
26 / 66
Modèle TSO Axiomatique
EvénementsLes opérations mémoires produisent des événements. On note El’ensemble des événements produits pour une exécution donnée.
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
vale1 0e2 0e3 1e4 ?e5 1e6 ?
26 / 66
Modèle TSO Axiomatique
Program Order (po)Les événements issus d’un même processus sont ordonnés par larelation Program Order
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
po po
vale1 0e2 0e3 1e4 ?e5 1e6 ?
27 / 66
Modèle TSO Axiomatique
Preserved Program Order (ppo)En TSO, l’ordre des paires écriture-lecture de ProgramOrder n’est paspréservé
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
vale1 0e2 0e3 1e4 ?e5 1e6 ?
28 / 66
Modèle TSO Axiomatique
FenceToutes les paires écriture-lecture d’unmêmeprocessus séparées parune barrière mémoire sont ordonnées par la relation Fence
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)fence fence
vale1 0e2 0e3 1e4 ?e5 1e6 ?
29 / 66
Modèle TSO Axiomatique
Read-From (rf)La relation Read-From relie chaque lecture à l’écriture qui lui fournitsa valeur
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
rfrf
vale1 0e2 0e3 1e4 0e5 1e6 0
30 / 66
Modèle TSO Axiomatique
Read-From (rf)La relation Read-From relie chaque lecture à l’écriture qui lui fournitsa valeur
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
rfrf
vale1 0e2 0e3 1e4 1e5 1e6 1
30 / 66
Modèle TSO Axiomatique
Read-From (rf)La relation Read-From relie chaque lecture à l’écriture qui lui fournitsa valeur
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)rf
rf
vale1 0e2 0e3 1e4 0e5 1e6 1
30 / 66
Modèle TSO Axiomatique
Read-From (rf)La relation Read-From relie chaque lecture à l’écriture qui lui fournitsa valeur
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
rf
rf
vale1 0e2 0e3 1e4 1e5 1e6 0
30 / 66
Modèle TSO Axiomatique
Coherence (co)La relation co ordonne les écritures sur une même variable selonl’ordre dans lequel elles deviennent visibles globalement
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
co co
vale1 0e2 0e3 1e4 ?e5 1e6 ?
31 / 66
Modèle TSO Axiomatique
From-Read (fr)La relation fr est dérivée de rf et co de la façon suivante : si on arf(e1,e2) et co(e1,e3), alors on a également fr(e2,e3)
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
corf
fr
vale1 0e2 0e3 1e4 ?e5 1e6 0
32 / 66
Modèle TSO Axiomatique
Global-Happens-Before (ghb)ghb est la plus petite relation d’ordre partiel telle que :
∀e1, e2· ppo(e1, e2) → ghb(e1, e2) GHB-PPO
∀e1, e2· fence(e1, e2) → ghb(e1, e2) GHB-FENCE
∀e1, e2· rfe(e1, e2) → ghb(e1, e2) GHB-RFE
∀e1, e2· co(e1, e2) → ghb(e1, e2) GHB-CO
∀e1, e2· fr(e1, e2) → ghb(e1, e2) GHB-FR
33 / 66
Modèle TSO Axiomatique
ExécutionUne exécution est définie par E = (E, po, rf, co)
Exécution réalisableUne exécution E = (E, po, rf, co) est réalisable si la relation ghbqu’elle engendre est une relation d’ordre partiel valide (i.e. acyclique)
34 / 66
Modèle TSO Axiomatique
ExécutionUne exécution est définie par E = (E, po, rf, co)
Exécution réalisableUne exécution E = (E, po, rf, co) est réalisable si la relation ghbqu’elle engendre est une relation d’ordre partiel valide (i.e. acyclique)
34 / 66
Modèle TSO Axiomatique
Sans les barrières mémoires, on peut obtenir (0,0) dans (eax,ebx)car l’exécution suivante est réalisable :
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
co corfrf
fr fr
vale1 0e2 0e3 1e4 0e5 1e6 0
35 / 66
Modèle TSO Axiomatique
Avec les barrières mémoires, l’exécution n’est plus réalisable :
Etat initial : x = 0, y = 0Thread 1 Thread 2
mov [x], 1 mov [y], 1mfence mfencemov eax, [y] mov ebx, [x]
→
e1:Wx e2:Wy
e3:Wx(p1)
e4:Ry(p1)
e5:Wy(p2)
e6:Rx(p2)
co corfrf
fr frfence fence
vale1 0e2 0e3 1e4 0e5 1e6 0
36 / 66
Comment implémenter un tel modèle dans Cubicle-W ?
37 / 66
Principe de Cubicle
Objectif : vérifier qu’un ensemble d’états, qualifiés de dangereux,n’est pas atteignable
Un ensembles d’états = une formule logique appelée cube, i.e. uneconjonction de littéraux composés de termes parmi :
• des constantes
• des identificateurs de processus
• des variables
• des accès à un tableau
∃p,q· p 6= q ∧ X = 42 ∧ T[p] < T[q]
38 / 66
Algorithme d’atteignabilité arrièreBR ():
V := ∅push(Q, U)while not_empty(Q) doϕ := pop(Q)if ϕ ∧ I sat then
return unsafeif ¬(ϕ �
∨ψ∈V ψ) then
V := V ∪ { ϕ }push(Q, preτ (ϕ))
return safe
}
}
Test de sûreté & Test de point fixe• Solveur SMT / Tests ensemblistes• Langage logique étendu pour
raisonner sur les événements et lesrelations
• Solveur SMT étendu pour raisonnermodulo TSO
Calcul de pré-image• Instrumenté pour produire des
événements et des relations• Fabrique les formules
correspondant aux différentesfaçons d’associer les écritures auxlectures
39 / 66
Algorithme d’atteignabilité arrièreBR ():
V := ∅push(Q, U)while not_empty(Q) doϕ := pop(Q)if ϕ ∧ I sat then
return unsafeif ¬(ϕ �
∨ψ∈V ψ) then
V := V ∪ { ϕ }push(Q, preτ (ϕ))
return safe
}
}
Test de sûreté & Test de point fixe• Solveur SMT / Tests ensemblistes• Langage logique étendu pour
raisonner sur les événements et lesrelations
• Solveur SMT étendu pour raisonnermodulo TSO
Calcul de pré-image• Instrumenté pour produire des
événements et des relations• Fabrique les formules
correspondant aux différentesfaçons d’associer les écritures auxlectures
39 / 66
Représentation des événements
Déclarations :weak var X : intweak array T[proc] : int
Lecture d’une variable :transition t ([p]) requires { X = 42 } { ... }
I ∃p, e1· e1:RX(p) ∧ val(e1) = 42
Lecture d’une case de tableau :transition t ([p] q) requires { T[q] = 42 } { ... }
I ∃p,q, e2· e2:RT(p,q) ∧ val(e2) = 42
40 / 66
Représentation des événements
Déclarations :weak var X : intweak array T[proc] : int
Lecture d’une variable :transition t ([p]) requires { X = 42 } { ... }
I ∃p, e1· e1:RX(p) ∧ val(e1) = 42
Lecture d’une case de tableau :transition t ([p] q) requires { T[q] = 42 } { ... }
I ∃p,q, e2· e2:RT(p,q) ∧ val(e2) = 42
40 / 66
Représentation des événements
Déclarations :weak var X : intweak array T[proc] : int
Lecture d’une variable :transition t ([p]) requires { X = 42 } { ... }
I ∃p, e1· e1:RX(p) ∧ val(e1) = 42
Lecture d’une case de tableau :transition t ([p] q) requires { T[q] = 42 } { ... }
I ∃p,q, e2· e2:RT(p,q) ∧ val(e2) = 42
40 / 66
Représentation des événements
Déclarations :weak var X : intweak array T[proc] : int
Ecriture d’une variable :transition t ([p]) requires { ... } { X := 42 }
I ∃p, e3· e3:WX(p) ∧ val(e3) = 42
Ecriture d’une case de tableau :transition t ([p] q) requires { ... } { T[q] := 42 }
I ∃p,q, e4· e4:WT(p,q) ∧ val(e4) = 42
41 / 66
Représentation des événements
Déclarations :weak var X : intweak array T[proc] : int
Ecriture d’une variable :transition t ([p]) requires { ... } { X := 42 }
I ∃p, e3· e3:WX(p) ∧ val(e3) = 42
Ecriture d’une case de tableau :transition t ([p] q) requires { ... } { T[q] := 42 }
I ∃p,q, e4· e4:WT(p,q) ∧ val(e4) = 42
41 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(#1), val(e1) > 0e2:Wx(#2), val(e2) = 1
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(p1), val(e1) > 0e2:Wx(p2), val(e2) = 1
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(p1), val(e1) > 0e2:Wx(p2), val(e2) = 1
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(p1), 1 > 0 .e2:Wx(p2), val(e2) = 2
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(p1), 1 > 0 .e2:Wx(p2), val(e2) = 2
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(p1), 1 > 0 .e2:Wx(p2), val(e2) = 2
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
e1:Rx(p1), val(e1) = 1e2:Wx(p2), val(e2) = 2
ghb(e1,e2)
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(p1), 1 > 0 .e2:Wx(p2), val(e2) = 2
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
e1:Rx(p1), val(e1) = 1e2:Wx(p2), val(e2) = 2
ghb(e1,e2)
• relier les écritures sur une même variable (co)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Calcul de pré-image
Similaire à Cubicle, mais il faut :
• relier les lectures avec les écritures (rf)e1:Rx(p1), 1 > 0 .e2:Wx(p2), val(e2) = 2
ghb(e2,e1), val(e1) = val(e2)
e1:Rx(p1), val(e1) > 0
X := 1
e1:Rx(p1), val(e1) = 1e2:Wx(p2), val(e2) = 2
ghb(e1,e2)
• relier les écritures sur une même variable (co)e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e1,e2)
X := 1
42 / 66
Exemple
type loc = L1 | L2 | End
array EIP[proc] : locarray EAX[proc] : intarray EBX[proc] : intweak var X : intweak var Y : int
init (p) { EIP[p] = L1 &&X = 0 && Y = 0 }
unsafe (p1 p2) {EIP[p1] = End && EIP[p2] = End &&EAX[p1] = 0 && EBX[p2] = 0 }
transition t1_L1_L2 ([p])requires { EIP[p] = L1 }{ EIP[p] := L2; X := 1 }
transition t1_L2_End ([p])requires { EIP[p] = L2 && fence() }{ EIP[p] := End; EAX[p] := Y }
transition t2_L1_L2 ([p])requires { EIP[p] = L1 }{ EIP[p] := L2; Y := 1 }
transition t2_L2_End ([p])requires { EIP[p] = L2 && fence() }{ EIP[p] := End; EBX[p] := X }
43 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
1
44 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
EIP[p1] = End, EIP[p2] = L2EAX[p1] = 0 .e1:Rx(p2), val(e1) = 0
fence(e1,p2) .
t2_L2_End(p2)1 2
44 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0
fence(e1,p2), fence(e2,p1)
EIP[p1] = End, EIP[p2] = L2EAX[p1] = 0 .e1:Rx(p2), val(e1) = 0
fence(e1,p2) .
t1_L2_End(p1)
t2_L2_End(p2)1 2
3
44 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0e3:Wy(p2), val(e3) = 1
fence(e1,p2), fence(e2,p1) ghb(e3,e1), ghb(e3,e2)
val(e2) = val(e3)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0
fence(e1,p2), fence(e2,p1)
EIP[p1] = End, EIP[p2] = L2EAX[p1] = 0 .e1:Rx(p2), val(e1) = 0
fence(e1,p2) .
t2_L1_L2(p2)
t1_L2_End(p1)
t2_L2_End(p2)1 2
3
4
44 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0e3:Wy(p2), val(e3) = 1
fence(e1,p2), fence(e2,p1) ghb(e3,e1), ghb(e3,e2)
val(e2) = val(e3)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0
fence(e1,p2), fence(e2,p1)
EIP[p1] = End, EIP[p2] = L2EAX[p1] = 0 .e1:Rx(p2), val(e1) = 0
fence(e1,p2) .
t2_L1_L2(p2)
t1_L2_End(p1)
t2_L2_End(p2)1 2
3
4
44 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0 e3:Wy(p2) .
fence(e1,p2), fence(e2,p1)ghb(e3,e1), ghb(e2,e3)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0e3:Wy(p2), val(e3) = 1
fence(e1,p2), fence(e2,p1) ghb(e3,e1), ghb(e3,e2)
val(e2) = val(e3)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0
fence(e1,p2), fence(e2,p1)
EIP[p1] = End, EIP[p2] = L2EAX[p1] = 0 .e1:Rx(p2), val(e1) = 0
fence(e1,p2) .
t2_L1_L2(p2)t2_L1_L2(p2)
t1_L2_End(p1)
t2_L2_End(p2)1 2
3
4
5
44 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0 e3:Wy(p2) .
fence(e1,p2), fence(e2,p1)ghb(e3,e1), ghb(e2,e3)
EIP[p1] = L1, EIP[p2] = L1e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0 e3:Wy(p2) .e4:Wx(p1) .
fence(e1,p2), fence(e2,p1)ghb(e3,e1), ghb(e2,e3)ghb(e4,e2), ghb(e1,e4)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0e3:Wy(p2), val(e3) = 1
fence(e1,p2), fence(e2,p1) ghb(e3,e1), ghb(e3,e2)
val(e2) = val(e3)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0
fence(e1,p2), fence(e2,p1)
EIP[p1] = End, EIP[p2] = L2EAX[p1] = 0 .e1:Rx(p2), val(e1) = 0
fence(e1,p2) .
t1_L1_L2(p1)
t2_L1_L2(p2)t2_L1_L2(p2)
t1_L2_End(p1)
t2_L2_End(p2)1 2
3
4
5
6
44 / 66
Exemple
EIP[p1] = End, EIP[p2] = EndEAX[p1] = 0, EBX[p2] = 0
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0 e3:Wy(p2) .
fence(e1,p2), fence(e2,p1)ghb(e3,e1), ghb(e2,e3)
EIP[p1] = L1, EIP[p2] = L1e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0 e3:Wy(p2) .e4:Wx(p1) .
fence(e1,p2), fence(e2,p1)ghb(e3,e1), ghb(e2,e3)ghb(e4,e2), ghb(e1,e4)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0e3:Wy(p2), val(e3) = 1
fence(e1,p2), fence(e2,p1) ghb(e3,e1), ghb(e3,e2)
val(e2) = val(e3)
EIP[p1] = L2, EIP[p2] = L2e1:Rx(p2), val(e1) = 0e2:Ry(p1), val(e2) = 0
fence(e1,p2), fence(e2,p1)
EIP[p1] = End, EIP[p2] = L2EAX[p1] = 0 .e1:Rx(p2), val(e1) = 0
fence(e1,p2) .
t1_L1_L2(p1)
t2_L1_L2(p2)t2_L1_L2(p2)
t1_L2_End(p1)
t2_L2_End(p2)1 2
3
4
5
6
44 / 66
Première implémentation
Première implémentation basée sur ces idées : inefficace
Source d’inefficacité : la relation co
Propagation tampon-mémoire↔ Ordre total co
Idée : restreindre les paires co fabriquées à celles présentes dansl’ordonnancement
Mais : risque d’oublier des exécutions réalisables
I On prouve que cette optimisation est correcte en TSO
45 / 66
Première implémentation
Première implémentation basée sur ces idées : inefficace
Source d’inefficacité : la relation co
Propagation tampon-mémoire↔ Ordre total co
Idée : restreindre les paires co fabriquées à celles présentes dansl’ordonnancement
Mais : risque d’oublier des exécutions réalisables
I On prouve que cette optimisation est correcte en TSO
45 / 66
Première implémentation
Première implémentation basée sur ces idées : inefficace
Source d’inefficacité : la relation co
Propagation tampon-mémoire↔ Ordre total co
Idée : restreindre les paires co fabriquées à celles présentes dansl’ordonnancement
Mais : risque d’oublier des exécutions réalisables
I On prouve que cette optimisation est correcte en TSO
45 / 66
Intuition de l’optimisation
e1:Wxe2:Wx
ghb(e1,e2)
…
e1:Wx
X := 2
X := 1
e1:Wxe2:Wx
ghb(e2,e1)
→
e2:Wxe1:Wx
ghb(e1,e2)
…
e1:Wx
X := 1
X := 1
e1:Wxe2:Wx
ghb(e2,e1)
e2:Wx
X := 2
X := 2
46 / 66
Intuition de l’optimisation
e1:Wxe2:Wx
ghb(e1,e2)
…
e1:Wx
X := 2
X := 1
e1:Wxe2:Wx
ghb(e2,e1)
→
e2:Wxe1:Wx
ghb(e1,e2)
…
e1:Wx
X := 1
X := 1
e1:Wxe2:Wx
ghb(e2,e1)
e2:Wx
X := 2
X := 2
46 / 66
Notion de compatibilité avec l’ordonnancement
Ordonnancement : relation sched, ordonne totalement les événe-ments suivant l’ordre dans lequel ils ont été générés
Compatiblilité avec l’ordonnancementUne relation r est dite compatible avec un ordonnancement scheds’il n’existe pas de paire d’événements (e1, e2) telle quesched(e1, e2) et r(e2, e1) soient tous les deux vrais
47 / 66
Enoncé du théorème
ThéorèmePour toute exécution E = (E, po, rf, co) d’un programme P , il existeun ordonnancement sched tel que co soit compatible avec sched
Preuve : par induction sur le nombre de paires co incompatibles avecsched
A chaque pas, on peut créer un nouvel ordonnancement sched’ danslequel on a une paire co en moins incompatible avec sched’
Utilisation d’un lemme permettant de réordonnancer toute paired’événements pour lesquels co est incompatible avec sched
48 / 66
Relations compatibles avec l’ordonnancement
• po, ppo et fence : issues d’un même processus,nécessairement compatibles avec l’ordonnancement
• rf : une lecture ne pouvant lire que depuis une écritureordonnancée avant, nécessairement compatible avecl’ordonnancement
49 / 66
Nouvelle définition de ghb
On regroupe dans une relation hb les relations compatibles avecl’ordonnancement, ainsi que celles qu’on voudrait compatibles :
Happens-Before (hb)hb est la plus petite relation d’ordre partiel telle que :
∀e1, e2· ppo(e1, e2) → hb(e1, e2) HB-PPO
∀e1, e2· fence(e1, e2) → hb(e1, e2) HB-FENCE
∀e1, e2· rfe(e1, e2) → hb(e1, e2) HB-RFE
∀e1, e2· co(e1, e2) → hb(e1, e2) HB-CO
50 / 66
Nouvelle définition de ghb
La relation ghb est alors reformulée comme suit :
Global-Happens-Before (ghb)ghb est la plus petite relation d’ordre partiel telle que :
∀e1, e2· hb(e1, e2) → ghb(e1, e2) GHB-HB
∀e1, e2· fr(e1, e2) → ghb(e1, e2) GHB-FR
51 / 66
Lemme de réordonnancement
Hypothèses : co(e2, e1) ∧ sched(e1, e2)
S A e1:WX C e2:WX B
co(e2,e1)
Conclusion : co(e2, e1) ∧ sched’(e2, e1) ∧∀(e3, e4)· hb(e3, e4) ∧ sched(e3, e4)→ sched’(e3, e4)
52 / 66
Lemme de réordonnancement
Hypothèses : co(e2, e1) ∧ sched(e1, e2)
S1 A e1:WX C1 C2 e2:WX B S2
co(e2,e1)
Conclusion : co(e2, e1) ∧ sched’(e2, e1) ∧∀(e3, e4)· hb(e3, e4) ∧ sched(e3, e4)→ sched’(e3, e4)
52 / 66
Lemme de réordonnancement
Hypothèses : co(e2, e1) ∧ sched(e1, e2)
S ′ A C2 e2:WXe1:WX C1 B
co(e2,e1)
Conclusion : co(e2, e1) ∧ sched’(e2, e1) ∧∀(e3, e4)· hb(e3, e4) ∧ sched(e3, e4)→ sched’(e3, e4)
52 / 66
Lemme de découpage
Hypothèses : ¬hb(e1, e2) ∧ sched(e1, e2)
S A e1:WX C e2:WX B
S1 A e1:WX C1 C2 e2:WX B S2
Conclusion : ∀(eC1 , eC2) ∈ (C1 × C2)· ¬hb(eC1 , eC2) ∧ ¬po(eC1 , eC2)
53 / 66
Lemme de découpage
Hypothèses : ¬hb(e1, e2) ∧ sched(e1, e2)
AS1
↑
e1:WX C1,1
↑ ↑
C1,m
↑
C2,1
↓ ↓
C2,n
↓
e2:WX B S2
↓
Conclusion : ∀(eC1 , eC2) ∈ (C1 × C2)· ¬hb(eC1 , eC2) ∧ ¬po(eC1 , eC2)
53 / 66
Nouveau calcul de pré-image
On relie les écritures sur une même variable en suivantl’ordonnancement :
e1:Wx(p1)e2:Wx(p2)e3:Wx(p3)ghb(e2,e1)ghb(e3,e2)ghb(e3,e1)
e1:Wx(p1)
e1:Wx(p1)e2:Wx(p2)ghb(e2,e1)
X := 1
X := 2
54 / 66
Outil Cubicle-W
Les techniques décrites précédemment ont été mises en oeuvredans Cubicle-W .
Cubicle-W est disponible à l’adresse :
http://cubicle.lri.fr/cubiclew/
55 / 66
Autres outils de vérification pour mémoire faibleOutils paramétrés :• Dual-TSO (Abdulla, Atig, Bouajjani, Ngo, Univ. Uppsala & Univ. Paris 7)
I propriétés de sûretéI utilise des tampons de lecture
Outils non paramétrés :• MEMORAX (Abdulla, Atig et al, Univ. Uppsala)
I propriétés de sûretéI deux modes de fonctionnement : tampon unique, tampons
bornés avec abstraction de prédicats
• Trencher (Bouajjani, Calin et al, Univ. Paris 7 & Univ. Kaiserslautern)I robustesse, recherche de bugsI introduction ponctuelle de la sémantique TSO
• CBMC (Alglave, Kroening et al, Univ. College London & Univ. Oxford)I recherche de bugsI analyse de code CI modèle axiomatique similaire à Cubicle-W
56 / 66
Benchmarks
Cubicle-W a été évalué sur différentes sortes d’algorithmes :
• Exclusion mutuelleI Haut niveau : Mutex Naïf, Arbitre, Dekker, Peterson, BurnsI Assembleur : Spinlock Linux, Mutex/xchg, Mutex/cmpxchg
• Sense-Reversing Barrier
• Two-Phase Commit
57 / 66
Benchmarks
Cubicle Dual TSO Memorax Trencher CBMCW PB Unwind 2
naive mutex 0.30s [N] – – – –TO[5] TO [11] TO [6] TO [5]
35.7s [4] 2m27 [10] 54.8s [5] 2m24 [4]lamport 0.60s [N] – – – –
TO [4] TO [4] A [5] TO [4]9.42s [3] 3m02 [3] 3.37s [4] 8m39 [3]
spinlock 0.06s [N] TO [N] – – –TO [6] TO [7] TO [7] TO [3]
1m16 [5] 9m52 [6] 21.45s [6] 19.58s [2]sense_rev 0.06s [N] – – – –
TO [3] TO [3] TO [5] TO [9]0.09s [2] 0.09s [2] 8 [4] 12m25 [8]
arbiter_v2 13.5s [N] – – – –TO [1+3] TO [1+2] A [1+4] TO [1+4]
24.2s [1+2] 1.62s [1+3] 2m56 [1+3]two_phase 54.1s [N] – – – –
TO [3] TO [4] TO [4] TO [11]12.3s [2] 39.7s [3] 8 [3] 12m39 [10]
8 = réponse incorrecte A = crash de l’outil TO> 20 minutes58 / 66
Conclusion et Perspectives
Contributions :
• Un outil de compilation de x86-TSO vers Cubicle-W
• Un Model Checker pour des Programmes Paramétrés sur desModèles de Mémoire Faibles
• Une optimisation permettant de réaliser une analyse efficace
Perspectives :
• Inférence de fence
• Génération d’invariants
• Autres modèles mémoires
• Approche Dual-TSO
• Programmes communiquant par canaux
59 / 66
MERCI
Cubicle-W : Parameterized Model Checking on Weak MemorySylvain Conchon, David Declerck, Fatiha Zaïdi [IJCAR 2018]Compiling Parameterized x86-TSO Concurrent Programs to Cubicle-WSylvain Conchon, David Declerck, Fatiha Zaïdi [ICFEM 2017]Parameterized Model Checking Modulo Explicit Weak Memory ModelsSylvain Conchon, David Declerck, Fatiha Zaïdi [IMPEX 2017]
PMCx86 : http://www.lri.fr/~declerck/pmcx86/
Cubicle-W : http://cubicle.lri.fr/cubiclew/
60 / 66
Programmes communiquant par canaux
Le modèle axiomatique de TSO n’est pas sans rappeler ce qui se faiten algorithmique distribuée avec des canaux
Idée : peut-on utiliser une approche similaire pour analyser des pro-grammes communiquant par canaux avec Cubicle ?
61 / 66
Programmes communiquant par canaux
Comme pour TSO, on peut caractériser une exécution pardifférentes relations :
• so (Send Order) : ordre d’envoi (≈ co en TSO)
• ro (Receive Order) : ordre de réception
• rf (Receive-From) : relie une réception à un envoi (≈ rf en TSO)
• fr (From-Receive) : si rf(e1,e2) et so(e1,e3) alors fr(e2,e3)(≈ fr en TSO)
62 / 66
Programmes communiquant par canaux
Global-Happens-Before (ghb)ghb est la plus petite relation d’ordre partiel telle que :
∀e1, e2· so(e1, e2) → ghb(e1, e2) GHB-SO
∀e1, e2· ro(e1, e2) → ghb(e1, e2) GHB-RO
∀e1, e2· rf(e1, e2) → ghb(e1, e2) GHB-RF
∀e1, e2· fr(e1, e2) → ghb(e1, e2) GHB-FR
63 / 66
Approche Dual-TSO
Dual-TSO utilise des tampons de lecture plutôt que des tamponsd’écriture ; cette modélisation préserve les propriétés d’atteignabilitéComme pour TSO, on peut encoder les tampons Dual-TSO avec lestableaux non-bornés de Cubicle
Noeuds Tests de TempsVisités Point Fixe d’Analyse
spinlock TSO 357 260 171 4m40sspinlock Dual-TSO 205 179 080 12.9sspinlock Cubicle-W 13 101 0.06sspinlock SC 10 63 0.03s
64 / 66
Approche Dual-TSO
Dual-TSO utilise des tampons de lecture plutôt que des tamponsd’écriture ; cette modélisation préserve les propriétés d’atteignabilitéComme pour TSO, on peut encoder les tampons Dual-TSO avec lestableaux non-bornés de Cubicle
Noeuds Tests de TempsVisités Point Fixe d’Analyse
spinlock TSO 357 260 171 4m40s
spinlock Dual-TSO 205 179 080 12.9sspinlock Cubicle-W 13 101 0.06sspinlock SC 10 63 0.03s
64 / 66
Approche Dual-TSO
Dual-TSO utilise des tampons de lecture plutôt que des tamponsd’écriture ; cette modélisation préserve les propriétés d’atteignabilitéComme pour TSO, on peut encoder les tampons Dual-TSO avec lestableaux non-bornés de Cubicle
Noeuds Tests de TempsVisités Point Fixe d’Analyse
spinlock TSO 357 260 171 4m40sspinlock Dual-TSO 205 179 080 12.9s
spinlock Cubicle-W 13 101 0.06sspinlock SC 10 63 0.03s
64 / 66
Approche Dual-TSO
Dual-TSO utilise des tampons de lecture plutôt que des tamponsd’écriture ; cette modélisation préserve les propriétés d’atteignabilitéComme pour TSO, on peut encoder les tampons Dual-TSO avec lestableaux non-bornés de Cubicle
Noeuds Tests de TempsVisités Point Fixe d’Analyse
spinlock TSO 357 260 171 4m40sspinlock Dual-TSO 205 179 080 12.9sspinlock Cubicle-W 13 101 0.06s
spinlock SC 10 63 0.03s
64 / 66
Approche Dual-TSO
Dual-TSO utilise des tampons de lecture plutôt que des tamponsd’écriture ; cette modélisation préserve les propriétés d’atteignabilitéComme pour TSO, on peut encoder les tampons Dual-TSO avec lestableaux non-bornés de Cubicle
Noeuds Tests de TempsVisités Point Fixe d’Analyse
spinlock TSO 357 260 171 4m40sspinlock Dual-TSO 205 179 080 12.9sspinlock Cubicle-W 13 101 0.06sspinlock SC 10 63 0.03s
64 / 66
Génération d’invariants
Cubicle possède un mécanisme de génération d’invariants (BRAB)
Guidé par une exploration avant finie
L’adapter à TSO n’est pas trivial :
• exploration avant opérationnelle ou axiomatique ?
• si opérationnelle, comment faire le lien avec l’axiomatique ?
• si axiomatique, quels invariants générer ?
65 / 66
Terminaison
La terminaison de Cubicle n’est pas garantie dans le cas général
On peut prouver la terminaison sur un système donné si on peutexhiber un bel ordre sur les configurations
Si un bel ordre existe en SC, en existe-t-il un en TSO ?
66 / 66
Terminaison
La terminaison de Cubicle n’est pas garantie dans le cas général
On peut prouver la terminaison sur un système donné si on peutexhiber un bel ordre sur les configurations
Si un bel ordre existe en SC, en existe-t-il un en TSO ?
66 / 66
Recommended