12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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). *)(* *)(**************************************************************************)openSelf(* Dependencies to kernel options *)letkernel_parameters_correctness=[Kernel.MainFunction.parameter;Kernel.LibEntry.parameter;Kernel.AbsoluteValidRange.parameter;Kernel.InitializedPaddingLocals.parameter;Kernel.SafeArrays.parameter;Kernel.UnspecifiedAccess.parameter;Kernel.SignedOverflow.parameter;Kernel.UnsignedOverflow.parameter;Kernel.LeftShiftNegative.parameter;Kernel.RightShiftNegative.parameter;Kernel.SignedDowncast.parameter;Kernel.UnsignedDowncast.parameter;Kernel.PointerDowncast.parameter;Kernel.SpecialFloat.parameter;Kernel.InvalidBool.parameter;Kernel.InvalidPointer.parameter;]letparameters_correctness=refTyped_parameter.Set.emptyletparameters_tuning=refTyped_parameter.Set.emptyletadd_depp=letstate=State.getp.Typed_parameter.nameinState_builder.Proxy.extend[state]Self.proxyletadd_correctness_depp=ifTyped_parameter.Set.memp!parameters_correctnessthenKernel.abort"adding correctness parameter %a twice"Typed_parameter.prettyp;add_depp;parameters_correctness:=Typed_parameter.Set.addp!parameters_correctnessletadd_precision_depp=ifTyped_parameter.Set.memp!parameters_tuningthenKernel.abort"adding tuning parameter %a twice"Typed_parameter.prettyp;add_depp;parameters_tuning:=Typed_parameter.Set.addp!parameters_tuninglet()=List.iteradd_correctness_depkernel_parameters_correctnessmoduleForceValues=WithOutput(structletoption_name="-eva"lethelp="Compute values"letoutput_by_default=trueend)let()=ForceValues.add_aliases~deprecated:true["-val"]letdomains=add_group"Abstract Domains"letprecision_tuning=add_group"Precision vs. time"letinitial_context=add_group"Initial Context"letperformance=add_group"Results memoization vs. time"letinterpreter=add_group"Deterministic programs"letalarms=add_group"Propagation and alarms "letmalloc=add_group"Dynamic allocation"(* -------------------------------------------------------------------------- *)(* --- Eva domains --- *)(* -------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupdomainsmoduleDomains=Filled_string_set(structletoption_name="-eva-domains"letarg_name="d1,...,dn"lethelp="Enable a list of analysis domains."letdefault=Datatype.String.Set.of_list["cvalue"]end)let()=add_precision_depDomains.parameterletremove_domainname=Domains.set(Datatype.String.Set.filter((!=)name)(Domains.get()))(* For backward compatibility, creates an invisible option for the domain [name]
that sets up -eva-domains with [name]. To be removed one day. *)letcreate_domain_optionname=letoption_name=matchnamewith|"apron-box"->"-eva-apron-box"|"apron-octagon"->"-eva-apron-oct"|"apron-polka-loose"->"-eva-polka-loose"|"apron-polka-strict"->"-eva-polka-strict"|"apron-polka-equality"->"-eva-polka-equalities"|_->"-eva-"^name^"-domain"inletmoduleInput=structletoption_name=option_namelethelp="Use the "^name^" domain of eva."letdefault=name="cvalue"endinParameter_customize.set_groupdomains;Parameter_customize.is_invisible();letmoduleParameter=Bool(Input)inParameter.add_set_hook(fun_old_new->warning"Option %s is deprecated. Use -eva-domains %s%s instead."option_name(if_newthen""else"-")name;if_newthenDomains.addnameelseremove_domainname)let()=Parameter_customize.set_groupperformancemoduleNoResultsDomains=String_set(structletoption_name="-eva-no-results-domain"letarg_name="domains"lethelp="Do not record the states of some domains during the analysis."end)let()=add_depNoResultsDomains.parameter(* List (name, descr) of available domains. *)letdomains_ref=ref[](* Help message for the -eva-domains option, with the list of currently
available domains. *)letdomains_help()=letpp_str_list=Pretty_utils.pp_list~sep:", "Format.pp_print_stringinFormat.asprintf"Enable a list of analysis domains. Available domains are: %a. \
Use -eva-domains help to print a short description of each domain."pp_str_list(List.rev_mapfst!domains_ref)(* Prints the list of available domains with their description. *)letdomains_list()=letpp_domfmt(name,descr)=Format.fprintffmt"%-20s @[%t@]"name(funfmt->Format.pp_print_textfmtdescr)infeedback~level:0"List of available domains:@,%a"(Pretty_utils.pp_list~pre:"@[<v>"~sep:"@,"~suf:"@]"pp_dom)(List.rev!domains_ref);raiseCmdline.Exit(* Registers a new domain. Updates the help message of -eva-domains. *)letregister_domain~name~descr=create_domain_optionname;domains_ref:=(name,descr)::!domains_ref;Cmdline.replace_option_helpDomains.option_name~plugin:"eva"~group:domains(domains_help())(* Checks that a domain has been registered. *)letcheck_domainoption_namedomain=ifdomain="help"||domain="list"thendomains_list()elseifnot(List.exists(fun(name,_)->name=domain)!domains_ref)thenletpp_str_list=Pretty_utils.pp_list~sep:",@ "Format.pp_print_stringinabort"invalid domain %S for option %s.@.Possible domains are: %a"domainoption_namepp_str_list(List.rev_mapfst!domains_ref)let()=lethookoption_name=fun_olddomains->Datatype.String.Set.iter(check_domainoption_name)domainsinDomains.add_set_hook(hookDomains.name);NoResultsDomains.add_set_hook(hookNoResultsDomains.name)let()=Parameter_customize.set_groupdomainsmoduleDomainsFunction=Make_multiple_map(structincludeDatatype.Stringletof_stringstr=check_domain"-eva-domains-function"str;strletof_singleton_string=no_element_of_stringletto_stringstr=strend)(structincludeDomain_mode.Function_Modeletof_string~key~prevstr=tryof_string~key~prevstrwithInvalid_argumentmsg->raise(Cannot_buildmsg)end)(structletoption_name="-eva-domains-function"lethelp="Enable a domain only for the given functions. \
<d:f+> enables the domain [d] from function [f] \
(the domain is enabled in all functions called from [f]). \
<d:f-> disables the domain [d] from function [f]."letarg_name="d:f"letdefault=Datatype.String.Map.emptyletdependencies=[]end)let()=add_precision_depDomainsFunction.parameterletenabled_domains()=letdomains=Domains.get()inletdomains_by_fct=DomainsFunction.get()inList.filter(fun(name,_)->Datatype.String.Set.memnamedomains||Datatype.String.Map.memnamedomains_by_fct)!domains_reflet()=Parameter_customize.set_groupdomainsmoduleEqualityCall=String(structletoption_name="-eva-equality-through-calls"lethelp="Propagate equalities through function calls (from the caller \
to the called function): none, only equalities between formal \
parameters and concrete arguments, or all. "letdefault="formals"letarg_name="none|formals|all"end)let()=EqualityCall.set_possible_values["none";"formals";"all"]let()=add_precision_depEqualityCall.parameterlet()=Parameter_customize.set_groupdomainsmoduleEqualityCallFunction=Kernel_function_map(structincludeDatatype.Stringtypekey=Cil_types.kernel_functionletof_string~key:_~prev:_=function|None|Some("none"|"formals"|"all")asx->x|_->raise(Cannot_build"must be 'none', 'formals' or 'all'.")letto_string~key:_s=send)(structletoption_name="-eva-equality-through-calls-function"lethelp="Propagate equalities through calls to specific functions. \
Overrides -eva-equality-call."letdefault=Kernel_function.Map.emptyletarg_name="f:none|formals|all"end)let()=add_precision_depEqualityCallFunction.parameterlet()=Parameter_customize.set_groupdomainsmoduleOctagonCall=Bool(structletoption_name="-eva-octagon-through-calls"lethelp="Propagate relations inferred by the octagon domain \
through function calls. Disabled by default: \
the octagon analysis is intra-procedural, starting \
each function with an empty octagon state, \
and losing the octagons inferred at the end. \
The interprocedural analysis is more precise but slower."letdefault=falseend)let()=add_precision_depOctagonCall.parameterlet()=Parameter_customize.set_groupdomainsmoduleNumerors_Real_Size=Int(structletdefault=128letoption_name="-eva-numerors-real-size"letarg_name="n"lethelp="Set <n> as the significand size of the MPFR representation \
of reals used by the numerors domain (defaults to 128)"end)let()=Numerors_Real_Size.set_range~min:1~max:max_intlet()=add_precision_depNumerors_Real_Size.parameterlet()=Parameter_customize.set_groupdomainsmoduleNumerors_Mode=String(structletoption_name="-eva-numerors-interaction"lethelp="Define how the numerors domain infers the absolute and the \
relative errors:\n\
- relative: the relative is deduced from the absolute;\n\
- absolute: the absolute is deduced from the relative;\n\
- none: absolute and relative are computed separately;\n\
- both: reduced product between absolute and relative."letdefault="both"letarg_name="relative|absolute|none|both"end)let()=Numerors_Mode.set_possible_values["relative";"absolute";"none";"both"]let()=add_precision_depNumerors_Mode.parameterlet()=Parameter_customize.set_groupdomainsmoduleTracesUnrollLoop=Bool(structletoption_name="-eva-traces-unroll-loop"lethelp="Specify if the traces domain should unroll the loops."letdefault=trueend)let()=add_precision_depTracesUnrollLoop.parameterlet()=Parameter_customize.set_groupdomainsmoduleTracesUnifyLoop=Bool(structletoption_name="-eva-traces-unify-loop"lethelp="Specify if all the instances of a loop should try \
to share theirs traces."letdefault=falseend)let()=add_precision_depTracesUnifyLoop.parameterlet()=Parameter_customize.set_groupdomainsmoduleTracesDot=Filepath(structletoption_name="-eva-traces-dot"letarg_name="FILENAME"letfile_kind="DOT"letexistence=Fc_Filepath.Indifferentlethelp="Output to the given filename the Cfg in dot format."end)let()=Parameter_customize.set_groupdomainsmoduleTracesProject=Bool(structletoption_name="-eva-traces-project"lethelp="Try to convert the Cfg into a program in a new project."letdefault=falseend)let()=Parameter_customize.set_groupdomainsmoduleMultidimSegmentLimit=Int(structletoption_name="-eva-multidim-segment-limit"letarg_name="N"lethelp="Limit the number of segments in the abstraction of arrays."letdefault=8end)let()=MultidimSegmentLimit.set_range~min:3~max:max_intlet()=add_precision_depMultidimSegmentLimit.parameterlet()=Parameter_customize.set_groupdomainsmoduleMultidimDisjunctiveInvariants=False(structletoption_name="-eva-multidim-disjunctive-invariants"lethelp="Try to infer structures disjunctive invariants."end)let()=add_precision_depMultidimDisjunctiveInvariants.parameterlet()=Parameter_customize.set_groupdomainslet()=Parameter_customize.is_invisible()moduleMultidimFastImprecise=False(structletoption_name="-eva-multidim-fast-imprecise"lethelp="Makes the multidim domain faster but less precise: \
the domain can lose more information when joining states."end)let()=add_precision_depMultidimFastImprecise.parameter(* -------------------------------------------------------------------------- *)(* --- Performance options --- *)(* -------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupperformancemoduleNoResultsFunctions=Fundec_set(structletoption_name="-eva-no-results-function"letarg_name="f"lethelp="Do not record the values obtained for the statements of \
function f"end)let()=add_depNoResultsFunctions.parameterlet()=Parameter_customize.set_groupperformancemoduleResultsAll=True(structletoption_name="-eva-results"lethelp="Record values for each of the statements of the program."end)let()=add_depResultsAll.parameterlet()=Parameter_customize.set_groupperformancemoduleJoinResults=Bool(structletoption_name="-eva-join-results"lethelp="Precompute consolidated states once Eva is computed"letdefault=trueend)(* ------------------------------------------------------------------------- *)(* --- Non-standard alarms --- *)(* ------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupalarmsmoduleUndefinedPointerComparisonPropagateAll=False(structletoption_name="-eva-undefined-pointer-comparison-propagate-all"lethelp="If the target program appears to contain undefined pointer \
comparisons, propagate both outcomes {0; 1} in addition to \
the emission of an alarm"end)let()=add_correctness_depUndefinedPointerComparisonPropagateAll.parameterlet()=Parameter_customize.set_groupalarmsmoduleWarnPointerComparison=String(structletoption_name="-eva-warn-undefined-pointer-comparison"lethelp="Warn on all pointer comparisons, on comparisons where \
the arguments have pointer type (default), or never warn"letdefault="pointer"letarg_name="all|pointer|none"end)let()=WarnPointerComparison.set_possible_values["all";"pointer";"none"]let()=add_correctness_depWarnPointerComparison.parameterlet()=Parameter_customize.set_groupalarmsmoduleWarnSignedConvertedDowncast=False(structletoption_name="-eva-warn-signed-converted-downcast"lethelp="Signed downcasts are decomposed into two operations: \
a conversion to the signed type of the original width, \
then a downcast. Warn when the downcast may exceed the \
destination range."end)let()=add_correctness_depWarnSignedConvertedDowncast.parameterlet()=Parameter_customize.set_groupalarmsmoduleWarnPointerSubstraction=True(structletoption_name="-eva-warn-pointer-subtraction"lethelp="Warn when subtracting two pointers that may not be in the same \
allocated block, and return the pointwise difference between the \
offsets. When unset, do not warn but generate imprecise offsets."end)let()=add_correctness_depWarnPointerSubstraction.parameterlet()=Parameter_customize.set_groupalarmslet()=Parameter_customize.is_invisible()moduleIgnoreRecursiveCalls=False(structletoption_name="-eva-ignore-recursive-calls"lethelp="Deprecated."end)let()=IgnoreRecursiveCalls.add_set_hook(fun_old_new->warning"@[Option -eva-ignore-recursive-calls has no effect.@ Recursive calls \
can be unrolled@ through option -eva-unroll-recursive-calls,@ or their \
specification is used@ to interpret them.@]")let()=Parameter_customize.set_groupalarmslet()=Parameter_customize.argument_may_be_fundecl();moduleWarnCopyIndeterminate=Kernel_function_set(structletoption_name="-eva-warn-copy-indeterminate"letarg_name="f | @all"lethelp="Warn when a statement copies a value that may be indeterminate \
(uninitialized, containing an escaping address, or infinite/NaN \
floating-point value). \
Set by default; can be deactivated for function 'f' by '=-f', \
or for all functions by '=-@all'."end)let()=add_correctness_depWarnCopyIndeterminate.parameterlet()=WarnCopyIndeterminate.Category.(set_default(all()))let()=Parameter_customize.set_groupalarmsmoduleReduceOnLogicAlarms=False(structletoption_name="-eva-reduce-on-logic-alarms"lethelp="Force reductions by a predicate to ignore logic alarms \
emitted while the predicate is evaluated (experimental)"end)let()=add_correctness_depReduceOnLogicAlarms.parameterlet()=Parameter_customize.set_groupalarmsmoduleInitializedLocals=False(structletoption_name="-eva-initialized-locals"lethelp="Local variables enter in scope fully initialized. \
Only useful for the analysis of programs buggy w.r.t. \
initialization."end)let()=add_correctness_depInitializedLocals.parameter(* ------------------------------------------------------------------------- *)(* --- Initial context --- *)(* ------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupinitial_contextmoduleAutomaticContextMaxDepth=Int(structletoption_name="-eva-context-depth"letdefault=2letarg_name="n"lethelp="Use <n> as the depth of the default context for Eva. \
(defaults to 2)"end)let()=AutomaticContextMaxDepth.set_range~min:0~max:max_intlet()=add_correctness_depAutomaticContextMaxDepth.parameterlet()=Parameter_customize.set_groupinitial_contextmoduleAutomaticContextMaxWidth=Int(structletoption_name="-eva-context-width"letdefault=2letarg_name="n"lethelp="Use <n> as the width of the default context for Eva. \
(defaults to 2)"end)let()=AutomaticContextMaxWidth.set_range~min:1~max:max_intlet()=add_correctness_depAutomaticContextMaxWidth.parameterlet()=Parameter_customize.set_groupinitial_contextmoduleAllocatedContextValid=False(structletoption_name="-eva-context-valid-pointers"lethelp="Only allocate valid pointers until context-depth, \
and then use NULL (defaults to false)"end)let()=add_correctness_depAllocatedContextValid.parameterlet()=Parameter_customize.set_groupinitial_contextmoduleInitializationPaddingGlobals=String(structletdefault="yes"letoption_name="-eva-initialization-padding-globals"letarg_name="yes|no|maybe"lethelp="Specify how padding bits are initialized inside global \
variables. Possible values are <yes> (padding is fully \
initialized), <no> (padding is completely uninitialized), or \
<maybe> (padding may be uninitialized). Default is <yes>."end)let()=InitializationPaddingGlobals.set_possible_values["yes";"no";"maybe"]let()=add_correctness_depInitializationPaddingGlobals.parameter(* ------------------------------------------------------------------------- *)(* --- Tuning --- *)(* ------------------------------------------------------------------------- *)(* --- Iteration strategy --- *)let()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.is_invisible()moduleDescendingIteration=String(structletdefault="no"letoption_name="-eva-descending-iteration"letarg_name="no|exits|full"lethelp="Experimental. After hitting a postfix point, try to improve \
the precision with either a <full> iteration or an iteration \
from loop head to exit paths (<exits>) or do not try anything \
(<no>). Default is <no>."end)let()=DescendingIteration.set_possible_values["no";"exits";"full"]let()=add_precision_depDescendingIteration.parameterlet()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.is_invisible()moduleHierarchicalConvergence=False(structletoption_name="-eva-hierarchical-convergence"lethelp="Experimental and unsound. Separate the convergence process \
of each level of nested loops. This implies that the \
convergence of inner loops will be completely recomputed when \
doing another iteration of the outer loops."end)let()=add_precision_depHierarchicalConvergence.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleWideningDelay=Int(structletdefault=3letoption_name="-eva-widening-delay"letarg_name="n"lethelp="Do not widen before the <n>-th iteration (defaults to 3)"end)let()=WideningDelay.set_range~min:1~max:max_intlet()=add_precision_depWideningDelay.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleWideningPeriod=Int(structletdefault=2letoption_name="-eva-widening-period"letarg_name="n"lethelp="After the first widening, widen each <n> iterations (defaults to 2)"end)let()=WideningPeriod.set_range~min:1~max:max_intlet()=add_precision_depWideningPeriod.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleRecursiveUnroll=Int(structletdefault=0letoption_name="-eva-unroll-recursive-calls"letarg_name="n"lethelp="Unroll <n> recursive calls before using the specification of \
the recursive function to interpret the calls."end)let()=RecursiveUnroll.set_range~min:0~max:max_intlet()=add_precision_depRecursiveUnroll.parameter(* --- Partitioning --- *)let()=Parameter_customize.set_groupprecision_tuningmoduleSemanticUnrollingLevel=Zero(structletoption_name="-eva-slevel"letarg_name="n"lethelp="Superpose up to <n> states when unrolling control flow. \
The larger n, the more precise and expensive the analysis \
(defaults to 0)"end)let()=SemanticUnrollingLevel.set_range~min:0~max:max_intlet()=add_precision_depSemanticUnrollingLevel.parameterlet()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.argument_may_be_fundecl()moduleSlevelFunction=Kernel_function_map(structincludeDatatype.Inttypekey=Cil_types.kernel_functionletof_string~key:_~prev:_s=Option.map(funs->tryint_of_stringswithFailure_->raise(Cannot_build("'"^s^"' is not an integer")))sletto_string~key:_=Option.mapstring_of_intend)(structletoption_name="-eva-slevel-function"letarg_name="f:n"lethelp="Override slevel with <n> when analyzing <f>"letdefault=Kernel_function.Map.emptyend)let()=add_precision_depSlevelFunction.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleSlevelMergeAfterLoop=Kernel_function_set(structletoption_name="-eva-slevel-merge-after-loop"letarg_name="f | @all"lethelp="When set, the different execution paths that originate from the body \
of a loop are merged before entering the next execution."end)let()=add_precision_depSlevelMergeAfterLoop.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleMinLoopUnroll=Int(structletoption_name="-eva-min-loop-unroll"letarg_name="n"letdefault=0lethelp="Unroll <n> loop iterations for each loop, regardless of the slevel \
settings and the number of states already propagated. \
Can be overwritten on a case-by-case basis by loop unroll annotations."end)let()=add_precision_depMinLoopUnroll.parameterlet()=MinLoopUnroll.set_range~min:0~max:max_intlet()=Parameter_customize.set_groupprecision_tuningmoduleAutoLoopUnroll=Int(structletoption_name="-eva-auto-loop-unroll"letarg_name="n"letdefault=0lethelp="Limit of the automatic loop unrolling: all loops whose \
number of iterations can be easily bounded by <n> \
are completely unrolled."end)let()=add_precision_depAutoLoopUnroll.parameterlet()=AutoLoopUnroll.set_range~min:0~max:max_intlet()=Parameter_customize.set_groupprecision_tuningmoduleDefaultLoopUnroll=Int(structletoption_name="-eva-default-loop-unroll"letarg_name="n"letdefault=100lethelp="Define the default limit for loop unroll annotations that do \
not explicitly provide a limit."end)let()=add_precision_depDefaultLoopUnroll.parameterlet()=DefaultLoopUnroll.set_range~min:0~max:max_intlet()=Parameter_customize.set_groupprecision_tuningmoduleHistoryPartitioning=Int(structletoption_name="-eva-partition-history"letarg_name="n"letdefault=0lethelp="Keep states distinct as long as the <n> last branching in their \
traces are also distinct. (A value of 0 deactivates this feature)"end)let()=add_precision_depHistoryPartitioning.parameterlet()=HistoryPartitioning.set_range~min:0~max:max_intlet()=Parameter_customize.set_groupprecision_tuningmoduleValuePartitioning=String_set(structletoption_name="-eva-partition-value"lethelp="Partition the space of reachable states according to the \
possible values of the global(s) variable(s) V."letarg_name="V"end)let()=add_precision_depValuePartitioning.parameterletuse_global_value_partitioningvi=ValuePartitioning.addvi.Cil_types.vnamelet()=Parameter_customize.set_groupprecision_tuningmoduleSplitLimit=Int(structletoption_name="-eva-split-limit"letarg_name="N"letdefault=100lethelp="Prevent split annotations or -eva-partition-value from \
enumerating more than N cases"end)let()=add_precision_depSplitLimit.parameterlet()=SplitLimit.set_range~min:0~max:max_intlet()=Parameter_customize.set_groupprecision_tuningmoduleInterproceduralSplits=False(structletoption_name="-eva-interprocedural-splits"lethelp="Keep partitioning splits through function returns"end)let()=add_precision_depInterproceduralSplits.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleInterproceduralHistory=False(structletoption_name="-eva-interprocedural-history"lethelp="Keep partitioning history through function returns"end)let()=add_precision_depInterproceduralHistory.parameterlet()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.argument_may_be_fundecl()moduleSplitReturnFunction=Kernel_function_map(struct(* this type is ad-hoc: cannot use Kernel_function_multiple_map here *)includeSplit_strategytypekey=Cil_types.kernel_functionletof_string~key:_~prev:_s=tryOption.mapSplit_strategy.of_stringswithSplit_strategy.ParseFailures->raise(Cannot_build("unknown split strategy "^s))letto_string~key:_v=Option.mapSplit_strategy.to_stringvend)(structletoption_name="-eva-split-return-function"letarg_name="f:n"lethelp="Split return states of function <f> according to \
\\result == n and \\result != n"letdefault=Kernel_function.Map.emptyend)let()=add_precision_depSplitReturnFunction.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleSplitReturn=String(structletoption_name="-eva-split-return"letarg_name="mode"letdefault=""lethelp="When 'mode' is a number, or 'full', this is equivalent \
to -eva-split-return-function f:mode for all functions f. \
When mode is 'auto', automatically split states at the end \
of all functions, according to the function return code"end)moduleSplitGlobalStrategy=State_builder.Ref(Split_strategy)(structletdefault()=Split_strategy.NoSplitletname="Parameters.SplitGlobalStrategy"letdependencies=[SplitReturn.self]end)let()=SplitReturn.add_set_hook(fun_x->SplitGlobalStrategy.set(trySplit_strategy.of_stringxwithSplit_strategy.ParseFailures->abort"@[@[incorrect argument for option %s@ (%s).@]"SplitReturn.names))let()=add_precision_depSplitReturn.parameter(* --- Misc --- *)let()=Parameter_customize.set_groupprecision_tuningmoduleILevel=Int(structletoption_name="-eva-ilevel"letdefault=8(* Must be synchronized with Int_set.small_cardinal. *)letarg_name="n"lethelp="Sets of integers are represented as sets up to <n> elements. \
Above, intervals with congruence information are used \
(defaults to 8, must be above 2)"end)let()=add_precision_depILevel.parameterlet()=ILevel.add_update_hook(fun_i->Int_set.set_small_cardinali)let()=ILevel.set_range~min:2~max:max_intletbuiltins=refDatatype.String.Set.emptyletregister_builtinname=builtins:=Datatype.String.Set.addname!builtinsletmem_builtinname=Datatype.String.Set.memname!builtinslet()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.argument_may_be_fundecl()moduleBuiltinsOverrides=Kernel_function_map(structincludeDatatype.Stringtypekey=Cil_types.kernel_functionletof_string~key:kf~prev:_nameopt=beginmatchnameoptwith|Somename->ifnot(mem_builtinname)thenabort"option '-eva-builtin %a:%s': undeclared builtin '%s'@.\
declared builtins: @[%a@]"Kernel_function.prettykfnamename(Pretty_utils.pp_list~sep:",@ "Format.pp_print_string)(Datatype.String.Set.elements!builtins)|_->abort"option '-eva-builtin':@ \
no builtin associated to function '%a',@ use '%a:<builtin>'"Kernel_function.prettykfKernel_function.prettykfend;nameoptletto_string~key:_name=nameend)(structletoption_name="-eva-builtin"letarg_name="f:ffc"lethelp="When analyzing function <f>, try to use Frama-C builtin \
<ffc> instead. \
Fall back to <f> if <ffc> cannot handle its arguments."letdefault=Kernel_function.Map.emptyend)let()=add_correctness_depBuiltinsOverrides.parameter(* Exported in Eva.mli. *)letuse_builtinkeyname=ifmem_builtinnamethenBuiltinsOverrides.add(key,Somename)elseraiseNot_foundlet()=Parameter_customize.set_groupprecision_tuningmoduleBuiltinsAuto=True(structletoption_name="-eva-builtins-auto"lethelp="When set, builtins will be used automatically to replace \
known C functions"end)let()=add_correctness_depBuiltinsAuto.parameterlet()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.set_negative_option_name""moduleBuiltinsList=False(structletoption_name="-eva-builtins-list"lethelp="List existing builtins, and which functions they \
are automatically associated to (if any)"end)let()=Parameter_customize.set_groupprecision_tuningmoduleLinearLevel=Zero(structletoption_name="-eva-subdivide-non-linear"letarg_name="n"lethelp="Improve precision when evaluating expressions in which a variable \
appears multiple times, by splitting its value at most n times. \
Defaults to 0."end)let()=LinearLevel.set_range~min:0~max:max_intlet()=add_precision_depLinearLevel.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleLinearLevelFunction=Kernel_function_map(structincludeDatatype.Inttypekey=Cil_types.kernel_functionletof_string~key:_~prev:_s=Option.map(funs->tryint_of_stringswithFailure_->raise(Cannot_build("'"^s^"' is not an integer")))sletto_string~key:_=Option.mapstring_of_intend)(structletoption_name="-eva-subdivide-non-linear-function"letarg_name="f:n"lethelp="Override the global option -eva-subdivide-non-linear with <n>\
when analyzing the function <f>."letdefault=Kernel_function.Map.emptyend)let()=add_precision_depLinearLevelFunction.parameterlet()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.argument_may_be_fundecl()moduleUsePrototype=Kernel_function_set(structletoption_name="-eva-use-spec"letarg_name="f1,..,fn"lethelp="Use the ACSL specification of the functions instead of \
their definitions"end)let()=add_correctness_depUsePrototype.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleSkipLibcSpecs=True(structletoption_name="-eva-skip-stdlib-specs"lethelp="Skip ACSL specifications on functions originating from the \
standard library of Frama-C, when their bodies are evaluated"end)let()=add_precision_depSkipLibcSpecs.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleRmAssert=True(structletoption_name="-eva-remove-redundant-alarms"lethelp="After the analysis, try to remove redundant alarms, \
so that the user needs to inspect fewer of them"end)let()=add_precision_depRmAssert.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleMemExecAll=True(structletoption_name="-eva-memexec"lethelp="Speed up analysis by not recomputing functions already \
analyzed in the same context. \
Callstacks for which the analysis has not been recomputed \
are incorrectly shown as dead in the GUI."end)let()=Parameter_customize.set_groupprecision_tuningmoduleArrayPrecisionLevel=Int(structletdefault=200letoption_name="-eva-plevel"letarg_name="n"lethelp="Use <n> as the precision level for arrays accesses. \
Array accesses are precise as long as the interval for the \
index contains less than n values. (defaults to 200)"end)let()=ArrayPrecisionLevel.set_range~min:0~max:max_intlet()=add_precision_depArrayPrecisionLevel.parameterlet()=ArrayPrecisionLevel.add_update_hook(fun_v->Offsetmap.set_plevelv)(* ------------------------------------------------------------------------- *)(* --- Messages --- *)(* ------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupmessagesmoduleValShowProgress=False(structletoption_name="-eva-show-progress"lethelp="Show progression messages during analysis"end)let()=Parameter_customize.set_groupmessagesmoduleValShowPerf=False(structletoption_name="-eva-show-perf"lethelp="Compute and show a summary of the time spent analyzing \
function calls"end)let()=Parameter_customize.set_groupmessagesmoduleValPerfFlamegraphs=Filepath(structletoption_name="-eva-flamegraph"letarg_name="file"letfile_kind="Text for flamegraph"letexistence=Fc_Filepath.Indifferentlethelp="Dump a summary of the time spent analyzing function calls \
in a format suitable for the Flamegraph tool \
(http://www.brendangregg.com/flamegraphs.html)"end)let()=Parameter_customize.set_groupmessagesmoduleShowSlevel=Int(structletoption_name="-eva-show-slevel"letdefault=100letarg_name="n"lethelp="Period for showing consumption of the allotted slevel during \
analysis"end)let()=ShowSlevel.set_range~min:1~max:max_intlet()=Parameter_customize.set_groupmessagesmodulePrintCallstacks=False(structletoption_name="-eva-print-callstacks"lethelp="When printing a message, also show the current call stack"end)let()=Parameter_customize.set_groupmessagesmoduleReportRedStatuses=Filepath(structletoption_name="-eva-report-red-statuses"letarg_name="filename"letfile_kind="CSV"letexistence=Fc_Filepath.Indifferentlethelp="Output the list of \"red properties\" in a csv file of the \
given name. These are the properties which were invalid for \
some states. Their consolidated status may not be invalid, \
but they should often be investigated first."end)let()=Parameter_customize.set_groupmessagesmoduleNumerorsLogFile=Filepath(structletoption_name="-eva-numerors-log-file"letarg_name="file"letfile_kind="Text"letexistence=Fc_Filepath.Indifferentlethelp="The Numerors domain will save each call to the DPRINT \
function in the given file"end)let()=Parameter_customize.set_groupmessagesmoduleStatisticsFile=Filepath(structletoption_name="-eva-statistics-file"letarg_name="file.csv"letfile_kind="CSV"letexistence=Fc_Filepath.Indifferentlethelp="Dump some internal statistics about the analysis"end)(* ------------------------------------------------------------------------- *)(* --- Interpreter mode --- *)(* ------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupinterpretermoduleInterpreterMode=False(structletoption_name="-eva-interpreter-mode"lethelp="Stop at first call to a library function, if main() has \
arguments, on undecided branches"end)let()=Parameter_customize.set_groupinterpretermoduleStopAtNthAlarm=Int(structletoption_name="-eva-stop-at-nth-alarm"letdefault=max_intletarg_name="n"lethelp="Abort the analysis when the nth alarm is emitted."end)let()=StopAtNthAlarm.set_range~min:0~max:max_int(* -------------------------------------------------------------------------- *)(* --- Ugliness required for correctness --- *)(* -------------------------------------------------------------------------- *)let()=Parameter_customize.is_invisible()moduleCorrectnessChanged=Int(structletoption_name="-eva-new-initial-state"letdefault=0letarg_name="n"lethelp=""end)let()=add_correctness_depCorrectnessChanged.parameter(* Changing the user-supplied initial state (or the arguments of main) through
the API does reset the state of Eva, but *not* the property statuses set by
Eva. Currently, statuses can only depend on command-line parameters.
We use the dummy one above to force a reset when needed. *)letchange_correctness=CorrectnessChanged.incr(* -------------------------------------------------------------------------- *)(* --- Eva options --- *)(* -------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupprecision_tuningmoduleEnumerateCond=Bool(structletoption_name="-eva-enumerate-cond"lethelp="Activate reduce_by_cond_enumerate."letdefault=trueend)let()=add_precision_depEnumerateCond.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleOracleDepth=Int(structletoption_name="-eva-oracle-depth"lethelp="Maximum number of successive uses of the oracle by the domain \
for the evaluation of an expression. Set 0 to disable the \
oracle."letdefault=2letarg_name=""end)let()=OracleDepth.set_range~min:0~max:max_intlet()=add_precision_depOracleDepth.parameterlet()=Parameter_customize.set_groupprecision_tuningmoduleReductionDepth=Int(structletoption_name="-eva-reduction-depth"lethelp="Maximum number of successive backward reductions that the \
domain may initiate."letdefault=4letarg_name=""end)let()=ReductionDepth.set_range~min:0~max:max_intlet()=add_precision_depReductionDepth.parameter(* -------------------------------------------------------------------------- *)(* --- Dynamic allocation --- *)(* -------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupmallocmoduleAllocBuiltin=String(structletoption_name="-eva-alloc-builtin"lethelp="Select the behavior of allocation builtins. \
By default, they use up to [-eva-mlevel] bases \
for each callstack (<by_stack>). They can also \
use one <imprecise> base for all allocations, \
create a <fresh> strong base at each call, \
or create a <fresh_weak> base at each call."letdefault="by_stack"letarg_name="imprecise|by_stack|fresh|fresh_weak"end)let()=add_precision_depAllocBuiltin.parameterlet()=AllocBuiltin.set_possible_values["imprecise";"by_stack";"fresh";"fresh_weak"]let()=Parameter_customize.set_groupmallocmoduleAllocFunctions=Filled_string_set(structletoption_name="-eva-alloc-functions"letarg_name="f1,...,fn"lethelp="Control call site creation for dynamically allocated bases. \
Dynamic allocation builtins use the call sites of \
malloc/calloc/realloc to know \
where to create new bases. This detection does not work for \
custom allocators or wrappers on top of them, unless they \
are listed here. \
By default, contains malloc, calloc and realloc."letdefault=Datatype.String.Set.of_list["malloc";"calloc";"realloc"]end)let()=AllocFunctions.add_aliases["-eva-malloc-functions"]let()=Parameter_customize.set_groupmallocmoduleAllocReturnsNull=True(structletoption_name="-eva-alloc-returns-null"lethelp="Memory allocation built-ins (malloc, calloc, realloc) are \
modeled as nondeterministically returning a null pointer"end)let()=add_correctness_depAllocReturnsNull.parameterlet()=Parameter_customize.set_groupmallocmoduleMallocLevel=Int(structletoption_name="-eva-mlevel"letdefault=0letarg_name="m"lethelp="Set to [m] the number of precise dynamic allocations \
besides the initial one, for each callstack (defaults to 0)"end)let()=MallocLevel.set_range~min:0~max:max_intlet()=add_precision_depMallocLevel.parameter(* -------------------------------------------------------------------------- *)(* --- Deprecated options and aliases --- *)(* -------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupalarmslet()=Parameter_customize.is_invisible()moduleAllRoundingModesConstants=False(structletoption_name="-eva-all-rounding-modes-constants"lethelp="Deprecated. Take into account the possibility of constants \
not being converted to the nearest representable value, \
or being converted to higher precision"end)let()=add_correctness_depAllRoundingModesConstants.parameterlet()=AllRoundingModesConstants.add_set_hook(fun_old_new->warning"Option -eva-all-rounding-modes-constants is now deprecated.@ \
Please contact us if you need it.")letdeprecated_aliases:((moduleParameter_sig.S)*string)list=[(moduleSemanticUnrollingLevel),"-slevel";(moduleSlevelFunction),"-slevel-function";(moduleNoResultsFunctions),"-no-results-function";(moduleResultsAll),"-results";(moduleJoinResults),"-val-join-results";(moduleAllRoundingModesConstants),"-all-rounding-modes-constants";(moduleUndefinedPointerComparisonPropagateAll),"-undefined-pointer-comparison-propagate-all";(moduleWarnPointerComparison),"-val-warn-undefined-pointer-comparison";(moduleWarnSignedConvertedDowncast),"-val-warn-signed-converted-downcast";(moduleWarnPointerSubstraction),"-val-warn-pointer-subtraction";(moduleIgnoreRecursiveCalls),"-val-ignore-recursive-calls";(moduleWarnCopyIndeterminate),"-val-warn-copy-indeterminate";(moduleReduceOnLogicAlarms),"-val-reduce-on-logic-alarms";(moduleInitializedLocals),"-val-initialized-locals";(moduleAutomaticContextMaxDepth),"-context-depth";(moduleAutomaticContextMaxWidth),"-context-width";(moduleAllocatedContextValid),"-context-valid-pointers";(moduleInitializationPaddingGlobals),"-val-initialization-padding-globals";(moduleWideningDelay),"-wlevel";(moduleSlevelMergeAfterLoop),"-val-slevel-merge-after-loop";(moduleSplitReturnFunction),"-val-split-return-function";(moduleSplitReturn),"-val-split-return";(moduleILevel),"-val-ilevel";(moduleBuiltinsOverrides),"-val-builtin";(moduleBuiltinsAuto),"-val-builtins-auto";(moduleBuiltinsList),"-val-builtins-list";(moduleLinearLevel),"-val-subdivide-non-linear";(moduleUsePrototype),"-val-use-spec";(moduleSkipLibcSpecs),"-val-skip-stdlib-specs";(moduleRmAssert),"-remove-redundant-alarms";(moduleMemExecAll),"-memexec-all";(moduleArrayPrecisionLevel),"-plevel";(moduleValShowProgress),"-val-show-progress";(moduleValShowPerf),"-val-show-perf";(moduleValPerfFlamegraphs),"-val-flamegraph";(moduleShowSlevel),"-val-show-slevel";(modulePrintCallstacks),"-val-print-callstacks";(moduleInterpreterMode),"-val-interpreter-mode";(moduleStopAtNthAlarm),"-val-stop-at-nth-alarm";(moduleAllocFunctions),"-val-malloc-functions";(moduleAllocReturnsNull),"-val-alloc-returns-null";(moduleMallocLevel),"-val-mlevel"]letadd_deprecated_alias((moduleP:Parameter_sig.S),name)=P.add_aliases~visible:false~deprecated:true[name]let()=List.iteradd_deprecated_aliasdeprecated_aliases(* -------------------------------------------------------------------------- *)(* --- Meta options --- *)(* -------------------------------------------------------------------------- *)modulePrecision=Int(structletoption_name="-eva-precision"letarg_name="n"letdefault=-1lethelp="Meta-option that automatically sets up some Eva parameters \
for a quick configuration of an analysis, \
from 0 (fastest but rather imprecise analysis) \
to 11 (accurate but potentially slow analysis)."end)let()=Precision.set_range~min:(-1)~max:11let()=add_precision_depPrecision.parameter(* Sets a parameter [P] to [t], unless it has already been set by any other
means. *)letset(typet)(moduleP:Parameter_sig.Swithtypet=t)=letprevious=ref(P.get())infun~defaultt->letalready_set=P.is_set()&¬(P.equal!previous(P.get()))inifnotalready_setthenbeginifdefaultthenP.clear()elseP.sett;previous:=P.get();end;letstr=Typed_parameter.get_valueP.parameterinletstr=matchP.parameter.Typed_parameter.accessorwith|Typed_parameter.String_->"\'"^str^"\'"|_->strinprintf" option %s %sset to %s%s."P.name(ifalready_setthen"already "else"")str(ifalready_set&¬(P.equalt(P.get()))then" (not modified)"elseifP.is_default()then" (default value)"else"")(* List of configure functions to be called for -eva-precision. *)letconfigures=ref[](* Binds the parameter [P] to the function [f] that gives the parameter value
for a precision n. *)letbind(typet)(moduleP:Parameter_sig.Swithtypet=t)f=letset=set(moduleP)inconfigures:=(funn->set~default:(n<0)(fn))::!configuresletdomainsn=let(<+>)domains(x,name)=ifn>=xthenname::domainselsedomainsin["cvalue"]<+>(1,"symbolic-locations")<+>(2,"equality")<+>(3,"gauges")<+>(5,"octagon")(* power 0 1 2 3 4 5 6 7 8 9 10 11 *)letslevel_power=[|0;10;20;35;60;100;160;250;500;1000;2000;5000|]letilevel_power=[|8;12;16;24;32;48;64;128;192;256;256;256|]letplevel_power=[|10;20;40;70;100;150;200;300;500;700;1000;2000|]letauto_unroll=[|0;16;32;64;96;128;192;256;384;512;768;1024|]letgetarrayn=ifn<0then0elsearray.(n)let()=bind(moduleMinLoopUnroll)(funn->max0(n-7));bind(moduleAutoLoopUnroll)(getauto_unroll);bind(moduleWideningDelay)(funn->1+n/2);bind(moduleHistoryPartitioning)(funn->(n-1)/5);bind(moduleSemanticUnrollingLevel)(getslevel_power);bind(moduleILevel)(getilevel_power);bind(moduleArrayPrecisionLevel)(getplevel_power);bind(moduleLinearLevel)(funn->n*20);bind(moduleRmAssert)(funn->n>0);bind(moduleDomains)(funn->Datatype.String.Set.of_list(domainsn));bind(moduleSplitReturn)(funn->ifn>3then"auto"else"");bind(moduleEqualityCall)(funn->ifn>4then"formals"else"none");bind(moduleOctagonCall)(funn->n>6);()letset_analysisn=feedback"Option %s %i detected, \
automatic configuration of the analysis:"Precision.namen;List.iter((|>)n)(List.rev!configures)letconfigure_precision()=ifPrecision.is_set()thenset_analysis(Precision.get())(* -------------------------------------------------------------------------- *)(* --- Freeze parameters. MUST GO LAST --- *)(* -------------------------------------------------------------------------- *)letparameters_correctness=Typed_parameter.Set.elements!parameters_correctnessletparameters_tuning=Typed_parameter.Set.elements!parameters_tuning