123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openCil_typesopenMt_typesopenMt_threadopenMt_cfg_typesopenMt_mutexes_types(* -------------------------------------------------------------------------- *)(* --- Checking that concurrent variables accesses are properly protected --- *)(* -------------------------------------------------------------------------- *)letmutexes_protecting_zones'accesses=letaux(z,set)=SetNodeIdAccess.fold(fun(rw,node,_id)acc->letmutexes=node.cfgn_context.locked_mutexesinletmut=matchrwwith|Read->{mutexes_for_write=Unaccessed;mutexes_for_read=Mutexesmutexes}|Write_->{mutexes_for_read=Unaccessed;mutexes_for_write=Mutexesmutexes}|ReadAloc_->{mutexes_for_read=Mutexesmutexes;mutexes_for_write=Unaccessed}|WriteAloc_->{mutexes_for_read=Unaccessed;mutexes_for_write=Mutexesmutexes}inMutexesByZone.add_binding~exact:falseacczmut)setMutexesByZone.emptyinletr1=List.mapauxaccessesinletz=List.fold_left(funrr'->MutexesByZone.joinrr')MutexesByZone.emptyr1inz(* Pretty a value of type [Mt_shared_vars.Precise.list_accesses]
with the mutex information at each node concatenated to the output *)letpretty_with_mutexes=Mt_shared_vars.Precise.pretty_concurrent_accesses~f:(funfmt(_,node,_)->letmutexes=node.cfgn_context.locked_mutexesinifMutexPresence.is_emptymutexesthenFormat.fprintffmt",@ unprotected"elseFormat.fprintffmt",@ @[<hov>protected by %a@]"MutexPresence.prettymutexes;ifMt_options.PrintCallstacks.get()thenFormat.fprintffmt",@ // %a"Callstack.prettynode.cfgn_stack)();;;typeprotection=Unprotected|Priority|ProtectedofMutex.Set.tletpretty_protectionfmt=function|Unprotected->Format.fprintffmt"unprotected"|Priority->Format.fprintffmt"protected by priorities"|Protectedset->Format.fprintffmt"@[<hov 2>protected by %a@]"(Pretty_utils.pp_iterMutex.Set.iterMutex.pretty)setletpretty_protection_per_threadfmt(th_read,th_write,protection)=Format.fprintffmt"@[<hov 2>Read by %a,@ Write by %a:@ %a@]"Thread.prettyth_readThread.prettyth_writepretty_protectionprotectiontypezone_protection=(Locations.Zone.t*(Thread.t*Thread.t*protection)list)listletpretty_zone_protectionfmt(z,l)=Format.fprintffmt"@[<hv 2>@[%a@]:@ %a@]"Locations.Zone.prettyz(Pretty_utils.pp_list~pre:""~suf:""pretty_protection_per_thread)lletcheck_protectionanalysis(l:Mt_shared_vars.Precise.list_accesses):zone_protection=letaux(z,s)=letm_read=refThread.Map.emptyinletm_write=refThread.Map.emptyin(* YYY: we disregard information about accesses that may not be possibly
simultaneous *)letaddthnodemap=letmutexes'=MutexPresence.only_presentnode.cfgn_context.locked_mutexesintryletmutexes=Thread.Map.findthmapinletinter=Mutex.Set.intermutexesmutexes'inThread.Map.addthintermapwithNot_found->Thread.Map.addthmutexes'mapinletaux_nodes(op,n,th)=matchopwith|Read->m_read:=addthn!m_read|Write_->m_write:=addthn!m_write|ReadAloc_->m_read:=addthn!m_read|WriteAloc_->m_write:=addthn!m_writeinSetNodeIdAccess.iteraux_nodess;letclassify_accessth_readreadth_writewriteclassified=ifnot(Thread.equalth_readth_write)thenbeginletth_read_state=Mt_thread.thread_stateanalysisth_readinletth_write_state=Mt_thread.thread_stateanalysisth_writeinletprotection=matchth_read_state.th_priority,th_write_state.th_prioritywith|PPriorityp1,PPriorityp2whenp1>p2->(* Protection by mutexes not needed, th_read cannot be preempted *)Priority|_->letboth_mutexes=Mutex.Set.interreadwriteinifMutex.Set.is_emptyboth_mutexesthenUnprotectedelseProtectedboth_mutexesin(th_read,th_write,protection)::classifiedendelseclassifiedinletprotections=Thread.Map.fold(funth_readreadacc->Thread.Map.fold(funth_writewriteacc->classify_accessth_readreadth_writewriteacc)!m_writeacc)!m_read[]in(z,protections)inList.mapauxlletpretty_protectionsfmtl=Pretty_utils.pp_list~pre:"@[<v>"~suf:"@]"~sep:"@ "pretty_zone_protectionfmtlletill_protected(accesses:Mt_shared_vars.Precise.list_accesses)(protections:zone_protection)=letres=Cil_datatype.Stmt.Hashtbl.create16inletaux(z,nodes)(z',protections)=assert(z==z');letaux(th_read,_th_write,protect)=ifprotect=Unprotectedthenletaux(op,node,th)=ifThread.equalthth_read&&op=Readthenbeginletstmts=CfgNode.node_stmtnodeinletauxstmt=letprev=tryCil_datatype.Stmt.Hashtbl.findresstmtwithNot_found->Locations.Zone.bottominletz=Locations.Zone.joinprevzinCil_datatype.Stmt.Hashtbl.replaceresstmtzinList.iterauxstmtsendinSetNodeIdAccess.iterauxnodesinList.iterauxprotectionsinList.iter2auxaccessesprotections;resletneed_syncstmtsh=letauxstmtzacc=(* YYY: detection should be improved to handle unspecified sequences. *)matchstmt.predswith|[stmt]whenMt_cil.is_call_to_syncstmt->acc|_->(stmt,z)::accinCil_datatype.Stmt.Hashtbl.foldauxstmtsh[]