Skip to content

Commit 18a9aac

Browse files
authored
Merge pull request #1224 from goblint/issue-392
Add unknown thread ID
2 parents cb90811 + 54bcf60 commit 18a9aac

File tree

11 files changed

+165
-39
lines changed

11 files changed

+165
-39
lines changed

src/analyses/apron/relationPriv.apron.ml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,17 +1010,17 @@ struct
10101010
)
10111011
)
10121012
else (
1013-
match ConcDomain.ThreadSet.elements tids with
1014-
| [tid] ->
1015-
let lmust',l' = G.thread (getg (V.thread tid)) in
1016-
{st with priv = (w, LMust.union lmust' lmust, L.join l l')}
1017-
| _ ->
1018-
(* To match the paper more closely, one would have to join in the non-definite case too *)
1019-
(* Given how we handle lmust (for initialization), doing this might actually be beneficial given that it grows lmust *)
1020-
st
1021-
| exception SetDomain.Unsupported _ ->
1022-
(* elements throws if the thread set is top *)
1013+
if ConcDomain.ThreadSet.is_top tids then
10231014
st
1015+
else
1016+
match ConcDomain.ThreadSet.elements tids with
1017+
| [tid] ->
1018+
let lmust',l' = G.thread (getg (V.thread tid)) in
1019+
{st with priv = (w, LMust.union lmust' lmust, L.join l l')}
1020+
| _ ->
1021+
(* To match the paper more closely, one would have to join in the non-definite case too *)
1022+
(* Given how we handle lmust (for initialization), doing this might actually be beneficial given that it grows lmust *)
1023+
st
10241024
)
10251025

10261026
let thread_return ask getg sideg tid (st: relation_components_t) =

src/analyses/base.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,10 +2397,12 @@ struct
23972397
(* handling thread joins... sort of *)
23982398
| ThreadJoin { thread = id; ret_var }, _ ->
23992399
let st' =
2400+
(* TODO: should invalidate shallowly? https://github.com/goblint/analyzer/pull/1224#discussion_r1405826773 *)
24002401
match (eval_rv (Analyses.ask_of_ctx ctx) gs st ret_var) with
24012402
| Int n when GobOption.exists (BI.equal BI.zero) (ID.to_int n) -> st
24022403
| Address ret_a ->
24032404
begin match eval_rv (Analyses.ask_of_ctx ctx) gs st id with
2405+
| Thread a when ValueDomain.Threads.is_top a -> invalidate ~ctx (Analyses.ask_of_ctx ctx) gs st [ret_var]
24042406
| Thread a ->
24052407
let v = List.fold VD.join (VD.bot ()) (List.map (fun x -> G.thread (ctx.global (V.thread x))) (ValueDomain.Threads.elements a)) in
24062408
(* TODO: is this type right? *)

src/analyses/basePriv.ml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -544,17 +544,17 @@ struct
544544
)
545545
)
546546
else (
547-
match ConcDomain.ThreadSet.elements tids with
548-
| [tid] ->
549-
let lmust',l' = G.thread (getg (V.thread tid)) in
550-
{st with priv = (w, LMust.union lmust' lmust, L.join l l')}
551-
| _ ->
552-
(* To match the paper more closely, one would have to join in the non-definite case too *)
553-
(* Given how we handle lmust (for initialization), doing this might actually be beneficial given that it grows lmust *)
554-
st
555-
| exception SetDomain.Unsupported _ ->
556-
(* elements throws if the thread set is top *)
547+
if ConcDomain.ThreadSet.is_top tids then
557548
st
549+
else
550+
match ConcDomain.ThreadSet.elements tids with
551+
| [tid] ->
552+
let lmust',l' = G.thread (getg (V.thread tid)) in
553+
{st with priv = (w, LMust.union lmust' lmust, L.join l l')}
554+
| _ ->
555+
(* To match the paper more closely, one would have to join in the non-definite case too *)
556+
(* Given how we handle lmust (for initialization), doing this might actually be beneficial given that it grows lmust *)
557+
st
558558
)
559559

560560
let thread_return ask getg sideg tid (st: BaseComponents (D).t) =

src/analyses/threadAnalysis.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,18 @@ struct
5757
| ThreadJoin { thread = id; ret_var } ->
5858
(* TODO: generalize ThreadJoin like ThreadCreate *)
5959
(let has_clean_exit tid = not (BatTuple.Tuple3.third (ctx.global tid)) in
60+
let tids = ctx.ask (Queries.EvalThread id) in
6061
let join_thread s tid =
6162
if has_clean_exit tid && not (is_not_unique ctx tid) then
6263
D.remove tid s
6364
else
6465
s
6566
in
66-
match TS.elements (ctx.ask (Queries.EvalThread id)) with
67-
| [t] -> join_thread ctx.local t (* single thread *)
68-
| _ -> ctx.local (* if several possible threads are may-joined, none are must-joined *)
69-
| exception SetDomain.Unsupported _ -> ctx.local)
67+
if TS.is_top tids
68+
then ctx.local
69+
else match TS.elements tids with
70+
| [t] -> join_thread ctx.local t (* single thread *)
71+
| _ -> ctx.local (* if several possible threads are may-joined, none are must-joined *))
7072
| ThreadExit { ret_val } ->
7173
handle_thread_return ctx (Some ret_val);
7274
ctx.local

src/analyses/threadJoins.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct
5252
if TIDs.is_top threads then
5353
ctx.local
5454
else (
55-
(* elements throws if the thread set is top *)
55+
(* all elements are known *)
5656
let threads = TIDs.elements threads in
5757
match threads with
5858
| [tid] when TID.is_unique tid->
@@ -70,7 +70,7 @@ struct
7070
(MustTIDs.bot(), true) (* consider everything joined, MustTIDs is reversed so bot is All threads *)
7171
)
7272
else (
73-
(* elements throws if the thread set is top *)
73+
(* all elements are known *)
7474
let threads = TIDs.elements threads in
7575
if List.compare_length_with threads 1 > 0 then
7676
M.info ~category:Unsound "Ambiguous thread ID assume-joined, assuming all of those threads must-joined.";

src/analyses/useAfterFree.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct
7676
end
7777
else if HeapVars.mem heap_var (snd ctx.local) then begin
7878
if is_double_free then set_mem_safety_flag InvalidFree else set_mem_safety_flag InvalidDeref;
79-
M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "%s might occur in current unique thread %a for heap variable %a" bug_name ThreadIdDomain.FlagConfiguredTID.pretty current CilType.Varinfo.pretty heap_var
79+
M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "%s might occur in current unique thread %a for heap variable %a" bug_name ThreadIdDomain.Thread.pretty current CilType.Varinfo.pretty heap_var
8080
end
8181
end
8282
| `Top ->

src/cdomains/concDomain.ml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
11
(** Domains for thread sets and their uniqueness. *)
22

3-
module ThreadSet = SetDomain.ToppedSet (ThreadIdDomain.Thread) (struct let topname = "All Threads" end)
3+
module ThreadSet =
4+
struct
5+
include SetDomain.Make (ThreadIdDomain.Thread)
6+
7+
let is_top = mem UnknownThread
8+
9+
let top () = singleton UnknownThread
10+
11+
let merge uop cop x y =
12+
match is_top x, is_top y with
13+
| true, true -> uop x y
14+
| false, true -> x
15+
| true, false -> y
16+
| false, false -> cop x y
17+
18+
let meet x y = merge join meet x y
19+
20+
let narrow x y = merge (fun x y -> widen x (join x y)) narrow x y
21+
22+
end
423
module MustThreadSet = SetDomain.Reverse(ThreadSet)
524

625
module CreatedThreadSet = ThreadSet

src/cdomains/mHP.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ include Printable.Std
44

55
let name () = "mhp"
66

7-
module TID = ThreadIdDomain.FlagConfiguredTID
7+
module TID = ThreadIdDomain.Thread
88
module Pretty = GoblintCil.Pretty
99

1010
type t = {

src/cdomains/threadIdDomain.ml

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,79 @@ struct
280280
let name () = "FlagConfiguredTID: " ^ if history_enabled () then H.name () else P.name ()
281281
end
282282

283-
module Thread = FlagConfiguredTID
283+
type thread =
284+
| Thread of FlagConfiguredTID.t
285+
| UnknownThread
286+
[@@deriving eq, ord, hash]
287+
288+
module Thread : Stateful with type t = thread =
289+
struct
290+
include Printable.Std
291+
type t = thread [@@deriving eq, ord, hash]
292+
293+
let name () = "Thread id"
294+
let pretty () t =
295+
match t with
296+
| Thread tid -> FlagConfiguredTID.pretty () tid
297+
| UnknownThread -> Pretty.text "Unknown thread id"
298+
299+
let show t =
300+
match t with
301+
| Thread tid -> FlagConfiguredTID.show tid
302+
| UnknownThread -> "Unknown thread id"
303+
304+
let printXml f t =
305+
match t with
306+
| Thread tid -> FlagConfiguredTID.printXml f tid
307+
| UnknownThread -> BatPrintf.fprintf f "<value>\n<data>\nUnknown thread id\n</data>\n</value>\n"
308+
309+
let to_yojson t =
310+
match t with
311+
| Thread tid -> FlagConfiguredTID.to_yojson tid
312+
| UnknownThread -> `String "Unknown thread id"
313+
314+
let relift t =
315+
match t with
316+
| Thread tid -> Thread (FlagConfiguredTID.relift tid)
317+
| UnknownThread -> UnknownThread
318+
319+
let lift t = Thread t
320+
321+
let threadinit v ~multiple = Thread (FlagConfiguredTID.threadinit v ~multiple)
322+
323+
let is_main t =
324+
match t with
325+
| Thread tid -> FlagConfiguredTID.is_main tid
326+
| UnknownThread -> false
327+
328+
let is_unique t =
329+
match t with
330+
| Thread tid -> FlagConfiguredTID.is_unique tid
331+
| UnknownThread -> false
332+
333+
let may_create t1 t2 =
334+
match t1, t2 with
335+
| Thread tid1, Thread tid2 -> FlagConfiguredTID.may_create tid1 tid2
336+
| _, _ -> true
337+
338+
let is_must_parent t1 t2 =
339+
match t1, t2 with
340+
| Thread tid1, Thread tid2 -> FlagConfiguredTID.is_must_parent tid1 tid2
341+
| _, _ -> false
342+
343+
module D = FlagConfiguredTID.D
344+
345+
let threadenter ~multiple (t, d) node i v =
346+
match t with
347+
| Thread tid -> List.map lift (FlagConfiguredTID.threadenter ~multiple (tid, d) node i v)
348+
| UnknownThread -> assert false
349+
350+
let threadspawn = FlagConfiguredTID.threadspawn
351+
352+
let created t d =
353+
match t with
354+
| Thread tid -> Option.map (List.map lift) (FlagConfiguredTID.created tid d)
355+
| UnknownThread -> None
356+
end
284357

285358
module ThreadLifted = Lift (Thread)

src/cdomains/valueDomain.ml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -552,11 +552,9 @@ struct
552552
| y, Blob (x,s,o) -> Blob (join (x:t) y, s, o)
553553
| (Thread x, Thread y) -> Thread (Threads.join x y)
554554
| (Int x, Thread y)
555-
| (Thread y, Int x) ->
556-
Thread y (* TODO: ignores int! *)
555+
| (Thread y, Int x) -> Thread (Threads.join y (Threads.top ()))
557556
| (Address x, Thread y)
558-
| (Thread y, Address x) ->
559-
Thread y (* TODO: ignores address! *)
557+
| (Thread y, Address x) -> Thread (Threads.join y (Threads.top ()))
560558
| (JmpBuf x, JmpBuf y) -> JmpBuf (JmpBufs.join x y)
561559
| (Mutex, Mutex) -> Mutex
562560
| (MutexAttr x, MutexAttr y) -> MutexAttr (MutexAttr.join x y)
@@ -585,11 +583,9 @@ struct
585583
| (Blob x, Blob y) -> Blob (Blobs.widen x y) (* TODO: why no blob special cases like in join? *)
586584
| (Thread x, Thread y) -> Thread (Threads.widen x y)
587585
| (Int x, Thread y)
588-
| (Thread y, Int x) ->
589-
Thread y (* TODO: ignores int! *)
586+
| (Thread y, Int x) -> Thread (Threads.widen y (Threads.join y (Threads.top ())))
590587
| (Address x, Thread y)
591-
| (Thread y, Address x) ->
592-
Thread y (* TODO: ignores address! *)
588+
| (Thread y, Address x) -> Thread (Threads.widen y (Threads.join y (Threads.top ())))
593589
| (Mutex, Mutex) -> Mutex
594590
| (JmpBuf x, JmpBuf y) -> JmpBuf (JmpBufs.widen x y)
595591
| (MutexAttr x, MutexAttr y) -> MutexAttr (MutexAttr.widen x y)
@@ -708,7 +704,7 @@ struct
708704
let v = invalidate_value ask voidType (CArrays.get ask n (array_idx_top)) in
709705
Array (CArrays.set ask n (array_idx_top) v)
710706
| t , Blob n -> Blob (Blobs.invalidate_value ask t n)
711-
| _ , Thread _ -> state (* TODO: no top thread ID set! *)
707+
| _ , Thread tid -> Thread (Threads.join (Threads.top ()) tid)
712708
| _ , JmpBuf _ -> state (* TODO: no top jmpbuf *)
713709
| _, Bot -> Bot (* Leave uninitialized value (from malloc) alone in free to avoid trashing everything. TODO: sound? *)
714710
| t , _ -> top_value t

0 commit comments

Comments
 (0)