Véri˙cation par Model Checking de Programmes Concurrents...

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