-
Notifications
You must be signed in to change notification settings - Fork 90
HB-relationship involving thread creations while mutexes are held #1913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
60 commits
Select commit
Hold shift + click to select a range
4f611d5
mustlock history analysis
dabund24 d4189b4
initial version of descendant lockset analysis
dabund24 4d5fee2
first descendant lockset racefree tests
dabund24 2cc4be9
first descendant lockset racing tests
dabund24 470279f
descendant lockset racing tests with multiple thread creations
dabund24 1f883f2
creation lockset query
dabund24 bb16da6
global descendant locksets
dabund24 8f46eb3
regression tests for global descendant locksets
dabund24 61cdb71
descendant lockset tests involving multiple mutexes
dabund24 67a62bd
Merge branch 'master' into descendant-locksets
dabund24 c8cdf89
fix incorrect indentatoin in regression test
dabund24 6c68a6c
add missing return statement to regression test
dabund24 6020267
add missing mutex initializations
dabund24 5bf536d
remove redundant whitespace in creation lockset analysis
dabund24 bd388a2
remove unused tid function parameter in `unlock` and `unknown_unlock`…
dabund24 66ad3f1
modify global domain to use `D` instances as values
dabund24 d4aec37
Merge branch 'master' into descendant-locksets
dabund24 743092a
recursive mutex regression tests for descendant locksets
dabund24 b161fed
Merge branch 'master' into descendant-locksets
dabund24 3461214
use `MapTop` instead of `MapBot` for inner map of descendant lockset …
dabund24 717b52f
some documentation in `descendantLockset` analysis
dabund24 ee18c9a
improve printing of `descendantLockset` analysis
dabund24 9f5b264
documentation for `mustlockHistory` analysis
dabund24 83d6f5a
remove unused dependencies from mustlock history analysis
dabund24 6785efa
Merge branch 'master' into descendant-locksets
dabund24 a71d29e
refactor functions related to thread descendants
dabund24 be913ba
locally abstract type for `happens_before` function in `descendantLoc…
dabund24 624254b
also print mustlock history in `A` of descendant lockset analysis
dabund24 30d7daf
remove side effects analysis for descendant locksets
dabund24 9b40093
skip tests involving global descendant lockset analysis
dabund24 ba0cac3
Merge branch 'master' into descendant-locksets
dabund24 9e8399e
undo removal of descendant lockset analysis
dabund24 6827d4d
undo skipping global descendant lockset regression tests
dabund24 ac2b66f
also use MapBot for global domain of descendant lockset analysis
dabund24 b0e6f4b
align definition of transfer functions of descendant lockset analysis…
dabund24 6dd1f3c
use sticky set intersection in global descendant lockset analysis
dabund24 596cb68
add global descendant lockset regression tests with multiple creates
dabund24 7e4f3d8
threadenter of descendant lockset analysis
dabund24 f3ba129
Merge branch 'master' into descendant-locksets
dabund24 2ab8e7f
Merge remote-tracking branch 'origin/master' into descendant-locksets
dabund24 f855eda
remove redundant quotation marks in descendant lockset test params
dabund24 3d401db
svcomp nondet initializers for descendant lockset tests
dabund24 0f52534
TIDV module
dabund24 b395b79
add dl test sometimes creation without lock
dabund24 e69cfd8
reference inter-threaded lockset bachelor's thesis
dabund24 c6a43d7
remove unnecessary parentheses in descendant lockset analysis
dabund24 e05ae7b
svcomp nondet initializers for creation lockset tests
dabund24 b0adaca
Indentation in descendant locksets analysis
dabund24 dfb2eba
fix inter-threaded lockset bachelor's thesis reference
dabund24 5ec0f12
enable svcomp functions for tests using nondet
dabund24 bc552ed
add missing RACE! annotations for descendant lockset tests
dabund24 31f5f3f
fix comments in global descendant lockset test
dabund24 76c1aa8
improve descendant lockset test case where same thread is created mul…
dabund24 425d0d4
remove unused query for current tid in descendant lockset analysis
dabund24 ec2b4f5
move query for must-lock history in descendant lockset analysis into …
dabund24 6d501eb
add missing line break before new function in thread descendants anal…
dabund24 ab3b3c6
indentation in descendant lockset test
dabund24 81d3ac9
remove redundant pthread declaration in descendant lockset test
dabund24 2cb2bd5
explain representation of bot in creation lockset and descendant lock…
dabund24 92794ee
Merge branch 'master' into descendant-locksets
dabund24 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| (** descendant lockset analysis [descendantLockset] | ||
| analyzes a happened-before relationship related to thread creations with mutexes held. | ||
|
|
||
| Enabling [creationLockset] may improve the precision of this analysis. | ||
|
|
||
| @see Daniel Bund. "Leveraging the Potential of Inter-Threaded Locksets in Abstract Interpretation", B.Sc. thesis at TUM. Available upon request. | ||
| *) | ||
|
|
||
| open Analyses | ||
| module TID = ThreadIdDomain.Thread | ||
| module TIDs = ConcDomain.ThreadSet | ||
| module Lockset = LockDomain.MustLockset | ||
|
|
||
| module Spec = struct | ||
| include IdentityUnitContextsSpec | ||
|
|
||
| (** [{ t_d |-> L }] | ||
|
|
||
| [t_d] was transitively created with all members of [L] held. | ||
| Additionally, no member of [L] could have been unlocked after the creation of [t_d] | ||
| If [L] is bot, this does not represent "all mutexes". Instead, it indicates no (transitive) creation of [t_d] has happened | ||
| *) | ||
| module D = MapDomain.MapBot (TID) (Lockset) | ||
|
|
||
| (** [{ t_0 |-> { t_d |-> L } }] | ||
|
|
||
| [{ t_d |-> L }] is the descendant lockset valid for the [V] value, | ||
|
michael-schwarz marked this conversation as resolved.
|
||
| because [t_d] was created in [t_0] with the lockset being a superset of L. | ||
| *) | ||
| module G = MapDomain.MapBot (TID) (D) | ||
|
|
||
| module V = TIDV | ||
|
|
||
| let name () = "descendantLockset" | ||
| let startstate _ = D.empty () | ||
| let exitstate _ = D.empty () | ||
|
|
||
| let threadenter man ~multiple lval f args = [ D.empty () ] | ||
|
|
||
| let threadspawn_contribute_globals man tid must_ancestor_descendants = | ||
| let descendant_lockset = man.local in | ||
|
|
||
| (* intersect locksets, but return bot if any arg is bot *) | ||
| let lockset_inter_sticky_bot = function | ||
| | `Top, _ | _, `Top -> Lockset.bot () | ||
| | ls1, ls2 -> Lockset.inter ls1 ls2 | ||
|
michael-schwarz marked this conversation as resolved.
|
||
| in | ||
|
|
||
| let contribute_for_descendant t_d = | ||
| let creation_lockset = man.ask @@ Queries.CreationLockset t_d in | ||
| let to_contribute = | ||
| D.fold | ||
| (fun t_l l_dl acc -> | ||
| let l_cl = Queries.CL.find tid creation_lockset in | ||
| let l_inter = lockset_inter_sticky_bot (l_cl, l_dl) in | ||
| D.add t_l l_inter acc) | ||
| descendant_lockset | ||
| (D.empty ()) | ||
| in | ||
| man.sideg t_d (G.singleton tid to_contribute) | ||
| in | ||
| TIDs.iter contribute_for_descendant must_ancestor_descendants | ||
|
|
||
| let threadspawn_compute_local_contribution man tid must_ancestor_descendants = | ||
| let lockset = man.ask Queries.MustLockset in | ||
| TIDs.fold | ||
| (fun t_d -> D.join (D.singleton t_d lockset)) | ||
| must_ancestor_descendants | ||
| man.local | ||
|
|
||
| let threadspawn man ~multiple lval f args fman = | ||
| let tid_lifted = man.ask Queries.CurrentThreadId in | ||
| let child_tid_lifted = fman.ask Queries.CurrentThreadId in | ||
| match tid_lifted, child_tid_lifted with | ||
| | `Lifted tid, `Lifted child_tid when TID.must_be_ancestor tid child_tid -> | ||
|
michael-schwarz marked this conversation as resolved.
|
||
| let must_ancestor_descendants = | ||
| ThreadDescendants.must_ancestor_descendants_closure fman child_tid | ||
| in | ||
| threadspawn_contribute_globals man tid must_ancestor_descendants; | ||
| threadspawn_compute_local_contribution man tid must_ancestor_descendants | ||
| | _ -> man.local | ||
|
|
||
| let unlock man lock = | ||
| D.map (Lockset.remove lock) man.local | ||
|
|
||
| let unknown_unlock man = | ||
| D.map (fun _ -> Lockset.empty ()) man.local | ||
|
|
||
| let event man e _ = | ||
| match e with | ||
| | Events.Unlock addr -> | ||
| let lock_opt = LockDomain.MustLock.of_addr addr in | ||
| (match lock_opt with | ||
| | Some lock -> unlock man lock | ||
| | None -> unknown_unlock man) | ||
| | _ -> man.local | ||
|
|
||
| module A = struct | ||
| module DlLhProd = Printable.Prod3 (D) (G) (Queries.LH) | ||
|
|
||
| (** ego tid * (local descendant lockset * global descendant lockset * lock history) *) | ||
| include Printable.Prod (TID) (DlLhProd) | ||
|
|
||
| (** checks if program point 1 must happen before program point 2 | ||
| @param (t1,dl1) thread id and descendant lockset of program point 1 | ||
| @param (t2,lh2) thread id and mustlock history of program point 2 | ||
| @param M module of [dl1] | ||
| *) | ||
| let happens_before (t1, dl1) (t2, lh2) = | ||
| let locks_held_creating_t2 = D.find t2 dl1 in | ||
| if Lockset.is_bot locks_held_creating_t2 then | ||
| false | ||
| else | ||
| let relevant_lh2_threads = | ||
| Lockset.fold | ||
| (fun lock -> TIDs.union (Queries.LH.find lock lh2)) | ||
| locks_held_creating_t2 | ||
| (TIDs.empty ()) | ||
| in | ||
| TIDs.exists | ||
| (fun t_lh -> | ||
| TID.must_be_ancestor t1 t_lh | ||
| && (TID.equal t_lh t2 || TID.must_be_ancestor t_lh t2)) | ||
| relevant_lh2_threads | ||
|
|
||
| (** checks if the entire execution of a thread must happen before a program point | ||
| @param dlg1 glabal descendant lockset of the thread | ||
| @param (t2,lh2) thread id and mustlock history of the program point | ||
| *) | ||
| let happens_before_global dlg1 (t2, lh2) = | ||
| G.exists (fun t dl_map -> happens_before (t, dl_map) (t2, lh2)) dlg1 | ||
|
|
||
| let may_race (t1, (dl1, dlg1, lh1)) (t2, (dl2, dlg2, lh2)) = | ||
| not | ||
| (happens_before (t1, dl1) (t2, lh2) | ||
| || happens_before (t2, dl2) (t1, lh1) | ||
| || happens_before_global dlg1 (t2, lh2) | ||
| || happens_before_global dlg2 (t1, lh1)) | ||
|
|
||
| (* ego tid is already printed elsewhere *) | ||
| let pretty () (_, dl_dlg_lh) = DlLhProd.pretty () dl_dlg_lh | ||
| let show (_, dl_dlg_lh) = DlLhProd.show dl_dlg_lh | ||
| let to_yojson (_, dl_dlg_lh) = DlLhProd.to_yojson dl_dlg_lh | ||
| let printXml f (_, dl_dlg_lh) = DlLhProd.printXml f dl_dlg_lh | ||
|
|
||
| let should_print (_, (dl, dlg, lh)) = | ||
| let ls_not_empty _ ls = not @@ Lockset.is_empty ls in | ||
| D.exists ls_not_empty dl | ||
| || G.exists (fun _ -> D.exists ls_not_empty) dlg | ||
| || Queries.LH.exists (fun l tids -> not @@ TIDs.is_empty tids) lh | ||
| end | ||
|
|
||
| let access man _ = | ||
| let tid_lifted = man.ask Queries.CurrentThreadId in | ||
| match tid_lifted with | ||
| | `Lifted tid -> | ||
| let lh = man.ask Queries.MustlockHistory in | ||
| tid, (man.local, man.global tid, lh) | ||
| | _ -> ThreadIdDomain.UnknownThread, (D.empty (), G.empty (), Queries.LH.empty ()) | ||
| end | ||
|
|
||
| let _ = | ||
| MCP.register_analysis | ||
| ~dep:[ "threadid"; "mutex"; "threadJoins"; "threadDescendants"; "mustlockHistory" ] | ||
|
michael-schwarz marked this conversation as resolved.
|
||
| (module Spec : MCPSpec) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| (** must-lock history analysis [mustlockHistory] | ||
| collects for locks, in which threads a lock operation must have happened | ||
| before reaching the current program point. | ||
|
|
||
| @see https://github.com/goblint/analyzer/pull/1923 | ||
| *) | ||
|
|
||
| open Analyses | ||
| module TIDs = SetDomain.Reverse (ConcDomain.ThreadSet) | ||
| module Lock = LockDomain.MustLock | ||
|
|
||
| module Spec = struct | ||
|
dabund24 marked this conversation as resolved.
|
||
| include IdentityUnitContextsSpec | ||
|
|
||
| (** [{ l |-> T }] | ||
|
|
||
| [l] must have been in all members of [T]. | ||
| *) | ||
| module D = Queries.LH | ||
|
|
||
| let name () = "mustlockHistory" | ||
| let startstate _ = D.empty () | ||
| let exitstate _ = D.empty () | ||
|
|
||
| let lock man tid lock = | ||
| let old_threadset = D.find lock man.local in | ||
| let new_threadset = TIDs.add tid old_threadset in | ||
| D.add lock new_threadset man.local | ||
|
|
||
| let event man e _ = | ||
| match e with | ||
| (* we only handle exclusive locks here *) | ||
| | Events.Lock (addr, true) -> | ||
| let tid_lifted = man.ask Queries.CurrentThreadId in | ||
| let lock_opt = Lock.of_addr addr in | ||
| (match tid_lifted, lock_opt with | ||
| | `Lifted tid, Some l -> lock man tid l | ||
| | _ -> man.local) | ||
| | _ -> man.local | ||
|
|
||
| let query man (type a) (x : a Queries.t) : a Queries.result = | ||
| match x with | ||
| | Queries.MustlockHistory -> (man.local : D.t) | ||
| | _ -> Queries.Result.top x | ||
| end | ||
|
|
||
| let _ = MCP.register_analysis ~dep:[ "threadid" ] (module Spec : MCPSpec) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.