12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: 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, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program 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. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** AST of the C language. *)openMopsaopenMopsa_c_parseropenUniversal.Ast(*==========================================================================*)(** {2 Types} *)(*==========================================================================*)typec_typedef={c_typedef_org_name:string;(** name as in source *)c_typedef_unique_name:string;(** unique name *)mutablec_typedef_def:typ;(** declaration *)c_typedef_range:Location.range;(** declaration location *)}(** Type definition. *)andc_record_kind=C_struct|C_union(** Whether a record is struct or union. *)andc_record_type={c_record_kind:c_record_kind;c_record_org_name:string;(** name as in source, may be empty *)c_record_unique_name:string;(** unique, non-empty name *)c_record_defined:bool;(** false if only declared *)c_record_sizeof:Z.t;(** size of record, in bytes *)c_record_alignof:Z.t;(** alignment, in bytes *)mutablec_record_fields:c_record_fieldlist;c_record_range:Location.range;(** declaration location *)}(** Struct or union type. *)andc_record_field={c_field_org_name:string;(** may be empty for anonymous or padding fields *)c_field_name:string;(** non-empty name *)c_field_offset:int;c_field_bit_offset:int;c_field_type:typ;c_field_range:Location.range;(** declaration location *)c_field_index:int;}(** Struct or union field. *)andc_enum_type={c_enum_org_name:string;(** name as in source, may be empty *)c_enum_unique_name:string;(** unique, non-empty name *)c_enum_defined:bool;(** false if only declared *)c_enum_values:c_enum_valuelist;c_enum_integer_type:c_integer_type;c_enum_range:Location.range;(** declaration location *)}(** Enumerated type. *)andc_enum_value={c_enum_val_org_name:string;(** name as in source *)c_enum_val_unique_name:string;(** unique name *)c_enum_val_value:Z.t;c_enum_val_range:range;}(** A possible value in an enumerated type. *)andc_integer_type=|C_signed_char|C_unsigned_char|C_signed_short|C_unsigned_short|C_signed_int|C_unsigned_int|C_signed_long|C_unsigned_long|C_signed_long_long|C_unsigned_long_long|C_signed_int128|C_unsigned_int128(** Integer types. *)andc_float_type=C_float|C_double|C_long_double|C_float128(** Floating-point types. *)andc_array_length=|C_array_no_length|C_array_length_cstofZ.t|C_array_length_exprofexpr(** Cases of arrays length. *)andc_qual={c_qual_is_const:bool;c_qual_is_volatile:bool;c_qual_is_restrict:bool;}(** Type qualifiers. *)andc_function_type={c_ftype_return:typ;c_ftype_params:typlist;c_ftype_variadic:bool;}(** Function type. *)typetyp+=|T_c_void(** Void type. *)|T_c_bool|T_c_integerofc_integer_type|T_c_floatofc_float_type|T_c_pointeroftyp(** Scalar types. *)|T_c_arrayoftyp*c_array_length(** Arrays. *)|T_c_bitfieldoftyp(* integer or enum type *)*int(* bit-size *)(** Bitfields, with bit-width, only used in struct. *)|T_c_functionofc_function_typeoption(** Function, with or without a prototype *)|T_c_builtin_fn(** Built-in functions *)|T_c_typedefofc_typedef(** Typedefs *)|T_c_recordofc_record_type(** struct and union *)|T_c_enumofc_enum_type(** enums *)|T_c_qualifiedofc_qual*typ(** Qualified type. *)|T_c_block_objectoftyp(** Type of block objects. *)|T_c_unknown_builtinofstring(** Unknown builtin type. *)(** {2 Function descriptor} *)(** *********************** *)typec_fundec={mutablec_func_uid:int;(** unique identifier *)mutablec_func_org_name:string;(** original name *)mutablec_func_unique_name:string;(** unique name for globals and statics *)c_func_is_static:bool;mutablec_func_return:typ;(** type of returned value *)mutablec_func_parameters:varlist;(** function parameters *)mutablec_func_body:stmtoption;(** function body *)mutablec_func_static_vars:varlist;(** static variables declared in the function *)mutablec_func_local_vars:varlist;(** local variables declared in the function (excluding parameters) *)mutablec_func_variadic:bool;(** whether the has a variable number of arguments *)mutablec_func_range:range;(** location range of the declaration *)mutablec_func_name_range:range;(** location range of the name in the declaration *)mutablec_func_stub:Stubs.Ast.stub_funcoption;(** stub comment *)}(** Function descriptor. *)(** {2 C variables} *)(* *************** *)typec_var_scope=|Variable_global(** global shared among translation units *)|Variable_extern(** declared but not defined *)|Variable_localofc_fundec(** local to a function *)|Variable_parameterofc_fundec(** formal argument *)|Variable_file_staticofstring(** restricted to a translation unit *)|Variable_func_staticofc_fundec(** restricted to a function *)letpp_scopefmts=Format.fprintffmt"%s"(matchswith|Variable_global->"variable_global"|Variable_extern->"extern"(** declared but not defined *)|Variable_local_->"local"|Variable_parameter_->"parameter"|Variable_file_static_->"file static"|Variable_func_static_->"func static")(** Variable initialization. *)typec_var_init=|C_init_exprofexpr|C_init_listofc_var_initlist(** specified elements *)*c_var_initoption(** filler *)|C_init_implicitoftyptypecvar={cvar_scope:c_var_scope;(** life-time scope of the variable *)cvar_range:range;(** declaration range *)cvar_uid:int;cvar_orig_name:string;cvar_uniq_name:string;cvar_before_stmts:stmtlist;(** list of statements to execute before the declaration of a variable *)cvar_after_stmts:stmtlist;(** list of statements to execute after the declaration of a variable *)}typevar_kind+=|V_cvarofcvar(** C variable *)let()=register_var{print=(funnextfmtv->matchvkindvwith|V_cvarcvar->if!Framework.Core.Ast.Var.print_uniq_with_uidthenFormat.fprintffmt"%s:%a"cvar.cvar_orig_namepp_relative_rangecvar.cvar_rangeelseFormat.fprintffmt"%s"cvar.cvar_orig_name|_->nextfmtv);compare=(funnextv1v2->matchvkindv1,vkindv2with|V_cvarcvar1,V_cvarcvar2->Compare.compose[(fun()->Stdlib.comparecvar1.cvar_uidcvar2.cvar_uid);(fun()->Stdlib.comparecvar1.cvar_uniq_namecvar2.cvar_uniq_name)]|_->nextv1v2);}(** {2 C expressions} *)(* ***************** *)typeoperator+=|O_c_and|O_c_ortypec_inc_location=|PRE|POST(** Whether an incrementation is performed before (PRE) or after (POST) the expression value is used *)typec_inc_direction=|INC|DEC(** Whether an incrementation is ++ or -- *)typec_character_kind=|C_char_ascii|C_char_wide|C_char_utf8|C_char_utf16|C_char_utf32|C_char_unevaluatedtypeconstant+=|C_c_characterofZ.t*c_character_kind(** Constant character *)|C_c_stringofstring*c_character_kind(** Constant string literal *)|C_c_invalid(** Invalid pointer value *)typeexpr_kind+=|E_c_conditionalofexpr(** condition *)*expr(** then *)*expr(** else *)(** ?: ternary operator *)|E_c_array_subscriptofexpr(** array *)*expr(** index *)(** Array access. *)|E_c_member_accessofexpr(** record *)*int(** field index *)*string(** field *)(** record.field access *)|E_c_functionofc_fundec|E_c_builtin_functionofstring|E_c_builtin_callofstring*exprlist|E_c_arrow_accessofexpr(** pointer *)*int(** field index *)*string(** field *)(** pointer->field access *)|E_c_assignofexpr(** lvalue *)*expr(** rvalue*)(** Assignment as an expression *)|E_c_compound_assignofexpr(** lvalue *)*typ(** promoted type of lvalue before operation *)*operator(** operator *)*expr(** rvalue *)*typ(** type of the result, before converting back to lvalue type *)(** Assignment with an operation: e1 += e2, etc. *)|E_c_commaofexpr*expr(** , operator *)|E_c_incrementofc_inc_direction*c_inc_location*expr|E_c_address_ofofexpr(** & operator (address of lvalue) *)|E_c_derefofexpr(** * operator (pointer dereference) *)|E_c_castofexpr*bool(** explicitness *)(** casted expression *)|E_c_statementofstmt|E_c_predefinedofstring(** predefined identifier *)|E_c_var_argsofexpr(** __builtin_va_arg *)|E_c_atomicofint(** operation *)*expr*expr|E_c_block_objectofexpr(** Block objects are useful to distinguish between operations on
the block itself and its content. For, expanding the contents of
a block will duplicate every cell in the block, while expanding
the block object will update the pointers that point to the
block. *)(*==========================================================================*)(** {2 Scope update} *)(*==========================================================================*)typec_scope_update={c_scope_var_added:varlist;c_scope_var_removed:varlist;}(** Scope update information for jump statements *)(*==========================================================================*)(** {2 Statements} *)(*==========================================================================*)typestmt_kind+=|S_c_goto_stabofstmt(** stabilization point for goto statement *)|S_c_declarationofvar*c_var_initoption*c_var_scope(** declaration of a variable *)|S_c_do_whileofstmt(** body *)*expr(** condition *)(** do-while loop *)|S_c_forofstmt(** init *)*exproption(** condition *)*exproption(** increment *)*stmt(** body *)(** for loop; the scope of the locals declared in the init block
is the while for loop *)|S_c_returnofexproption*c_scope_update(** return statement *)|S_c_breakofc_scope_update(** break statement *)|S_c_continueofc_scope_update(** continue statement *)|S_c_gotoofstring*c_scope_update(** goto statements. *)|S_c_switchofexpr*stmt(** switch statement. *)|S_c_labelofstring(** statement label. *)|S_c_switch_caseofexprlist*c_scope_update(** case of a switch statement.
case a:
case b:
stmt;
is represented through S_c_switch_case [a; b] to factor in some cases
For integer cases, we use the interval [a, b] to simplify expressions, similar to the GCC C extension for ranges
*)|S_c_switch_defaultofc_scope_update(** default case of switch statements. *)|S_c_asmofstring(** inline assembly
for now, we keep only a string representation to display warnings;
see C_AST.asm_kind for a more usable representation when support is added
*)typec_program={c_globals:(var*c_var_initoption)list;(** global variables of the program *)c_functions:c_fundeclist;(** functions of the program *)c_stub_directives:Stubs.Ast.stub_directivelist;(** list of stub directives *)}typeprog_kind+=|C_programofc_programmoduleCProgramKey=GenContextKey(structtype'at=c_programletprintppfmtprog=Format.fprintffmt"C program"end)(** Flow-insensitive context to keep the analyzed C program *)letc_program_ctx=CProgramKey.key(** Set the C program in the flow *)letset_c_programprogflow=Flow.set_ctx(Flow.get_ctxflow|>add_ctxc_program_ctxprog)flow(** Get the C program from the flow *)letget_c_programflow=Flow.get_ctxflow|>find_ctxc_program_ctx(*==========================================================================*)(** {2 Conversion to/from Clang parser types} *)(*==========================================================================*)letto_clang_int_type:c_integer_type->C_AST.integer_type=function|C_signed_char->C_AST.SIGNED_CHAR|C_unsigned_char->C_AST.UNSIGNED_CHAR|C_signed_short->C_AST.SIGNED_SHORT|C_unsigned_short->C_AST.UNSIGNED_SHORT|C_signed_int->C_AST.SIGNED_INT|C_unsigned_int->C_AST.UNSIGNED_INT|C_signed_long->C_AST.SIGNED_LONG|C_unsigned_long->C_AST.UNSIGNED_LONG|C_signed_long_long->C_AST.SIGNED_LONG_LONG|C_unsigned_long_long->C_AST.UNSIGNED_LONG_LONG|C_signed_int128->C_AST.SIGNED_INT128|C_unsigned_int128->C_AST.UNSIGNED_INT128letto_clang_float_type:c_float_type->C_AST.float_type=function|C_float->C_AST.FLOAT|C_double->C_AST.DOUBLE|C_long_double->C_AST.LONG_DOUBLE|C_float128->C_AST.FLOAT128letfrom_clang_int_type:C_AST.integer_type->c_integer_type=function|C_AST.(CharSIGNED)->C_signed_char|C_AST.(CharUNSIGNED)->C_unsigned_char|C_AST.SIGNED_CHAR->C_signed_char|C_AST.UNSIGNED_CHAR->C_unsigned_char|C_AST.SIGNED_SHORT->C_signed_short|C_AST.UNSIGNED_SHORT->C_unsigned_short|C_AST.SIGNED_INT->C_signed_int|C_AST.UNSIGNED_INT->C_unsigned_int|C_AST.SIGNED_LONG->C_signed_long|C_AST.UNSIGNED_LONG->C_unsigned_long|C_AST.SIGNED_LONG_LONG->C_signed_long_long|C_AST.UNSIGNED_LONG_LONG->C_unsigned_long_long|C_AST.SIGNED_INT128->C_signed_int128|C_AST.UNSIGNED_INT128->C_unsigned_int128letfrom_clang_float_type:C_AST.float_type->c_float_type=function|C_AST.FLOAT->C_float|C_AST.DOUBLE->C_double|C_AST.LONG_DOUBLE->C_long_double|C_AST.FLOAT128->C_float128(***********************)(** Target information *)(***********************)moduleTargetCtx=GenContextKey(structtype'at=Clang_AST.target_infoletprint_fmt_=Format.pp_print_stringfmt"target information"end)letget_c_target_infoflow=letctx=Flow.get_ctxflowinfind_ctxTargetCtx.keyctxletset_c_target_infotargetflow=letctx=Flow.get_ctxflowinletctx'=add_ctxTargetCtx.keytargetctxinFlow.set_ctxctx'flowletremove_c_target_infoflow=letctx=Flow.get_ctxflowinletctx'=remove_ctxTargetCtx.keyctxinFlow.set_ctxctx'flow(*==========================================================================*)(** {2 Sizes and alignments} *)(*==========================================================================*)(** [sizeof t] computes the size (in bytes) of a C type [t] *)letrecsizeof_type_in_target(t:typ)target:Z.t=matchtwith|T_c_void->C_utils.sizeof_typetargetC_AST.T_void|T_c_bool->C_utils.sizeof_typetargetC_AST.T_bool|T_c_integeri->to_clang_int_typei|>C_utils.sizeof_inttarget|>Z.of_int|T_c_floatf->to_clang_float_typef|>C_utils.sizeof_floattarget|>Z.of_int|T_c_pointer_->fstC_AST.void_ptr_type|>C_utils.sizeof_typetarget|T_c_array(t,C_array_length_cstx)->Z.mulx(sizeof_type_in_targetttarget)|T_c_array(_,(C_array_no_length|C_array_length_expr_))->panic~loc:__LOC__"%a has no length information"pp_typt|T_c_bitfield(t,size)->Z.of_intsize(* panic ~loc:__LOC__ "%a is a bitfield" pp_typ t *)|T_c_function_|T_c_builtin_fn->panic~loc:__LOC__"%a is a function"pp_typt|T_c_typedeftd->sizeof_type_in_targettd.c_typedef_deftarget|T_c_recordr->ifnotr.c_record_definedthenZ.zero(*panic ~loc:__LOC__ " %a is undefined" pp_typ t; *)elser.c_record_sizeof|T_c_enume->ifnote.c_enum_definedthenpanic~loc:__LOC__"%a is undefined"pp_typt;sizeof_type_in_target(T_c_integere.c_enum_integer_type)target|T_c_qualified(_,t)->sizeof_type_in_targetttarget|t->panic~loc:__LOC__"%a not a C type"pp_typtletsizeof_type(t:typ)flow:Z.t=lettarget=get_c_target_infoflowinsizeof_type_in_targetttargetlethost_target_info=Clang_parser.get_target_info(Clang_parser.get_default_target_options())letsizeof_type_in_host(t:typ):Z.t=sizeof_type_in_targetthost_target_infoletsizeof_expr(t:typ)flowrange:expr=letrecdoitt=matchtwith|T_c_void|T_c_bool|T_c_integer_|T_c_float_|T_c_pointer_|T_c_record_|T_c_enum_->mk_z(sizeof_typetflow)range|T_c_array(t,l)->letlen=matchlwith|C_array_length_cstlen->mk_zlenrange|C_array_length_expre->e|C_array_no_length->(* TODO: fix *)(* error range "sizeof" "array with no size"*)mk_zerorangeinmk_binop(doitt)(O_mult)lenrange|T_c_bitfield(t,_)->invalid_arg"sizeof_expr: size of bitfield"|T_c_function_|T_c_builtin_fn->invalid_arg"sizeof_expr: size of function"|T_c_typedeft->doit(t.c_typedef_def)|_->assertfalseindoitt(** Size (in bytes) of a type, as an expression. Handles variable-length ararys. *)letrecremove_typedef=function|T_c_typedef(td)->remove_typedef(td.c_typedef_def)|t->tletrecremove_qual=function|T_c_qualified(_,t)->remove_qualt|T_c_pointert->T_c_pointer(remove_qualt)|t->tletrecremove_typedef_qual=function|T_c_qualified(_,t)->remove_typedef_qualt|T_c_typedef(td)->remove_typedef_qual(td.c_typedef_def)|t->t(** [is_signed t] whether [t] is signed *)letrecis_signed(t:typ):bool=matchremove_typedef_qualtwith|T_c_bool->true|T_c_integerit->beginmatchitwith|C_signed_char|C_signed_short|C_signed_int|C_signed_long|C_signed_long_long|C_signed_int128->true|_->falseend|T_c_enume->is_signed(T_c_integere.c_enum_integer_type)|_->panic~loc:__LOC__"%a is not an integer type"pp_typt(** [range t] computes the interval range of type [t] *)letrangeof(t:typ)flow=letpart=8*Z.to_int(sizeof_typetflow)inifis_signedtthenletpart'=Z.pow(Z.of_int(2))(part-1)in(Z.negpart',Z.subpart'(Z.of_int1))elseletpart'=Z.pow(Z.of_int2)partin(Z.of_int0,Z.subpart'(Z.of_int1))(** [range t] computes the interval range of type [t] as integers *)letint_rangeoftflow=leta,b=rangeoftflowin(Z.to_inta,Z.to_intb)(** [wrap_expr e (l,h)] expression needed to bring back [e] in range ([l],[h]) *)letwrap_expr(e:expr)((l,h):Z.t*Z.t)range:expr=mk_unop(O_wrap(l,h))e~etyp:e.etyprangeletis_c_char_type(t:typ)=matchremove_typedef_qualtwith|T_c_integer(C_signed_char|C_unsigned_char)->true|_->falseletis_c_string_type(t:typ)=matchremove_typedef_qualtwith|T_c_array(t,_)->is_c_char_typet|_->false(** [is_c_int_type t] tests whether [t] is an integer type *)letis_c_int_type(t:typ)=matchremove_typedef_qualtwith|T_c_bool->true|T_c_enum_->true|T_c_integer_->true|_->falseletis_c_int_array_type(t:typ)=matchremove_typedef_qualtwith|T_c_array(t,_)->is_c_int_typet|_->falseletis_c_signed_int_type(t:typ)=matchremove_typedef_qualtwith|T_c_bool->false|T_c_enum_->false|T_c_integer(C_signed_char|C_signed_short|C_signed_int|C_signed_int128|C_signed_long|C_signed_long_long)->true|T_c_integer(C_unsigned_char|C_unsigned_short|C_unsigned_int|C_unsigned_int128|C_unsigned_long|C_unsigned_long_long)->false|_->falseletis_c_bool_type(t:typ)=matchremove_typedef_qualtwith|T_c_bool->true|_->false(** [is_c_int_type t] tests whether [t] is a floating point type *)letis_c_float_type(t:typ)=matchremove_typedef_qualtwith|T_c_float_->true|_->falseletget_c_float_type(t:typ)=matchremove_typedef_qualtwith|T_c_floatt->t|_->panic~loc:__LOC__"get_c_float_type called on a non-float type %a"pp_typt(** Get the float precision from a C type *)letget_c_float_precisiont=matchget_c_float_typetwith|C_float->F_SINGLE|C_double->F_DOUBLE|C_long_double->F_LONG_DOUBLE|C_float128->F_FLOAT128letis_c_bitfieldtyp=matchtypwith|T_c_bitfield_->true|_->false(** [is_c_int_type t] tests whether [t] is a numeric type *)letis_c_num_type(t:typ)=is_c_int_typet||is_c_float_typet||is_c_bitfieldt(** [is_c_scalar_type t] tests whether [t] is a scalar type *)letis_c_scalar_type(t:typ)=matchremove_typedef_qualtwith|T_c_bool|T_c_integer_|T_c_float_|T_c_pointer_->true|T_c_bitfield_->true|T_c_enum_->true|_->false(** [is_c_pointer t] tests whether [t] is a pointer *)letis_c_pointer_type(t:typ)=matchremove_typedef_qualtwith|T_c_pointer_->true|T_c_array_->true|_->falseletis_c_void_type(t:typ)=matchremove_typedef_qualtwith|T_c_void->true|_->falseletis_c_record_type(t:typ)=matchremove_typedef_qualtwith|T_c_record_->true|_->falseletis_c_struct_type(t:typ)=matchremove_typedef_qualtwith|T_c_record({c_record_kind=C_struct})->true|_->falseletis_c_union_type(t:typ)=matchremove_typedef_qualtwith|T_c_record({c_record_kind=C_union})->true|_->falseletrecis_c_array_type(t:typ)=matchremove_typedef_qualtwith|T_c_array_->true|_->falseletrecis_c_function_type(t:typ)=matchremove_typedef_qualtwith|T_c_function_->true|_->false(** [is_scalartype t] lifts [t] to a pointer to [t] *)letpointer_type(t:typ)=(T_c_pointert)letrecunder_pointer_type(t:typ):typ=matchremove_typedef_qualtwith|T_c_pointert'->t'|_->failwith"[under_pointer_type] called with a non pointer argument"letrecunder_array_type(t:typ):typ=matchremove_typedef_qualtwith|T_c_array(t',_)->t'|_->failwith"[under_array_type] called with a non array argument"letunder_type(t:typ):typ=matchremove_typedef_qualtwith|T_c_array_->under_array_typet|T_c_pointer_->under_pointer_typet|_->failwith"[under_type] called with a non array/pointer argument"letvoid_to_chart=matchremove_typedef_qualtwith|T_c_void->T_c_integerC_unsigned_char|_->tletget_array_constant_lengtht=matchremove_typedef_qualtwith|T_c_array(_,C_array_length_cstn)->n|_->assertfalseletalign_byteti=matchremove_typedef_qualtwith|T_c_recordcrt->(List.nthcrt.c_record_fieldsi).c_field_offset|_->assertfalseletis_c_type=function|T_c_void|T_c_bool|T_c_integer_|T_c_float_|T_c_pointer_|T_c_array_|T_c_bitfield_|T_c_function_|T_c_builtin_fn|T_c_typedef_|T_c_record_|T_c_enum_|T_c_qualified_->true|T_addr->true(* XXX is it safe to consider heap addresses as C objects? *)|_->falseletis_c_function_parameterv=matchv.vkindwith|V_cvar{cvar_scope=Variable_parameter_}->true|_->falseletmk_c_address_oferange=mk_expr(E_c_address_ofe)~etyp:(T_c_pointere.etyp)rangeletmk_c_dereferange=mk_expr(E_c_derefe)~etyp:(under_pointer_typee.etyp)rangeletmk_c_member_accessrfrange=mk_expr(E_c_member_access(r,f.c_field_index,f.c_field_org_name))~etyp:f.c_field_typerangeletmk_c_arrow_accessrfrange=mk_expr(E_c_arrow_access(r,f.c_field_index,f.c_field_org_name))~etyp:f.c_field_typerangeletmk_c_member_access_by_namerfnamerange=letfields=matchremove_typedef_qualr.etypwith|T_c_recordr->r.c_record_fields|_->assertfalseinletfield=List.find(funf->f.c_field_org_name=fname)fieldsinmk_c_member_accessrfieldrangeletmk_c_arrow_access_by_namerfnamerange=lett=under_typer.etypinletfields=matchremove_typedef_qualtwith|T_c_recordr->r.c_record_fields|_->assertfalseinletfield=List.find(funf->f.c_field_org_name=fname)fieldsinmk_c_arrow_accessrfieldrangeletmk_c_subscript_accessairange=mk_expr(E_c_array_subscript(a,i))~etyp:(under_typea.etyp)rangeletmk_c_charactercranget=letx=int_of_charcinletx=ifis_signedt&&x>=128thenx-256elsexinmk_constant(C_c_character(Z.of_intx,C_char_ascii))range~etyp:t(* extract a multi-byte integer of type t starting at offset off of s *)letextract_multibyte_integer(s:string)(off:int)tflow=letn=Z.to_int(sizeof_typetflow)inlettarget=get_c_target_infoflowin(* get bytes in right order according to endianess *)letrecdoitacci=ifi>=nthenaccelseletoff'=iftarget.target_big_endianthenoff+ielseoff+n-i-1indoit(Z.add(Z.mul(Z.of_int256)acc)(Z.of_int(int_of_chars.[off'])))(i+1)inletv=doitZ.zero0in(* sign correction *)ifis_signedt&&v>=Z.shift_leftZ.one(n*8-1)thenZ.subv(Z.shift_leftZ.one(n*8))elsevletmk_c_multibyte_integer(s:string)(off:int)tflowrange=mk_z(extract_multibyte_integersofftflow)~typ:trangeletmk_c_invalid_pointerrange=mk_constantC_c_invalid~etyp:(T_c_pointerT_c_void)rangeletvoid=T_c_voidletu8=T_c_integer(C_unsigned_char)lets8=T_c_integer(C_signed_char)lets16=T_c_integer(C_signed_short)letu16=T_c_integer(C_unsigned_short)lets32=T_c_integer(C_signed_int)letu32=T_c_integer(C_unsigned_int)lets64=T_c_integer(C_signed_long)letu64=T_c_integer(C_unsigned_long)letul=T_c_integer(C_unsigned_long)letsl=T_c_integer(C_signed_long)letull=T_c_integer(C_unsigned_long_long)letsll=T_c_integer(C_signed_long_long)letarray_typetypsize=T_c_array(typ,C_array_length_cstsize)letsize_typeflow=lett=C_utils.size_type(get_c_target_infoflow)|>from_clang_int_typeinT_c_integertlettype_of_strings=T_c_array(s8,C_array_length_cst(Z.of_int(1+String.lengths)))letis_c_block_object_type=functionT_c_block_object_->true|_->falseletto_c_block_objecte=mk_expr(E_c_block_objecte)e.erange~etyp:(T_c_block_objecte.etyp)letof_c_block_objecte=matchekindewith|E_c_block_objectee->ee|_->assertfalseletmk_c_string?(kind=C_char_ascii)srange=mk_constant(C_c_string(s,kind))range~etyp:(type_of_strings)letmk_c_fun_typf=letftype={c_ftype_return=f.c_func_return;c_ftype_params=List.map(funp->p.vtyp)f.c_func_parameters;c_ftype_variadic=f.c_func_variadic;}inT_c_function(Someftype)letmk_c_callfargsrange=mk_expr(E_call(mk_expr(E_c_functionf)range~etyp:(mk_c_fun_typf),args))range~etyp:(f.c_func_return)letmk_c_builtin_callbuiltinargstyprange=mk_expr(E_c_builtin_call(builtin,args))range~etyp:typletmk_c_call_stmtfargsrange=letexp=mk_c_callfargsrangeinmk_stmt(S_expressionexp)rangeletmk_c_castetrange=mk_expr(E_c_cast(e,true))~etyp:trangeletmk_c_nullrange=mk_c_cast(mk_zero~typ:u8range)(pointer_typevoid)rangeletmk_c_declarationvinitscoperange=mk_stmt(S_c_declaration(v,init,scope))rangeletis_c_global_scope=function|Variable_global|Variable_extern|Variable_file_static_->true|Variable_func_static_|Variable_local_|Variable_parameter_->falselet()=register_typ_compare(funnextt1t2->matchremove_typedeft1,remove_typedeft2with|T_c_void,T_c_void->0|T_c_bool,T_c_bool->0|T_c_integeri1,T_c_integeri2->comparei1i2|T_c_floatf1,T_c_floatf2->comparef1f2|T_c_pointert1,T_c_pointert2->compare_typt1t2|T_c_array(t1,l1),T_c_array(t2,l2)->Compare.compose[(fun()->compare_typt1t2);(fun()->matchl1,l2with|C_array_length_cstn1,C_array_length_cstn2->Z.comparen1n2|C_array_length_expre1,C_array_length_expre2->panic~loc:__LOC__"type compare on arrays with expr length not supported"|C_array_no_length,C_array_no_length->0|_->comparel1l2)]|T_c_bitfield(t1,n1),T_c_bitfield(t2,n2)->Compare.compose[(fun()->compare_typt1t2);(fun()->comparen1n2)]|T_c_functionf1,T_c_functionf2->beginmatchf1,f2with|Someff1,Someff2->ifList.lengthff1.c_ftype_params=List.lengthff2.c_ftype_paramsthenletl=[(fun()->compare_typff1.c_ftype_returnff2.c_ftype_return);(fun()->compareff1.c_ftype_variadicff2.c_ftype_variadic)]@(List.map2(funtt'->fun()->compare_typtt')ff1.c_ftype_paramsff2.c_ftype_params)inCompare.composelelse1|None,None->0|_->1end|T_c_builtin_fn,T_c_builtin_fn->0|T_c_typedeftd1,T_c_typedeftd2->compare_typtd1.c_typedef_deftd2.c_typedef_def|T_c_recordr1,T_c_recordr2->ifr1==r2then0elseletcompare_c_record_fieldf1f2=iff1==f2then0elseCompare.compose[(* also compare field names, as field swaps should be detected *)(fun()->Stdlib.comparef1.c_field_org_namef2.c_field_org_name);(fun()->Stdlib.comparef1.c_field_offsetf2.c_field_offset);(fun()->Stdlib.comparef1.c_field_bit_offsetf2.c_field_bit_offset);(fun()->compare_typf1.c_field_typef2.c_field_type);(fun()->Stdlib.comparef1.c_field_indexf2.c_field_index)]inCompare.compose[(fun()->String.comparer1.c_record_unique_namer2.c_record_unique_name);(fun()->Stdlib.comparer1.c_record_kindr2.c_record_kind);(fun()->Stdlib.comparer1.c_record_definedr2.c_record_defined);(fun()->Z.comparer1.c_record_sizeofr2.c_record_sizeof);(fun()->Z.comparer1.c_record_alignofr2.c_record_alignof);(fun()->Compare.listcompare_c_record_fieldr1.c_record_fieldsr2.c_record_fields)]|T_c_enume1,T_c_enume2->letcompare_c_enum_valuev1v2=Z.comparev1.c_enum_val_valuev2.c_enum_val_valueinCompare.compose[(fun()->Stdlib.comparee1.c_enum_definede2.c_enum_defined);(fun()->Compare.listcompare_c_enum_valuee1.c_enum_valuese2.c_enum_values);(fun()->Stdlib.comparee1.c_enum_integer_typee2.c_enum_integer_type)]|T_c_qualified(q1,t1),T_c_qualified(q2,t2)->Compare.compose[(fun()->compareq1.c_qual_is_constq2.c_qual_is_const);(fun()->compareq1.c_qual_is_volatileq2.c_qual_is_volatile);(fun()->compareq1.c_qual_is_restrictq2.c_qual_is_restrict);(fun()->compare_typt1t2)]|T_c_block_objecttt1,T_c_block_objecttt2->compare_typtt1tt2|_->nextt1t2)letcompare_c_fundecf1f2=Compare.compose[(fun()->Stdlib.comparef1.c_func_org_namef2.c_func_org_name);(fun()->Stdlib.comparef1.c_func_is_staticf2.c_func_is_static);(fun()->compare_typf1.c_func_returnf2.c_func_return);(fun()->Compare.listcompare_varf1.c_func_parametersf2.c_func_parameters);(fun()->Compare.optioncompare_stmtf1.c_func_bodyf2.c_func_body);(fun()->Compare.listcompare_varf1.c_func_static_varsf2.c_func_static_vars);(fun()->Compare.listcompare_varf1.c_func_local_varsf2.c_func_local_vars);(fun()->Stdlib.comparef1.c_func_variadicf2.c_func_variadic)(*XXX: ranges and stubs are ignored. *)]let()=register_expr_compare(funnexte1e2->matchekinde1,ekinde2with|E_c_conditional(cond1,then1,else1),E_c_conditional(cond2,then2,else2)->Compare.triplecompare_exprcompare_exprcompare_expr(cond1,then1,else1)(cond2,then2,else2)|E_c_array_subscript(a1,i1),E_c_array_subscript(a2,i2)->Compare.paircompare_exprcompare_expr(a1,i1)(a2,i2)|E_c_member_access(s1,i1,f1),E_c_member_access(s2,i2,f2)->Compare.triplecompare_exprcomparecompare(s1,i1,f1)(s2,i2,f2)|E_c_function(f1),E_c_function(f2)->compare_c_fundecf1f2|E_c_builtin_function(f1),E_c_builtin_function(f2)->comparef1f2|E_c_builtin_call(f1,args1),E_c_builtin_call(f2,args2)->Compare.paircompare(Compare.listcompare_expr)(f1,args1)(f2,args2)|E_c_arrow_access(p1,i1,f1),E_c_arrow_access(p2,i2,f2)->Compare.triplecompare_exprcomparecompare(p1,i1,f1)(p2,i2,f2)|E_c_assign(x1,e1),E_c_assign(x2,e2)->Compare.paircompare_exprcompare_expr(x1,e1)(x2,e2)|E_c_compound_assign(lval1,t1,op1,rval1,tt1),E_c_compound_assign(lval2,t2,op2,rval2,tt2)->Compare.compose[(fun()->compare_exprlval1lval2);(fun()->compare_typt1t2);(fun()->compare_operatorop1op2);(fun()->compare_exprrval1rval2);(fun()->compare_typtt1tt2);]|E_c_comma(e1,ee1),E_c_comma(e2,ee2)->Compare.paircompare_exprcompare_expr(e1,ee1)(e2,ee2)|E_c_increment(dir1,loc1,e1),E_c_increment(dir2,loc2,e2)->Compare.triplecomparecomparecompare_expr(dir1,loc1,e1)(dir2,loc2,e2)|E_c_address_of(e1),E_c_address_of(e2)->compare_expre1e2|E_c_deref(e1),E_c_deref(e2)->compare_expre1e2|E_c_cast(e1,b1),E_c_cast(e2,b2)->Compare.paircompare_exprcompare(e1,b1)(e2,b2)|E_c_statement(s1),E_c_statement(s2)->compare_stmts1s2|E_c_predefined(s1),E_c_predefined(s2)->compares1s2|E_c_var_args(e1),E_c_var_args(e2)->compare_expre1e2|E_c_atomic(op1,e1,ee1),E_c_atomic(op2,e2,ee2)->Compare.triplecomparecompare_exprcompare_expr(op1,e1,ee1)(op2,e2,ee2)|E_c_block_object(e1),E_c_block_object(e2)->compare_expre1e2|_->nexte1e2)(**************************)(** Statement comparison **)(**************************)letreccompare_c_var_initi1i2=matchi1,i2with|C_init_expre1,C_init_expre2->compare_expre1e2|C_init_list(l1,o1),C_init_list(l2,o2)->Compare.compose[(fun()->Compare.listcompare_c_var_initl1l2);(fun()->Compare.optioncompare_c_var_inito1o2)]|C_init_implicitt1,C_init_implicitt2->compare_typt1t2|_->Stdlib.comparei1i2letcompare_c_fundecf1f2=Compare.compose[(fun()->Stdlib.comparef1.c_func_uidf2.c_func_uid);(fun()->Stdlib.comparef1.c_func_unique_namef2.c_func_unique_name)]letcompare_c_var_scopes1s2=matchs1,s2with|Variable_localf1,Variable_localf2|Variable_parameterf1,Variable_parameterf2|Variable_func_staticf1,Variable_func_staticf2->compare_c_fundecf1f2|_->Stdlib.compares1s2letcompare_c_var_scope_updates1s2=Compare.compose[(fun()->Compare.listcompare_vars1.c_scope_var_addeds2.c_scope_var_added);(fun()->Compare.listcompare_vars1.c_scope_var_removeds2.c_scope_var_removed)]let()=register_stmt_compare(funnexts1s2->matchskinds1,skinds2with|S_c_goto_stab(s1),S_c_goto_stab(s2)->compare_stmts1s2|S_c_declaration(v1,i1,s1),S_c_declaration(v2,i2,s2)->Compare.compose[(fun()->compare_varv1v2);(fun()->Compare.optioncompare_c_var_initi1i2);(fun()->compare_c_var_scopes1s2)]|S_c_do_while(s1,e1),S_c_do_while(s2,e2)->Compare.compose[(fun()->compare_stmts1s2);(fun()->compare_expre1e2)]|S_c_for(init1,cond1,incr1,body1),S_c_for(init2,cond2,incr2,body2)->Compare.compose[(fun()->compare_stmtinit1init2);(fun()->Compare.optioncompare_exprcond1cond2);(fun()->Compare.optioncompare_exprincr1incr2);(fun()->compare_stmtbody1body2)]|S_c_return(e1,s1),S_c_return(e2,s2)->Compare.compose[(fun()->Compare.optioncompare_expre1e2);(fun()->compare_c_var_scope_updates1s2)]|S_c_break(s1),S_c_break(s2)|S_c_continue(s1),S_c_continue(s2)->compare_c_var_scope_updates1s2|S_c_goto(l1,s1),S_c_goto(l2,s2)->Compare.compose[(fun()->comparel1l2);(fun()->compare_c_var_scope_updates1s2)]|S_c_switch(e1,s1),S_c_switch(e2,s2)->Compare.compose[(fun()->compare_expre1e2);(fun()->compare_stmts1s2)]|S_c_label(l1),S_c_label(l2)->Stdlib.comparel1l2|S_c_switch_case(e1,s1),S_c_switch_case(e2,s2)->Compare.compose[(fun()->Compare.listcompare_expre1e2);(fun()->compare_c_var_scope_updates1s2)]|S_c_switch_default(s1),S_c_switch_default(s2)->compare_c_var_scope_updates1s2|_->nexts1s2)letrange_conde_mintrminrmaxrange=letcondle=mk_binope_mintO_le(mk_zrmaxrange)~etyp:T_boolrangeinletcondge=mk_binope_mintO_ge(mk_zrminrange)~etyp:T_boolrangeinmk_binopcondleO_log_andcondge~etyp:T_boolrangeletrecremove_castse=matchekindewith|E_c_cast(e',_)->remove_castse'|_->e(** Simplify C constant expressions to constants *)letrecc_expr_to_z(e:expr)flow:Z.toption=matchekindewith|E_constant(C_intn)->Somen|E_constant(C_c_character(ch,_))->Somech|E_unop(O_minus,e')->c_expr_to_ze'flow|>OptionExt.bind@@funn->Some(Z.negn)|E_unop(O_bit_invert,e')->c_expr_to_ze'flow|>OptionExt.bind@@funn->Some(Z.lognotn)|E_unop(O_log_not,e')->c_expr_to_ze'flow|>OptionExt.bind@@funn->ifZ.equalnZ.zerothenSomeZ.oneelseSomeZ.zero|E_binop(O_c_and,e1,e2)->c_expr_to_ze1flow|>OptionExt.bind@@funn1->ifZ.equaln1Z.zerothenSomeZ.zeroelsec_expr_to_ze2flow|E_binop(O_c_or,e1,e2)->c_expr_to_ze1flow|>OptionExt.bind@@funn1->ifZ.equaln1Z.zerothenc_expr_to_ze2flowelseSomeZ.one|E_binop(op,e1,e2)->c_expr_to_ze1flow|>OptionExt.bind@@funn1->c_expr_to_ze2flow|>OptionExt.bind@@funn2->beginmatchopwith|O_plus->Some(Z.addn1n2)|O_minus->Some(Z.subn1n2)|O_mult->Some(Z.muln1n2)|O_div->ifZ.equaln2Z.zerothenNoneelseSome(Z.divn1n2)|O_bit_lshift->begintrySome(Z.shift_leftn1(Z.to_intn2))with_->Noneend|O_bit_rshift->begintrySome(Z.shift_rightn1(Z.to_intn2))with_->Noneend|O_bit_and->Some(Z.logandn1n2)|O_bit_or->Some(Z.logorn1n2)|O_eq->Some(ifZ.equaln1n2thenZ.oneelseZ.zero)|O_ne->Some(ifZ.equaln1n2thenZ.zeroelseZ.one)|O_gt->Some(ifZ.gtn1n2thenZ.oneelseZ.zero)|O_ge->Some(ifZ.geqn1n2thenZ.oneelseZ.zero)|O_lt->Some(ifZ.ltn1n2thenZ.oneelseZ.zero)|O_le->Some(ifZ.leqn1n2thenZ.oneelseZ.zero)|_->Noneend|E_c_conditional(cond,e1,e2)->c_expr_to_zcondflow|>OptionExt.bind@@func->ifnot(Z.equalcZ.zero)thenc_expr_to_ze1flowelsec_expr_to_ze2flow|E_c_cast(ee,_)whenis_c_int_typee.etyp->c_expr_to_zeeflow|>OptionExt.bind@@funn->leta,b=rangeofe.etypflowinifZ.leqan&&Z.leqnbthenSomenelseNone|_->Noneletis_c_expr_equals_zezflow=matchc_expr_to_zeflowwith|None->false|Somen->Z.equalnzletis_c_constanteflow=matchc_expr_to_zeflowwith|None->false|Some_->trueletrecis_c_lvale=matchekindewith|E_var_|E_c_deref_|E_c_array_subscript_|E_c_member_access_|E_c_arrow_access_->true|Stubs.Ast.E_stub_primedee->is_c_lvalee|_->falseletis_c_derefe=matchremove_castse|>ekindwith|E_c_deref_->true|_->falseletget_c_deref_typee=matchremove_castse|>ekindwith|E_c_derefp->under_typep.etyp|_->assertfalse(** Check if v is declared as a variable length array *)letis_c_variable_length_array_typet=matchremove_typedef_qualtwith|T_c_array(_,C_array_length_expr_)->true|_->false(** Check if v is declared as an array without length (as for many auxiliary variables) *)letis_c_no_length_array_typet=matchremove_typedef_qualtwith|T_c_array(_,C_array_no_length)->true|_->false(** Find the definition of a C function *)letfind_c_fundec_by_namenameflow=letprog=get_c_programflowinList.find(funf->f.c_func_org_name=name)prog.c_functionsletfind_c_fundec_by_uiduidflow=letprog=get_c_programflowinList.find(funf->f.c_func_uid=uid)prog.c_functions(** Check if a pointer points to a nul-terminated array *)letassert_valid_string(p:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_assert_valid_string"flowinletstmt=mk_c_call_stmtf[p]rangeinman.execstmtflow(** Check if a pointer points to a nul-terminated wide char array *)letassert_valid_wide_string(p:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_assert_valid_wide_string"flowinletstmt=mk_c_call_stmtf[p]rangeinman.execstmtflow(** Check if a pointer points to a valid stream *)letassert_valid_stream(p:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_assert_valid_stream"flowinletstmt=mk_c_call_stmtf[p]rangeinman.execstmtflow(** Check if a pointer points to a valid file descriptor *)letassert_valid_file_descriptor(p:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_assert_valid_file_descriptor"flowinletstmt=mk_c_call_stmtf[p]rangeinman.execstmtflow(** Check if a pointer is valid *)letassert_valid_ptr(p:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_assert_valid_ptr"flowinletstmt=mk_c_call_stmtf[p]rangeinman.execstmtflow(** Randomize an entire array *)letmemrand(p:expr)(i:expr)(j:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_memrand"flowinletstmt=mk_c_call_stmtf[p;i;j]rangeinman.execstmtflow(** Randomize a string *)letstrrand(p:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_strrand"flowinletstmt=mk_c_call_stmtf[p]rangeinman.execstmtflow(** Randomize a substring *)letstrnrand(p:expr)(n:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_strnrand"flowinletstmt=mk_c_call_stmtf[p;n]rangeinman.execstmtflow(** Randomize a wide substring *)letwcsnrand(p:expr)(n:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_wcsnrand"flowinletstmt=mk_c_call_stmtf[p;n]rangeinman.execstmtflow(** Set elements of an array with the same value [c] *)letmemset(p:expr)(c:expr)(i:expr)(j:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_memset"flowinletstmt=mk_c_call_stmtf[p;c;i;j]rangeinman.execstmtflow(** Copy elements of an array *)letmemcpy(dst:expr)(src:expr)(i:expr)(j:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_memcpy"flowinletstmt=mk_c_call_stmtf[dst;src;i;j]rangeinman.execstmtflow(** Exit if status is non-zero *)leterror_error(p:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_error"flowinletstmt=mk_c_call_stmtf[p]rangeinman.execstmtflow(** Exit if status is non-zero *)leterror_error_at_line(p:expr)(n:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_error_at_line"flowinletstmt=mk_c_call_stmtf[p;n]rangeinman.execstmtflowletasprintf_stub(dst:expr)rangemanflow=letf=find_c_fundec_by_name"_mopsa_asprintf"flowinletexp=mk_c_callf[dst]rangeinman.evalexpflowletvasprintf_stubis_constant_stringformat(dst:expr)rangemanflow=letf=ifis_constant_stringthen"_mopsa_constant_vasprintf"else"_mopsa_general_vasprintf"inletf=find_c_fundec_by_namefflowinletexp=mk_c_callf(dst::format::[])rangeinman.evalexpflow(********************)(** Stack variables *)(********************)(** This vkind is used to attach the callstack to local variables *)typevar_kind+=V_c_stack_varofcallstack*var(** Create a stack variable *)letmk_stack_varcsv=matchvkindvwith|V_c_stack_var_->v|_->letuniq_name=Format.asprintf"stack(%a, %s)"pp_callstack_shortcsv.vnameinmkvuniq_name(V_c_stack_var(cs,v))v.vtyplet()=register_var{print=(funnextfmtv->matchvkindvwith|V_c_stack_var(cs,vv)->pp_varfmtvv|_->nextfmtv);compare=(funnextv1v2->matchvkindv1,vkindv2with|V_c_stack_var(cs1,vv1),V_c_stack_var(cs2,vv2)->Compare.paircompare_callstackcompare_var(cs1,vv1)(cs2,vv2)|_->nextv1v2);}letrecvar_scopev=matchv.vkindwith|V_cvar{cvar_scope}->cvar_scope|V_c_stack_var(_,vv)->var_scopevv|_->assertfalse