Skip to content

Commit 4f80557

Browse files
authored
Merge pull request #137 from goblint/thread/join
Handle thread joins
2 parents 8ebcb00 + b5dc093 commit 4f80557

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+393
-174
lines changed

src/analyses/arinc.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ struct
403403
if mode_is_multi (Pmo.of_int i) then (
404404
let tasks = ctx.global tasks_var in
405405
ignore @@ printf "arinc: SetPartitionMode NORMAL: spawning %i processes!\n" (Tasks.cardinal tasks);
406-
Tasks.iter (fun (fs,f_d) -> Queries.LS.iter (fun f -> ctx.spawn (fst f) []) fs) tasks;
406+
Tasks.iter (fun (fs,f_d) -> Queries.LS.iter (fun f -> ctx.spawn None (fst f) []) fs) tasks;
407407
);
408408
add_action (SetPartitionMode pm)
409409
|> D.pmo (const @@ Pmo.of_int i)
@@ -653,7 +653,7 @@ struct
653653
let startstate v = { pid = Pid.of_int 0L; pri = Pri.top (); per = Per.top (); cap = Cap.top (); pmo = Pmo.of_int 1L; pre = PrE.of_int 0L; pred = Pred.of_node (MyCFG.Function (emptyFunction "main").svar); ctx = Ctx.top () }
654654
let exitstate v = D.bot ()
655655

656-
let threadenter ctx f args =
656+
let threadenter ctx lval f args =
657657
let d : D.t = ctx.local in
658658
let tasks = ctx.global tasks_var in
659659
(* TODO: optimize finding *)
@@ -664,7 +664,7 @@ struct
664664
let f_d = snd (Tasks.choose tasks_f) in
665665
{ f_d with pre = d.pre }
666666

667-
let threadspawn ctx f args fctx = D.bot ()
667+
let threadspawn ctx lval f args fctx = D.bot ()
668668
end
669669

670670
let _ =

src/analyses/base.ml

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,7 @@ struct
16371637
let find_fps e xs = Addr.to_var_must e @ xs in
16381638
let vars = AD.fold find_fps adrs [] in
16391639
let funs = List.filter (fun x -> isFunctionType x.vtype) vars in
1640-
List.iter (fun x -> ctx.spawn x []) funs
1640+
List.iter (fun x -> ctx.spawn None x []) funs
16411641
| _ -> ()
16421642
);
16431643
match lval with (* this section ensure global variables contain bottom values of the proper type before setting them *)
@@ -1748,7 +1748,13 @@ struct
17481748
| TFun(ret, _, _, _) -> ret
17491749
| _ -> assert false
17501750
in
1751-
set ~t_override ctx.ask ctx.global nst (return_var ()) t_override (eval_rv ctx.ask ctx.global ctx.local exp)
1751+
let rv = eval_rv ctx.ask ctx.global ctx.local exp in
1752+
let nst =
1753+
match ThreadId.get_current ctx.ask with
1754+
| `Lifted tid when ThreadReturn.is_current ctx.ask -> Tuple2.map1 (CPA.add tid rv) nst
1755+
| _ -> nst
1756+
in
1757+
set ~t_override ctx.ask ctx.global nst (return_var ()) t_override rv
17521758
(* lval_raw:None, and rval_raw:None is correct here *)
17531759

17541760
let vdecl ctx (v:varinfo) =
@@ -1834,8 +1840,8 @@ struct
18341840

18351841

18361842

1837-
let forkfun (ctx:(D.t, G.t, C.t) Analyses.ctx) (lv: lval option) (f: varinfo) (args: exp list) : (varinfo * exp list) list =
1838-
let create_thread arg v =
1843+
let forkfun (ctx:(D.t, G.t, C.t) Analyses.ctx) (lv: lval option) (f: varinfo) (args: exp list) : (lval option * varinfo * exp list) list =
1844+
let create_thread lval arg v =
18391845
try
18401846
(* try to get function declaration *)
18411847
let fd = Cilfacade.getdec v in
@@ -1844,25 +1850,25 @@ struct
18441850
| Some x -> [x]
18451851
| None -> List.map (fun x -> MyCFG.unknown_exp) fd.sformals
18461852
in
1847-
Some (v, args)
1853+
Some (lval, v, args)
18481854
with Not_found ->
18491855
if LF.use_special f.vname then None (* we handle this function *)
18501856
else if isFunctionType v.vtype then (
18511857
M.warn_each ("Creating a thread from unknown function " ^ v.vname);
1852-
Some (v, args)
1858+
Some (lval, v, args)
18531859
) else (
18541860
M.warn_each ("Not creating a thread from " ^ v.vname ^ " because its type is " ^ sprint d_type v.vtype);
18551861
None
18561862
)
18571863
in
18581864
match LF.classify f.vname args with
18591865
(* handling thread creations *)
1860-
| `ThreadCreate (start,ptc_arg) -> begin
1866+
| `ThreadCreate (id,start,ptc_arg) -> begin
18611867
(* extra sync so that we do not analyze new threads with bottom global invariant *)
18621868
publish_all ctx;
18631869
(* Collect the threads. *)
18641870
let start_addr = eval_tv ctx.ask ctx.global ctx.local start in
1865-
List.filter_map (create_thread (Some ptc_arg)) (AD.to_var_may start_addr)
1871+
List.filter_map (create_thread (Some (Mem id, NoOffset)) (Some ptc_arg)) (AD.to_var_may start_addr)
18661872
end
18671873
| `Unknown _ when get_bool "exp.unknown_funs_spawn" -> begin
18681874
let args =
@@ -1872,7 +1878,7 @@ struct
18721878
in
18731879
let flist = collect_funargs ctx.ask ctx.global ctx.local args in
18741880
let addrs = List.concat (List.map AD.to_var_may flist) in
1875-
List.filter_map (create_thread None) addrs
1881+
List.filter_map (create_thread None None) addrs
18761882
end
18771883
| _ -> []
18781884

@@ -1928,8 +1934,8 @@ struct
19281934
let special ctx (lv:lval option) (f: varinfo) (args: exp list) =
19291935
(* let heap_var = heap_var !Tracing.current_loc in*)
19301936
let forks = forkfun ctx lv f args in
1931-
if M.tracing then if not (List.is_empty forks) then M.tracel "spawn" "Base.special %s: spawning functions %a\n" f.vname (d_list "," d_varinfo) (List.map fst forks);
1932-
List.iter (uncurry ctx.spawn) forks;
1937+
if M.tracing then if not (List.is_empty forks) then M.tracel "spawn" "Base.special %s: spawning functions %a\n" f.vname (d_list "," d_varinfo) (List.map BatTuple.Tuple3.second forks);
1938+
List.iter (BatTuple.Tuple3.uncurry ctx.spawn) forks;
19331939
let cpa,dep as st = ctx.local in
19341940
let gs = ctx.global in
19351941
match LF.classify f.vname args with
@@ -2012,7 +2018,18 @@ struct
20122018
end
20132019
| `Unknown "exit" -> raise Deadcode
20142020
| `Unknown "abort" -> raise Deadcode
2015-
| `Unknown "pthread_exit" -> raise Deadcode (* TODO: somehow actually return value, pthread_join doesn't handle anyway? *)
2021+
| `Unknown "pthread_exit" ->
2022+
begin match args with
2023+
| [exp] ->
2024+
begin match ThreadId.get_current ctx.ask with
2025+
| `Lifted tid ->
2026+
let rv = eval_rv ctx.ask ctx.global ctx.local exp in
2027+
ctx.sideg tid rv
2028+
| _ -> ()
2029+
end;
2030+
raise Deadcode
2031+
| _ -> failwith "Unknown pthread_exit."
2032+
end
20162033
| `Unknown "__builtin_expect" ->
20172034
begin match lv with
20182035
| Some v -> assign ctx v (List.hd args)
@@ -2023,10 +2040,20 @@ struct
20232040
| Some x -> assign ctx x (List.hd args)
20242041
| None -> ctx.local
20252042
end
2043+
(* handling thread creations *)
2044+
| `ThreadCreate _ ->
2045+
D.bot () (* actual results joined via threadspawn *)
20262046
(* handling thread joins... sort of *)
20272047
| `ThreadJoin (id,ret_var) ->
20282048
begin match (eval_rv ctx.ask gs st ret_var) with
20292049
| `Int n when GU.opt_predicate (BI.equal BI.zero) (ID.to_int n) -> cpa,dep
2050+
| `Address ret_a ->
2051+
begin match eval_rv ctx.ask gs st id with
2052+
| `Address a ->
2053+
(* TODO: is this type right? *)
2054+
set ctx.ask gs st ret_a (Cil.typeOf ret_var) (get ctx.ask gs st a None)
2055+
| _ -> invalidate ctx.ask gs st [ret_var]
2056+
end
20302057
| _ -> invalidate ctx.ask gs st [ret_var]
20312058
end
20322059
| `Malloc size -> begin
@@ -2145,15 +2172,25 @@ struct
21452172
Printable.get_short_list (GU.demangle f.svar.vname ^ "(") ")" 80 args_short
21462173

21472174

2148-
let threadenter ctx (f: varinfo) (args: exp list): D.t =
2175+
let threadenter ctx (lval: lval option) (f: varinfo) (args: exp list): D.t =
21492176
try
21502177
make_entry ctx f args
21512178
with Not_found ->
21522179
(* Unknown functions *)
21532180
ctx.local
21542181

2155-
let threadspawn ctx (f: varinfo) (args: exp list) fctx: D.t =
2156-
D.bot ()
2182+
let threadspawn ctx (lval: lval option) (f: varinfo) (args: exp list) fctx: D.t =
2183+
match lval with
2184+
| Some lval ->
2185+
begin match ThreadId.get_current fctx.ask with
2186+
| `Lifted tid ->
2187+
(* TODO: is this type right? *)
2188+
set ctx.ask ctx.global ctx.local (eval_lv ctx.ask ctx.global ctx.local lval) (Cil.typeOfLval lval) (`Address (AD.from_var tid))
2189+
| _ ->
2190+
ctx.local
2191+
end
2192+
| None ->
2193+
ctx.local
21572194
end
21582195

21592196
module type MainSpec = sig

src/analyses/condVars.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ struct
143143
ctx.local
144144

145145
let startstate v = D.bot ()
146-
let threadenter ctx f args = D.bot ()
147-
let threadspawn ctx f args fctx = D.bot ()
146+
let threadenter ctx lval f args = D.bot ()
147+
let threadspawn ctx lval f args fctx = D.bot ()
148148
let exitstate v = D.bot ()
149149
end
150150

src/analyses/contain.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -805,8 +805,8 @@ struct
805805
end
806806

807807
let startstate v = D.bot ()
808-
let threadenter ctx f args = D.bot ()
809-
let threadspawn ctx f args fctx = D.bot ()
808+
let threadenter ctx lval f args = D.bot ()
809+
let threadspawn ctx lval f args fctx = D.bot ()
810810
let exitstate v = D.bot ()
811811
end
812812

src/analyses/deadlock.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ struct
5252

5353
(* Some required states *)
5454
let startstate _ : D.t = D.empty ()
55-
let threadenter ctx f args : D.t = D.empty ()
56-
let threadspawn ctx f args fctx = D.empty ()
55+
let threadenter ctx lval f args : D.t = D.empty ()
56+
let threadspawn ctx lval f args fctx = D.empty ()
5757
let exitstate _ : D.t = D.empty ()
5858

5959
(* ======== Transfer functions ======== *)

src/analyses/deadlocksByRaces.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ struct
5151
| _ -> MSpec.special ctx lval f arglist
5252

5353
let startstate v = MSpec.startstate v
54-
let threadenter ctx f args = MSpec.threadenter ctx f args
55-
let threadspawn ctx f args fctx = MSpec.threadspawn ctx f args fctx
54+
let threadenter ctx lval f args = MSpec.threadenter ctx lval f args
55+
let threadspawn ctx lval f args fctx = MSpec.threadspawn ctx lval f args fctx
5656
let exitstate v = MSpec.exitstate v
5757
end
5858

src/analyses/expRelation.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ struct
107107
ctx.local
108108

109109
let startstate v = D.bot ()
110-
let threadenter ctx f args = D.top ()
111-
let threadspawn ctx f args fctx = D.bot ()
110+
let threadenter ctx lval f args = D.top ()
111+
let threadspawn ctx lval f args fctx = D.bot ()
112112
let exitstate v = D.top ()
113113
end
114114

src/analyses/extract_arinc.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ struct
362362
| "SetPartitionMode", "NORMAL"::_ ->
363363
let tasks = ctx.global tasks_var in
364364
ignore @@ printf "arinc: SetPartitionMode NORMAL: spawning %i processes!\n" (Tasks.cardinal tasks);
365-
Tasks.iter (fun (fs,f_d) -> Queries.LS.iter (fun f -> ctx.spawn (fst f) []) fs) tasks;
365+
Tasks.iter (fun (fs,f_d) -> Queries.LS.iter (fun f -> ctx.spawn None (fst f) []) fs) tasks;
366366
| "SetPartitionMode", x::_ -> failwith @@ "SetPartitionMode: arg "^x
367367
| s, a -> print_endline @@ "arinc: FUN: "^s^"("^String.concat ", " a^")"
368368
end;
@@ -390,7 +390,7 @@ struct
390390
print_endline "Run ./spin/check.sh to verify."
391391
)
392392

393-
let threadenter ctx f args =
393+
let threadenter ctx lval f args =
394394
let tasks = ctx.global tasks_var in
395395
(* TODO: optimize finding *)
396396
let tasks_f = Tasks.filter (fun (fs,f_d) ->
@@ -400,7 +400,7 @@ struct
400400
let f_d = snd (Tasks.choose tasks_f) in
401401
f_d
402402

403-
let threadspawn ctx f args fctx = D.bot ()
403+
let threadspawn ctx lval f args fctx = D.bot ()
404404
end
405405

406406
let _ =

src/analyses/extract_osek.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,8 @@ struct
316316
) ctx.local args_product
317317

318318
let startstate v = Pid.of_int 0L, Ctx.top (), Pred.of_node (MyCFG.Function (emptyFunction "main").svar)
319-
let threadenter ctx f args = D.bot ()
320-
let threadspawn ctx f args fctx = D.bot ()
319+
let threadenter ctx lval f args = D.bot ()
320+
let threadspawn ctx lval f args fctx = D.bot ()
321321
let exitstate v = D.bot ()
322322

323323
let init () = (* registers which functions to extract and writes out their definitions *)

src/analyses/fileUse.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ struct
296296
| _ -> m
297297

298298
let startstate v = D.bot ()
299-
let threadenter ctx f args = D.bot ()
300-
let threadspawn ctx f args fctx = D.bot ()
299+
let threadenter ctx lval f args = D.bot ()
300+
let threadspawn ctx lval f args fctx = D.bot ()
301301
let exitstate v = D.bot ()
302302
end
303303

0 commit comments

Comments
 (0)