1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)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;[str]letto_stringstr=strend)(structincludeDomain_mode.Function_Modeletof_stringstr=tryof_stringstrwithInvalid_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.Stringletof_string=function|"none"|"formals"|"all"asx->x|_->raise(Cannot_build"must be 'none', 'formals' or 'all'.")letto_strings=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=Enum(structtypet=[`All|`Pointer|`None]letoption_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=`Pointerletvalues=[`All,"all";`Pointer,"pointer";`None,"none"]end)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=Enum(structtypet=[`Initialized|`Uninitialized|`MaybeInitialized]letoption_name="-eva-initialization-padding-globals"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>."letdefault=`Initializedletvalues=[`Initialized,"yes";`Uninitialized,"no";`MaybeInitialized,"maybe"]end)let()=add_correctness_depInitializationPaddingGlobals.parameter(* ------------------------------------------------------------------------- *)(* --- Tuning --- *)(* ------------------------------------------------------------------------- *)(* --- Iteration strategy --- *)typedescending_strategy=NoIteration|FullIteration|ExitIterationlet()=Parameter_customize.set_groupprecision_tuninglet()=Parameter_customize.is_invisible()moduleDescendingIteration=Enum(structletoption_name="-eva-descending-iteration"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>."typet=descending_strategyletdefault=NoIterationletvalues=[NoIteration,"no";FullIteration,"full";ExitIteration,"exits"]end)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(Value_int)(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_tuninglet()=Parameter_customize.argument_may_be_fundecl()moduleHistoryPartitioningFunction=Kernel_function_map(Value_int)(structletoption_name="-eva-partition-history-function"letarg_name="f:n"lethelp="Override partition-history with <n> when analyzing <f>"letdefault=Kernel_function.Map.emptyend)let()=add_precision_depHistoryPartitioningFunction.parameterlet()=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(Split_strategy)(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=Custom(Split_strategy)(structletoption_name="-eva-split-return"letarg_name="mode"letdefault=Split_strategy.NoSplitlethelp="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)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.Stringletof_stringname=ifnot(mem_builtinname)thenabort"option '-eva-builtin': undeclared builtin '%s'@.\
declared builtins: @[%a@]"name(Pretty_utils.pp_list~sep:",@ "Format.pp_print_string)(Datatype.String.Set.elements!builtins);nameletto_stringname=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,name)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(Value_int)(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)let()=Parameter_customize.set_groupmessagesmoduleForcePrintSummary=False(structletoption_name="-eva-force-print-summary"lethelp="Print the analysis summary even when '-eva-verbose 0' is set"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(* -------------------------------------------------------------------------- *)(* --- Annotations Generator options --- *)(* -------------------------------------------------------------------------- *)let()=Parameter_customize.set_groupmessagesmoduleAnnot=Kernel_function_set(structletoption_name="-eva-annot"letarg_name="f"lethelp="Populate the specified functions with assertions \
representing the range of values computed by Eva \
on l-values read by the code, when available."end)(* -------------------------------------------------------------------------- *)(* --- 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^"\'"|_->strinletdkey=dkey_precision_settingsinprintf~dkey" 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>3thenSplitAutoelseNoSplit);bind(moduleEqualityCall)(funn->ifn>4then"formals"else"none");bind(moduleOctagonCall)(funn->n>6);()letset_analysisn=letdkey=dkey_precision_settingsinfeedback~dkey"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