123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-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 LICENSE). *)(* *)(**************************************************************************)(* This file defines a set of static and dynamic parameters.
Static parameters, if muted, are muted very early: this file should
be the first executed, and it depends on nothing else. After that
the configuration does not change: for the rest of the application,
the parameters are considered as being static.
This simplifies adding configuration options to the rest of the
code; for instance it generally allows using local modules instead
of functors. Also, we can use a purely static configuration here,
to generate an optimized version of Codex.
Dynamic parameters are supposed to be changed dynamically, at any
time (e.g. during an interactive session). *)(* All parameters are function from unit to their result, in case they
become dynamic later. *)moduleLog=Tracelog.Make(structletcategory="Codex_config"end);;(** Domains options *)letr_ptr_size=ref@@(Units.In_bits.of_int@@-333);;letset_ptr_size(x:Units.In_bits.t)=Log.notice(funp->p"Setting pointer size to %d"(x:>int));r_ptr_size:=x;;letptr_size()=!r_ptr_size;;(* Dummy size when size of functions is required (e.g. allocation of a dummy base). *)letfunction_size()=0;;(** Limit the number of backpropagations performed in non-relational domains *)letback_propagation_limit=ref1000letset_back_propagation_limitx=back_propagation_limit:=xletget_back_propagation_limit()=!back_propagation_limit(* If true, record the parents of a variable (i.e. set of variables
whose defs immediately depends on the variable). Necessary for
re-forward term propagation. *)letterms_register_parents()=false;;(* Do we consider array elements individually, or do we squash all
cells together. *)letarray_expansion():[`full_expansion|`full_squashing]=`full_expansion;;(** Term generation options. *)(* When true, we put an assume whenever there is an alarm. This makes
the analysis more precise, but also slower; especially the set of
conditions on which we depend (represented as a BDD) can become
much larger. *)letassume_alarms()=true;;(* Translate binary terms to integer terms. Sound only if there is no
signed nor unsigned overflow, but works much better than bitvector reasoning. *)lettranslation_to_smt_use_integer()=true(** Debugging options *)(* When dumping a term to a SMT solver, dump the input to the SMT solver. *)letprint_smt_input()=false(* true *)(* false *)(** Goal-oriented options *)(* Should goal-oriented procedures attempt to perform deductive verification? *)lettry_hard_with_deductive_verification()=true(* Should goal-oriented procedures attempt to perform symbolic execution? *)lettry_hard_with_symbolic_execution()=true(* Should goal-oriented procedures attempt to perform software model checking with muz? *)lettry_hard_with_muz()=true(* Which muz engine to use. Valid values include clp for symbolic
execution, and pdr for property-directed reachability. *)(* Now it has spacer too. *)(* let muz_engine() = "pdr" *)(* let muz_engine() = "clp" *)letmuz_engine()="spacer"(* Whether to also check assertions that have been proved by abstract
interpretation with the goal-oriented procedures. This is mainly
used for debugging. *)lettry_hard_double_check()=false(* Number of seconds before the SMT solver times out. *)letsmt_timeout()=10;;letterm_group_inductive_variable_by_tuple=false(* None means: cannot write to an absolute address (default for C). *)letr_valid_absolute_addresses:(Z.t*Z.t)optionref=refNone;;letset_valid_absolute_addresses(min,max)=Log.notice(funp->p"Setting absolute addresses to 0x%s-0x%s"(Z.format"%08x"min)(Z.format"%08x"max));assert(Z.geqminZ.zero);if(Z.equalminZ.zero)thenPrintf.eprintf"Warning: zero (nullptr) considered a valid address\n";(assert(Z.geqmaxZ.one));r_valid_absolute_addresses:=Some(min,max);;letvalid_absolute_addresses()=!r_valid_absolute_addresses;;letr_show_memory_on_exit=reffalseletshow_memory_on_exit()=!r_show_memory_on_exitletset_show_memory_on_exitbool=r_show_memory_on_exit:=boollet_=at_exit(fun()->ifshow_memory_on_exit()thenletminor,promoted,major=Gc.counters()inletallocated=minor+.major-.promotedinletl1=String.length(Printf.sprintf"%.0f"allocated)inPrintf.eprintf"\nGC counters:\nminor_words: %*.0f\n\
major_words: %*.0f\n\
promoted_words: %*.0f\n\
total_allocated: %.0f\n"l1minorl1majorl1promotedallocated);;letr_assume_simple_asts=reftrueletset_assume_simple_astsb=r_assume_simple_asts:=bletassume_simple_asts()=!r_assume_simple_asts(* let r_widen = ref true
* let set_widen b = r_widen := b *)(* let widen () = !r_widen *)(* If false, do not perform widening, only joins. Note that
convergence will be slow on most programs. *)letwiden()=true(* Should malloc be handled only using the weak type domain. *)lethandle_malloc_as_unknown_typed_pointers()=(* false *)true(* If false, the behaviour is more predictable (e.g. garbage
collection cannot interfere, so ids are better used).
Moreover, it seems that this improves performances (probably because
more terms are reused).
MAYBE: Use "ancient" and move these terms there.
This would also provide a unique id, using address_of.
*)lethash_cons_terms_with_weak_table()=false(* When we don't want arithmetic operations to overflow, we perform
the operation using a larger size. For multiplication we have to
double the size; for addition/subtraction, a size + 1 suffice.
Should we minimize the size (do size + 1), or try to stick to
standard sizes (doubling the size)? *)letextend_size_for_additive_operationssize=(* size + 1 *)Units.In_bits.doublesize