Skip to content

Commit 0ad89cd

Browse files
Complete tutorial
1 parent 35cbd45 commit 0ad89cd

5 files changed

Lines changed: 168 additions & 55 deletions

File tree

src/analyses/tutorials/gStoreWidening.ml

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,63 @@ open SimplifiedAnalysis
33
open GStoreWideningHelper
44

55
(**
6-
This analysis proceeds in steps, with the steps building on each other.
6+
This analysis proceeds in steps, with the steps building on each other.
77
8-
For the sake of this analysis, we are assuming that all variables are of integer type.
9-
This allows us to keep the analysis simple in the beginning.
8+
For the sake of this analysis, we are assuming that all variables are of integer type.
9+
This allows us to keep the analysis simple in the beginning.
1010
1111
12-
1) First, a simple interval analysis is implemented which tracks intervals
13-
for local variables only.
12+
1) First, a simple interval analysis is implemented which tracks intervals
13+
for local variables only.
1414
1515
The majority of the code is already provided, there is one place where
16-
changes need to be made, namely the handling of branches.
16+
changes need to be made, namely the handling of branches.
1717
It is marked with TODO: 1).
1818
19-
2) Then the analysis is extended to also track values for globals via global store widening
19+
2) Then the analysis is extended to also track values for globals via global store widening
2020
2121
To this end, one should fix which set of globals to track, and their domain.
2222
Then, assignment and evaluation functions should be changed appropriately.
2323
These are marked with TODO: 2).
24-
25-
3) Define a helper analysis which tracks for each variable which thread ids are used to write to it,
24+
25+
3) Define a helper analysis which tracks for each variable which thread ids are used to write to it,
2626
and use this information to determine whether a variable is effectively local
2727
(i.e., only written by one thread).
2828
29-
This requires modifying the domain to store thread ids, and modifying the assign function
30-
to record thread ids for global variables.
29+
This requires modifying the domain to store thread ids, and modifying the assign function
30+
to record thread ids for global variables.
3131
Then, the query function should be modified to check whether there is only one thread
32-
accessing this variable, and whether it is the current one.
32+
accessing this variable, and whether it is the current one.
3333
These are marked with TODO: 3).
34-
35-
4) Modify the first analysis to exploit the information from the helper analysis to
34+
35+
4) Modify the first analysis to exploit the information from the helper analysis to
3636
track the values of effectively local variables more precisely in the thread that
3737
owns them, while keeping applying global store widening to obtain the perspective
3838
of other threads.
3939
4040
This will amount to modifying some of the places changed in step 2)
4141
42-
43-
After modifying things, don't forget to compile by running `make`
42+
43+
After modifying things, don't forget to compile by running `make`
4444
4545
There are regression tests for this analysis, which you can run by calling:
4646
- ./regtest.sh 99 05
4747
- ./regtest.sh 99 06
48+
- ./regtest.sh 99 07
4849
49-
After fixing the TODO: 1), the first regression test should pass.
50-
After fixing the TODO: 2), both the first and the second tests should pass.
50+
After fixing the TODO: 1), the first regression test should pass.
51+
After fixing the TODO: 2), both the first and the second tests should pass.
52+
After fixing the last TODO:, all three tests should pass
5153
52-
Running a regression test also produces a visualization of the analysis results as a HTML file in the folder
53-
result.
54+
Running a regression test also produces a visualization of the analysis results as a HTML file in the folder
55+
result.
5456
55-
You can access these by spinning up a HTTP server for the result directory,
56-
e.g., by calling `python3 -m http.server --directory result`.
57-
Then open `index.xml` in your browser.
57+
You can access these by spinning up a HTTP server for the result directory,
58+
e.g., by calling `python3 -m http.server --directory result`.
59+
Then open `index.xml` in your browser.
5860
59-
(When using devcontainer, VSCode will automatically detect the server and
60-
provide a link to open the visualization in your browser.)
61+
(When using devcontainer, VSCode will automatically detect the server and
62+
provide a link to open the visualization in your browser.)
6163
6264
*)
6365

@@ -80,7 +82,7 @@ module GStoreWideningAnalysis: SimplifiedSpec = struct
8082
(* Evaluate a single variable given a local state *)
8183
let eval_varinfo man state v =
8284
if v.vglob then
83-
(** TODO: 2) Modify so that we store values for globals *)
85+
(* TODO: 2) Modify so that we get values for globals *)
8486
top_of_var v
8587
else
8688
D.find v state
@@ -236,7 +238,7 @@ module GStoreWideningAnalysis: SimplifiedSpec = struct
236238
) (D.bot ()) f.sformals
237239
end
238240

239-
module ThreadSet = ConcDomain.ThreadSet
241+
module ThreadSet = ConcDomain.ThreadSet
240242

241243
module EffectivelyLocalAnalysis:SimplifiedSpec = struct
242244
let name = "effectivelyLocal"
@@ -252,20 +254,24 @@ module EffectivelyLocalAnalysis:SimplifiedSpec = struct
252254
let startcontext = ()
253255

254256
let assign man state lval rval =
255-
let tid = ThreadId.get_current_unlift (SimplifiedAnalysis.ask_of_man man) in
256-
let singleton_set = ThreadSet.singleton tid in
257-
match is_tracked_lval lval with
258-
| Some v ->
259-
(* TODO: 3) check if this is a global variable and if it is, record the thread id *)
257+
(* When the global initializers are evaluated, no threads exists yet *)
258+
if !AnalysisState.global_initialization then
260259
state
261-
| None ->
262-
state
263-
260+
else
261+
let tid = ThreadId.get_current_unlift (SimplifiedAnalysis.ask_of_man man) in
262+
let singleton_set = ThreadSet.singleton tid in
263+
match is_tracked_lval lval with
264+
| Some v ->
265+
(* TODO: 3) check if this is a global variable and if it is, record the thread id *)
266+
state
267+
| None ->
268+
state
269+
264270
let query man state (type a) (q: a Queries.t): a Queries.result =
265271
match q with
266272
| Queries.TutorialEffectivelyLocal v ->
267273
(* TODO: 3) Get the current thread id, and check whether there is only one thread
268-
accessing this variable, and whether it is the current one *)
274+
accessing this variable, and whether it is the current one *)
269275
Queries.Result.top q
270276
| _ -> Queries.Result.top q
271277

src/analyses/tutorials/gStoreWideningSol.ml

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,6 @@ open GStoreWideningHelper
88
** THIS IS THE SOLUTION TO THIS TUTORIAL ANALYSIS, READING THIS BEFORE DOING THE TUTORIAL WILL SPOIL THE FUN. **
99
** YOU HAVE BEEN WARNED. **
1010
**********************************************************************************************************************
11-
12-
There are two regression tests for this analysis, which you can run by calling:
13-
- ./regtest.sh 99 05
14-
- ./regtest.sh 99 06
15-
16-
Running these scripts also produces a visualization of the analysis results as a HTML file in the folder
17-
result.
18-
19-
You can access these by spinning up a HTTP server, e.g., by calling `python3 -m http.server`
20-
21-
First fix the TODO: 1) to ensure unreachable code is marked as dead.
22-
Then, tackle TODO: 2) to change this analysis so it tracks global variables
23-
24-
After modifying things, don't forget to compile by running `make`
2511
*)
2612

2713

@@ -42,7 +28,8 @@ module Analysis: SimplifiedSpec = struct
4228

4329
(* Evaluate a single variable given a local state *)
4430
let eval_varinfo man state v =
45-
if v.vglob then
31+
if v.vglob && not (man.ask (Queries.TutorialEffectivelyLocal v)) then
32+
(* TODO: 2) Modify so that we get values for globals *)
4633
man.global v
4734
else
4835
D.find v state
@@ -145,7 +132,10 @@ module Analysis: SimplifiedSpec = struct
145132
else
146133
(** TODO: 2) Modify so that we store values for globals *)
147134
(man.sideg v (cast_to_typ v.vtype (eval man state rval));
148-
state)
135+
if man.ask (Queries.TutorialEffectivelyLocal v) then
136+
D.add v (cast_to_typ v.vtype (eval man state rval)) state
137+
else
138+
state)
149139
| None ->
150140
state
151141

@@ -201,5 +191,70 @@ module Analysis: SimplifiedSpec = struct
201191
) (D.bot ()) f.sformals
202192
end
203193

194+
module ThreadSet = ConcDomain.ThreadSet
195+
196+
module EffectivelyLocalAnalysis:SimplifiedSpec = struct
197+
let name = "effectivelyLocalSol"
198+
199+
module D = Lattice.Unit
200+
module C = Printable.Unit
201+
202+
(** TODO: 3) Modify so we store for each variable which thread ids are used to write to it *)
203+
module V = Basetype.Variables
204+
module G = ThreadSet
205+
206+
let startstate = ()
207+
let startcontext = ()
208+
209+
let assign man state lval rval =
210+
(* When the global initializers are evaluated, no threads exists yet *)
211+
if !AnalysisState.global_initialization then
212+
state
213+
else
214+
let tid = ThreadId.get_current_unlift (SimplifiedAnalysis.ask_of_man man) in
215+
let singleton_set = ThreadSet.singleton tid in
216+
match is_tracked_lval lval with
217+
| Some v ->
218+
(* TODO: 3) check if this is a global variable and if it is, record the thread id *)
219+
if v.vglob then
220+
(man.sideg v singleton_set; state)
221+
else
222+
state
223+
| None ->
224+
state
225+
226+
let query man state (type a) (q: a Queries.t): a Queries.result =
227+
match q with
228+
| Queries.TutorialEffectivelyLocal v when not !AnalysisState.global_initialization ->
229+
(* TODO: 3) Get the current thread id, and check whether there is only one thread
230+
accessing this variable, and whether it is the current one *)
231+
let tid = ThreadId.get_current_unlift (SimplifiedAnalysis.ask_of_man man) in
232+
let singleton_set = ThreadSet.singleton tid in
233+
let writers = man.global v in
234+
ThreadSet.equal singleton_set writers
235+
| _ -> Queries.Result.top q
236+
237+
let branch man state e tv = state
238+
239+
let return _ state _ _ =
240+
state
241+
242+
let body _ state f = ()
243+
244+
let enter man state _ f args = ()
245+
246+
let combine _ state _ lval _ _ = ()
247+
let special man state lval _ _ = ()
248+
249+
let context _ (_, c) _ _ =
250+
c
251+
252+
let threadenter _ _ f _ = ()
253+
end
254+
255+
256+
257+
204258
let _ =
205-
MCPRegistry.registered_simplified_analysis (module Analysis:SimplifiedSpec)
259+
MCPRegistry.registered_simplified_analysis (module Analysis:SimplifiedSpec);
260+
MCPRegistry.registered_simplified_analysis (module EffectivelyLocalAnalysis:SimplifiedSpec)

tests/regression/99-tutorials/05-gstore-zero.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SKIP PARAM: --set ana.activated '["gStoreWidening","assert"]'
1+
// SKIP PARAM: --set ana.activated '["gStoreWidening","assert","escape"]'
22
#include <goblint.h>
33

44
int main() {

tests/regression/99-tutorials/06-gstore-thread.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SKIP PARAM: --set ana.activated '["gStoreWidening","assert","base","mallocWrapper"]' --set ana.base.privatization none --enable exp.globs_are_top
1+
// SKIP PARAM: --set ana.activated '["gStoreWidening","assert","base","mallocWrapper","escape"]' --set ana.base.privatization none --enable exp.globs_are_top
22
// Additional analyses are activated so framework can handle thread creation
33
#include <goblint.h>
44
#include <pthread.h>
@@ -16,6 +16,7 @@ void* thread(void* arg) {
1616
}
1717

1818
int main() {
19+
global = 0;
1920
int x = 11;
2021

2122
pthread_t t;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SKIP PARAM: --set ana.activated '["gStoreWidening","effectivelyLocal","assert","base","mallocWrapper","thread","threadid","escape"]' --set ana.base.privatization none --enable exp.globs_are_top
2+
// Additional analyses are activated so framework can handle thread creation
3+
#include <goblint.h>
4+
#include <pthread.h>
5+
int global = 0;
6+
int thread_owned = 0;
7+
8+
void* thread(void* arg) {
9+
10+
thread_owned = 42;
11+
__goblint_check(thread_owned == 42);
12+
13+
if(global < 0) {
14+
global = -58;
15+
} else {
16+
global = 1;
17+
}
18+
19+
thread_owned = 11;
20+
__goblint_check(thread_owned == 11);
21+
22+
return NULL;
23+
}
24+
25+
int main() {
26+
int x = 11;
27+
global = 0;
28+
29+
pthread_t t;
30+
pthread_create(&t, NULL, &thread, NULL);
31+
32+
global = x*x;
33+
34+
if(global > 200) {
35+
global = -12;
36+
}
37+
38+
__goblint_check(global < 200);
39+
__goblint_check(global >= 0);
40+
__goblint_check(thread_owned >= 0);
41+
42+
43+
pthread_join(t, NULL);
44+
45+
global = 42;
46+
47+
// This is out of reach here
48+
__goblint_check(global == 42);
49+
50+
return 0;
51+
}

0 commit comments

Comments
 (0)