123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(**
C_utils - Utilities to access the simple C AST
*)openC_ASTopenC_printopenMopsa_utilsmoduleC=structincludeClang_ASTincludeClang_dumpend(** {2 Debug} *)letlog_type_unify=reffalse(** verbose logging during type unification, for debugging *)letlog_type_compare=false(** verbose logging during type comparison, for debugging *)(** {2 Location utilities} *)letrange_of_blockb=ifb=[]theninvalid_arg"range_of_block: empty block";{C.range_begin=(ListExt.hdb).C.range_begin;C.range_end=(ListExt.lastb).C.range_end;}(** From the begining of the first block statement to the end of the last block statement.
Raises Invalid_argument for empty blocks.
*)(** {2 Size and alignment} *)letsizeof_inttargett:int=matchtwith|Char_|UNSIGNED_CHAR|SIGNED_CHAR->1|SIGNED_SHORT|UNSIGNED_SHORT->target.C.target_short_width/8|SIGNED_INT|UNSIGNED_INT->target.C.target_int_width/8|SIGNED_LONG|UNSIGNED_LONG->target.C.target_long_width/8|SIGNED_LONG_LONG|UNSIGNED_LONG_LONG->target.C.target_long_long_width/8|SIGNED_INT128|UNSIGNED_INT128->128/8(** Size (in bytes) of an integer type. *)letalignof_inttargett:int=matchtwith|Char_|UNSIGNED_CHAR|SIGNED_CHAR->1|SIGNED_SHORT|UNSIGNED_SHORT->target.C.target_short_align/8|SIGNED_INT|UNSIGNED_INT->target.C.target_int_align/8|SIGNED_LONG|UNSIGNED_LONG->target.C.target_long_align/8|SIGNED_LONG_LONG|UNSIGNED_LONG_LONG->target.C.target_long_long_align/8|SIGNED_INT128|UNSIGNED_INT128->128/8(** Alignment (in bytes) of an integer type. *)letsignedness_intt=matchtwith|Chars->s|SIGNED_CHAR|SIGNED_SHORT|SIGNED_INT|SIGNED_LONG|SIGNED_LONG_LONG|SIGNED_INT128->SIGNED|UNSIGNED_CHAR|UNSIGNED_SHORT|UNSIGNED_INT|UNSIGNED_LONG|UNSIGNED_LONG_LONG |UNSIGNED_INT128->UNSIGNED(** Signedness of an integer type. *)letsizeof_floattargett:int=matchtwith|FLOAT16->2|FLOAT->target.C.target_float_width/8|DOUBLE->target.C.target_double_width/8|LONG_DOUBLE->target.C.target_long_double_width/8|FLOAT128->target.C.target_float128_width/8(** Size (in bytes) of a float type. *)letalignof_floattargett:int=matchtwith|FLOAT16->2|FLOAT->target.C.target_float_align/8|DOUBLE->target.C.target_double_align/8|LONG_DOUBLE->target.C.target_long_double_align/8|FLOAT128->target.C.target_float128_align/8(** Alignment (in bytes) of a float type. *)letrecsizeof_typetargett:Z.t=matchtwith|T_void->invalid_arg"sizeof_type: size of void"|T_bool->Z.of_int(target.C.target_bool_width/8)|T_integeri->Z.of_int(sizeof_inttargeti)|T_floatf->Z.of_int(sizeof_floattargetf)|T_complexf->Z.of_int(2*(sizeof_floattargetf))|T_pointer_->Z.of_int(target.C.target_pointer_width/8)|T_array((t,_),Length_cstlen)->Z.mullen(sizeof_typetargett)|T_array_->invalid_arg"sizeof_type: size of array with unknown size"|T_bitfield(t,_)->invalid_arg"sizeof_type: size of bitfield"|T_function_|T_builtin_fn->invalid_arg"sizeof_type: size of function"|T_typedeft->sizeof_typetarget(fstt.typedef_def)|T_recordr->ifnotr.record_definedtheninvalid_arg"sizeof_type: size of incomplete record";r.record_sizeof|T_enume->ifnote.enum_definedtheninvalid_arg"sizeof_type: size of incomplete enum";Z.of_int(sizeof_inttarget(matche.enum_integer_typewith|Somes->s|None->assertfalse))|T_vectorv->v.vector_sizeof|T_unknown_builtin_->Z.zero|T_attributed(t,_)->sizeof_typetargett(** Size (in bytes) of a type. Raises an Invalid_argument if the size is not a constant. *)letsizeof_exprtarget(range:C.range)(result_type:type_qual)(t:typ):expr=letrecdoitt=matchtwith|T_void->invalid_arg"sizeof_expr: size of void"|T_bool|T_integer_|T_float_|T_pointer_|T_record_|T_enum_|T_complex_|T_vector_->E_integer_literal(sizeof_typetargett),result_type,range|T_array((t,_),l)->letlen=matchlwith|Length_cstlen->E_integer_literallen,result_type,range|Length_expre->e|No_length->(* TODO: fix *)(* error range "sizeof" "array with no size"*)E_integer_literalZ.zero,result_type,rangeinE_binary(O_arithmeticMUL,doitt,len),result_type,range|T_bitfield(t,_)->invalid_arg"sizeof_expr: size of bitfield"|T_function_|T_builtin_fn->invalid_arg"sizeof_expr: size of function"|T_typedeft->doit(fstt.typedef_def)|T_unknown_builtin_->E_integer_literal(Z.zero),result_type,range|T_attributed(t,_)->doittindoitt(** Size (in bytes) of a type, as an expression. Handles variable-length ararys. *)letrecalignof_typetargett:Z.t=matchtwith|T_void->invalid_arg"alignof_type: align of void"|T_bool->Z.of_int(target.C.target_bool_align/8)|T_integeri->Z.of_int(alignof_inttargeti)|T_floatf|T_complexf->Z.of_int(alignof_floattargetf)|T_pointer_->Z.of_int(target.C.target_pointer_align/8)|T_array((t,_),_)->alignof_typetargett|T_bitfield(t,_)->invalid_arg"alignof_type: align of bitfield"|T_function_|T_builtin_fn->invalid_arg"alignof_type: align of function"|T_typedeft->alignof_typetarget(fstt.typedef_def)|T_recordr->ifnotr.record_definedtheninvalid_arg"alignof_type: size of incomplete record";r.record_alignof|T_enume->ifnote.enum_definedtheninvalid_arg"alignof_type: size of incomplete enum";Z.of_int(alignof_inttarget(matche.enum_integer_typewith|Somes->s|None->assertfalse))|T_vectorv->alignof_typetarget(fstv.vector_type)|T_unknown_builtin_->Z.zero|T_attributed(t,_)->alignof_typetargett(** Alignment (in bytes) of a type. *)letrectype_declarable=function|T_void->false|T_bool|T_integer_|T_float_|T_complex_->true|T_pointer_->true|T_array(t,len)->len<>No_length&&type_qual_declarablet|T_bitfield(t,_)->type_declarablet|T_functionf->false|T_builtin_fn->false|T_typedeft->type_qual_declarablet.typedef_def|T_recordr->r.record_defined|T_enume->e.enum_defined|T_vectorv->type_declarable(fstv.vector_type)|T_unknown_builtin_->true|T_attributed(t,_)->type_declarabletandtype_qual_declarable(t,q)=type_declarablet(** Whether we can declare a variable of this type (sizeof defined). *)(** {2 Useful target-specific types} *)lettarget_int=function|C.Target_NoInt->invalid_arg"target_int: NoInt"|C.Target_SignedChar->SIGNED_CHAR|C.Target_UnsignedChar->UNSIGNED_CHAR|C.Target_SignedShort->SIGNED_SHORT|C.Target_UnsignedShort->UNSIGNED_SHORT|C.Target_SignedInt->SIGNED_INT|C.Target_UnsignedInt->UNSIGNED_INT|C.Target_SignedLong->SIGNED_LONG|C.Target_UnsignedLong->UNSIGNED_LONG|C.Target_SignedLongLong->SIGNED_LONG_LONG|C.Target_UnsignedLongLong->UNSIGNED_LONG_LONG(** Converts target int to SAST int types. *)letsize_typetarget=target_inttarget.C.target_size_typeletintmax_typetarget=target_inttarget.C.target_intmax_typeletptrdiff_typetarget=target_inttarget.C.target_ptrdiff_typeletintptr_typetarget=target_inttarget.C.target_intptr_typeletint64_typetarget=target_inttarget.C.target_int64_typeletwchar_typetarget=target_inttarget.C.target_wchar_typeletwint_typetarget=target_inttarget.C.target_wint_typeletchar16_typetarget=target_inttarget.C.target_char16_typeletchar32_typetarget=target_inttarget.C.target_char32_typeletsigatomic_typetarget=target_inttarget.C.target_sigatomic_typeletprocessid_typetarget=target_inttarget.C.target_processid_type(** Base integer type of a derived integer type. *)(** {2 Comments} *)(** Ensure that comments are not duplicated. *)letcomment_unify(c1:commentlist)(c2:commentlist):commentlist=matchc1,c2with|[],x|x,[]->x|[a],[b]->ifa=bthen[a]else[a;b]|_->(* could be improved, but we expect the lists to have length 1 at most *)List.sort_uniqcompare(c1@c2)letcomment_macro_unify(c1:(comment*macroStringMap.t)list)(c2:(comment*macroStringMap.t)list):(comment*macroStringMap.t)list=matchc1,c2with|[],x|x,[]->x|[a],[b]->iffsta=fstbthen[a]else[a;b]|_->(* could be improved, but we expect the lists to have length 1 at most *)List.sort_uniq(funab->compare(fsta)(fstb))(c1@c2)(** {2 Attibutes} *)letattrs_unifya1a2=List.sort_uniq(funab->comparea.Clang_AST.attr_printb.Clang_AST.attr_print)(a1@a2)(** {2 Type compatibility} *)typetype_cmp={cmp_ignore_qual:bool;(** if true, type_compatible does not take qualifiers into account in comparison *)cmp_int_size:bool;(** if true, type_compatible use integer size and signess instead of name *)cmp_enum_as_int:bool;(** if true, type_compatible handles an enum as an its integer type *)cmp_ignore_name:bool;(** if true, type_compatible disregards type names in comparison *)cmp_ignore_undefined:bool;(** if true, an undefined enum, struct or union compares equal to a defined one *)cmp_ignore_typedef:bool;(** if true, a typedef is replaced with its defining type during comparison *)cmp_ignore_array_size:bool;(** if true, arrays with undefined size compare equal to that of defined size *)cmp_ignore_vector_size:bool;(** if true, the size of vector types is ignored in comparison *)cmp_ignore_vector_kind:bool;(** if true, the kind of vector types is ignored in comparison *)cmp_ignore_attributes:bool;(** if true, ignore attributes in comparison *)}(** Comfigures the test equality functions, to allow various relaxation. *)letcmp_compatible={cmp_ignore_qual=true;cmp_int_size=false;cmp_enum_as_int=false;cmp_ignore_name=false;cmp_ignore_undefined=true;cmp_ignore_typedef=true;cmp_ignore_array_size=true;cmp_ignore_vector_size=true;cmp_ignore_vector_kind=true;cmp_ignore_attributes=true;}(** Type compatibility. *)letcmp_unifiable={cmp_ignore_qual =true;cmp_int_size=false;cmp_enum_as_int=false;cmp_ignore_name=false;cmp_ignore_undefined=true;cmp_ignore_typedef=false;cmp_ignore_array_size =true;cmp_ignore_vector_size=true;cmp_ignore_vector_kind=true;cmp_ignore_attributes=true;}(** Unifiable compatibility. *)letcmp_equal={cmp_ignore_qual=false;cmp_int_size=false;cmp_enum_as_int=false;cmp_ignore_name=false;cmp_ignore_undefined=false;cmp_ignore_typedef=false;cmp_ignore_array_size=false;cmp_ignore_vector_size=false;cmp_ignore_vector_kind=false;cmp_ignore_attributes=false;}(** Strict type equality. *)letrectype_comparecmpgray(target:C.target_info)(t1:typ)(t2:typ)=iflog_type_comparethenPrintf.printf"type_compare: %s and %s\n"(string_of_typet1)(string_of_typet2);(t1==t2)||matcht1,t2with|T_void,T_void->true|T_bool,T_bool->true|T_integeri1,T_integeri2->ifcmp.cmp_int_sizethensizeof_inttargeti1=sizeof_inttargeti2&&signedness_int i1=signedness_inti2elsei1=i2|T_floatf1,T_floatf2->f1=f2|T_pointerp1,T_pointerp2->type_qual_comparecmpgraytargetp1p2|T_array(a1,l1),T_array(a2,l2)->type_qual_comparecmpgraytargeta1a2&&(matchl1,l2with|Length_cst c1,Length_cstc2->c1=c2|Length_expre1,Length_expre2->true(* TODO *)|No_length,No_length->true|No_length,_->cmp.cmp_ignore_array_size|_,No_length->cmp.cmp_ignore_array_size|_->false)|T_bitfield(t1,l1),T_bitfield(t2,l2)->type_comparecmpgraytargett1t2&&l1=l2|T_function(Somef1),T_function(Somef2)->type_qual_comparecmpgraytargetf1.ftype_returnf2.ftype_return&&List.lengthf1.ftype_params=List.lengthf2.ftype_params&&List.for_all2(type_qual_comparecmpgraytarget)f1.ftype_paramsf2.ftype_params&&f1.ftype_variadic=f2.ftype_variadic|T_functionNone,T_function_->true|T_function_,T_functionNone->true|T_builtin_fn,T_builtin_fn->true|T_typedeft1,_whencmp.cmp_ignore_typedef->type_comparecmpgraytarget(fstt1.typedef_def)t2|_,T_typedeft2whencmp.cmp_ignore_typedef->type_comparecmpgraytargett1(fstt2.typedef_def)|T_typedeft1,T_typedeft2->(cmp.cmp_ignore_name||t1.typedef_org_name =t2.typedef_org_name)&&type_qual_comparecmpgraytargett1.typedef_deft2.typedef_def|T_enume1,_whencmp.cmp_enum_as_int->(note1.enum_defined)||type_comparecmpgraytarget(T_integer(matche1.enum_integer_typewith|Somes->s|None->assertfalse))t2|_,T_enume2whencmp.cmp_enum_as_int->(note2.enum_defined)||type_comparecmpgraytargett1(T_integer(matche2.enum_integer_typewith|Somes->s|None->assertfalse))|T_enume1,T_enume2->(cmp.cmp_ignore_name||e1.enum_org_name=e2.enum_org_name)&&((cmp.cmp_ignore_undefined&&(note1.enum_defined||note2.enum_defined))||(List.lengthe1.enum_values=List.lengthe2.enum_values&&List.for_all2(funv1v2->v1.enum_val_org_name=v2.enum_val_org_name &&v1.enum_val_value=v2.enum_val_value)e1.enum_valuese2.enum_values))|T_recordr1,T_recordr2->ifHashtbl.memgray(r1.record_uid,r2.record_uid)thentrueelse(Hashtbl.addgray(r1.record_uid,r2.record_uid)();(cmp.cmp_ignore_name||r1.record_org_name=r2.record_org_name)&&(r1.record_kind=r2.record_kind)&&((cmp.cmp_ignore_undefined&&(notr1.record_defined||notr2.record_defined))||(Array.lengthr1.record_fields=Array.length r2.record_fields&&r1.record_sizeof=r2.record_sizeof&&letl1,l2=Array.to_listr1.record_fields,Array.to_listr2.record_fieldsinList.for_all2(funf1f2->(cmp.cmp_ignore_name||(f1.field_org_name=f2.field_org_name))&&f1.field_offset =f2.field_offset&&f1.field_bit_offset=f2.field_bit_offset&&type_qual_comparecmpgraytargetf1.field_typef2.field_type)l1l2)))|T_vectorv1,T_vectorv2->type_qual_comparecmpgraytargetv1.vector_typev2.vector_type&&(cmp.cmp_ignore_vector_size||v1.vector_size=v2.vector_size)&&(cmp.cmp_ignore_vector_kind||v1.vector_kind=v2.vector_kind)|T_unknown_builtins1,T_unknown_builtins2->s1=s2|T_attributed(t1,_),_whencmp.cmp_ignore_attributes->type_comparecmpgraytargett1t2|_,T_attributed(t2,_)whencmp.cmp_ignore_attributes ->type_comparecmpgraytargett1t2|T_attributed(t1,a1),T_attributed(t2,a2)->(type_comparecmpgraytargett1t2)&&(a1=a2)|_->falseandqual_comparecmp(q1:qualifier)(q2:qualifier)=cmp.cmp_ignore_qual||q1=q2andtype_qual_comparecmpgraytarget((t1,q1):type_qual)((t2,q2):type_qual)=type_comparecmpgraytarget t1t2&&qual_comparecmpq1q2(* internal functions passing along a set of gray nodes to avoid infinite loops on cyclic types *)lettype_compatiblectxab=type_comparecmp_compatible(Hashtbl.create16)ctxablettype_qual_compatiblectxab=type_qual_comparecmp_compatible(Hashtbl.create16)ctxab(** Type compatibility. Two declarations for the same object must have compatible types. *)lettype_equalctxab=type_comparecmp_equal(Hashtbl.create16)ctxablettype_qual_equalctxab=type_qual_comparecmp_equal(Hashtbl.create16)ctxab(** Strict type equality, to allow type merging. *)lettype_unifiablectxab=type_comparecmp_unifiable(Hashtbl.create16)ctxablettype_qual_unifiablectxab=type_qual_comparecmp_unifiable(Hashtbl.create16)ctxab(** Arguments are eligible to call type_unify. *)letrectype_unifygraytarget(t1:typ)(t2:typ)=if!log_type_unifythenPrintf.printf"type_unify: %s and %s\n"(string_of_typet1)(string_of_typet2);ift1==t2thent1elsematcht1,t2with|T_void,T_void->t1|T_bool,T_bool->t1|T_integeri1,T_integeri2->ifsizeof_int targeti1=sizeof_inttargeti2&&signedness_inti1=signedness_inti2thent1elseinvalid_arg(Printf.sprintf"type_unify: incompatible integer types %s and %s"(string_of_integer_typei1)(string_of_integer_typei2))|T_floatf1,T_floatf2->iff1<>f2theninvalid_arg(Printf.sprintf"type_unify: incompatible float types %s and %s"(string_of_float_typef1)(string_of_float_typef2))elset1|T_pointerp1,T_pointerp2->letp=type_qual_unifygraytargetp1p2inifp==p1thent1elseT_pointerp|T_array(a1,l1),T_array(a2,l2)->leta=type_qual_unifygraytargeta1a2inletl=matchl1,l2with|_,No_length->l1|No_length,_->l2|Length_cstc1,Length_cstc2whenc1=c2->l1|Length_expr _,Length_expr_->l1(* TODO: check expressions? *)|_->invalid_arg"type_unify: incompatible array length"inifa==a1&&l==l1thent1 elseT_array(a,l)|T_bitfield (b1,l1),T_bitfield(b2,l2)->letb=type_unifygraytargetb1b2inifl1<>l2theninvalid_arg(Printf.sprintf"type_unify: incompatible bitfield length %i and %i"l1l2);ifb==b1thent1elseT_bitfield(b,l1)|T_function_,T_functionNone->t1|T_functionNone,T_function_->t2|T_function(Somef1),T_function (Somef2)->letr=type_qual_unifygraytargetf1.ftype_returnf2.ftype_returninifList.lengthf1.ftype_params<>List.lengthf2.ftype_paramstheninvalid_arg(Printf.sprintf"type_unify: incompatible function parameter number %i and %i"(List.lengthf1.ftype_params)(List.lengthf2.ftype_params));leta=List.map2(type_qual_unifygraytarget)f1.ftype_paramsf2.ftype_paramsiniff1.ftype_variadic<>f2.ftype_variadictheninvalid_arg "type_unify: incompatible variadic function type";f1.ftype_return<-r;f2.ftype_return<-r;f1.ftype_params<-a;f2.ftype_params<-a;t1|T_builtin_fn,T_builtin_fn->t1|T_typedefd1,T_typedefd2->typedef_unifygraytargetd1d2;t1|T_typedefd1,_->lett=type_qual_unifygraytargetd1.typedef_def(t2,no_qual)ind1.typedef_def<-t;t1|_,T_typedefd2->lett=type_qual_unifygraytarget(t1,no_qual)d2.typedef_defind2.typedef_def<-t;t1|T_enume1,T_enume2->enum_unifygraytargete1e2;t1|T_recordr1,T_recordr2->record_unifygraytargetr1r2;t1|T_vectorv1,T_vectorv2->(* keep the minimum size and set kind to -1 if they differ *)(* TODO: is that correct? *)lett=type_qual_unifygraytargetv1.vector_typev2.vector_typeinletsize=minv1.vector_sizev2.vector_sizeinletsizeof=minv1.vector_sizeofv2.vector_sizeofinletkind=ifv1.vector_kind=v2.vector_kindthenv1.vector_kindelse-1inT_vector{vector_type=t;vector_size=size;vector_kind=kind;vector_sizeof=sizeof;}|T_unknown_builtins1,T_unknown_builtins2whens1=s2->T_unknown_builtins1|T_attributed(t1,a1),T_attributed(t2,a2)->(* TODO: merge attributes *)T_attributed(type_unifygraytargett1t2,a1)|T_attributed(t1,a),t2->T_attributed(type_unifygraytargett1t2,a)|t1,T_attributed (t2,a)->T_attributed (type_unifygraytargett1t2,a)|_->invalid_arg"type_unify: incompatible types"andtype_qual_unifygraytarget(t1,q1)(t2,q2)=type_unifygraytargett1t2,merge_qualifiersq1q2andtypedef_unifygraytargetd1d2=ifd1.typedef_org_name<>d2.typedef_org_nametheninvalid_arg("typedef_unify: incompatible typedef names: "^d1.typedef_org_name^" and "^d2.typedef_org_name);d1.typedef_attrs<-attrs_unifyd1.typedef_attrsd2.typedef_attrs;d2.typedef_attrs<-d1.typedef_attrs;lett=type_qual_unifygraytargetd1.typedef_defd2.typedef_defind1.typedef_def<-t;d2.typedef_def<-t;d2.typedef_unique_name<-d1.typedef_unique_name;letc=comment_unify d1.typedef_comd2.typedef_comind1.typedef_com<-c;d2.typedef_com<-candrecord_unifygraytargetr1r2=if!log_type_unifythenPrintf.printf"record_unify: %s and %s\n"(string_of_type(T_recordr1))(string_of_type(T_recordr2));ifHashtbl.memgray(r1.record_uid,r2.record_uid)then()else(Hashtbl.addgray(r1.record_uid,r2.record_uid)();ifr1.record_org_name<>r2.record_org_nametheninvalid_arg(Printf.sprintf "record_unify: incompatible record names %s and %s"r1.record_org_namer2.record_org_name);ifr1.record_kind<>r2.record_kind;theninvalid_arg"record_unify: incompatible record kinds";r1.record_attrs<-attrs_unifyr1.record_attrs r2.record_attrs;r2.record_attrs<-r1.record_attrs;(matchr1.record_defined&&r1.record_sizeof<>Z.zero,r2.record_defined&&r2.record_sizeof<>Z.zerowith|true,false->fori=0toArray.lengthr2.record_fields-1doletf1,f2=r1.record_fields.(i),r2.record_fields.(i)iniff1.field_org_name <>f2.field_org_name||not(type_qual_unifiable targetf1.field_typef2.field_type)theninvalid_arg"record_unify: incompatible record layout"done;r2.record_uid<-r1.record_uid;r2.record_unique_name<-r1.record_unique_name;r2.record_defined<-true;r2.record_sizeof<-r1.record_sizeof;r2.record_alignof<-r1.record_alignof;r2.record_fields<-r1.record_fields;r2.record_range<-r1.record_range|false,true->fori=0toArray.lengthr1.record_fields-1doletf1,f2=r1.record_fields.(i),r2.record_fields.(i)iniff1.field_org_name<>f2.field_org_name||not(type_qual_unifiabletargetf1.field_typef2.field_type)theninvalid_arg"record_unify: incompatible record layout"done;r1.record_uid<-r2.record_uid;r1.record_unique_name<-r2.record_unique_name;r1.record_defined<-true;r1.record_sizeof<-r2.record_sizeof;r1.record_alignof<-r2.record_alignof;r1.record_fields<-r2.record_fields;r1.record_range<-r2.record_range|true,true->ifr1.record_sizeof<>r2.record_sizeofthen(invalid_arg("record_unify: incompatible record sizeof "^(Z.to_stringr1.record_sizeof)^" and "^(Z.to_stringr2.record_sizeof)));ifr1.record_alignof<>r2.record_alignofthen invalid_arg"record_unify: incompatible record alignof";ifnot(Array.lengthr1.record_fields=Array.lengthr2.record_fields)theninvalid_arg(Printf.sprintf"record_unify: incompatible record field numbers %i and %i"(Array.lengthr1.record_fields)(Array.lengthr2.record_fields));fori=0toArray.lengthr1.record_fields-1doletf1,f2=r1.record_fields.(i),r2.record_fields.(i)iniff1.field_org_name<>f2.field_org_name||f1.field_offset<>f2.field_offset||f1.field_bit_offset<>f2.field_bit_offsettheninvalid_arg"record_unify: incompatible record layout";lett=type_qual_unifygraytargetf1.field_typef2.field_typeinf1.field_type<-t;f2.field_type<-t;letc=comment_unifyf1.field_comf2.field_cominf1.field_com<-c;f2.field_com <-c;f1.field_attrs<-attrs_unifyf1.field_attrsf2.field_attrs;f2.field_attrs<-f1.field_attrsdone|false,false->());letc=comment_unifyr1.record_comr2.record_cominr1.record_com<-c;r2.record_com<-c)andenum_unifygraytargete1e2=e1.enum_attrs<-attrs_unifye1.enum_attrse2.enum_attrs;e2.enum_attrs<-e1.enum_attrs;ife1.enum_org_name<>e2.enum_org_nametheninvalid_arg"enum_unify: incompatible enum names";(matche1.enum_defined,e2.enum_definedwith|true,false ->e2.enum_uid<-e1.enum_uid;e2.enum_unique_name<-e1.enum_unique_name;e2.enum_defined<-true;e2.enum_values<-e1.enum_values;e2.enum_integer_type<-e1.enum_integer_type;e2.enum_range<-e1.enum_range|false,true->e1.enum_uid<-e2.enum_uid;e1.enum_unique_name <-e2.enum_unique_name;e1.enum_defined<-true;e1.enum_values<-e2.enum_values;e1.enum_integer_type<-e2.enum_integer_type;e1.enum_range<-e2.enum_range|true,true->letenum_integer_type=matche1.enum_integer_type,e2.enum_integer_typewith|None,Somer->Somer|Somel,None->Somel|None,None->None|Somel,Somer->Some(matchtype_unifygraytarget(T_integer l)(T_integerr)with|T_integert->t|_->assertfalse)ine1.enum_integer_type<-enum_integer_type;e2.enum_integer_type<-enum_integer_type;ifnot(List.lengthe1.enum_values=List.lengthe2.enum_values&&List.for_all2(funv1v2->v1.enum_val_org_name=v2.enum_val_org_name &&v1.enum_val_value=v2.enum_val_value)e1.enum_valuese2.enum_values)theninvalid_arg"enum_unify: incompatible enum values";List.iter2(funv1v2->letc=comment_unifyv1.enum_val_comv2.enum_val_cominv1.enum_val_com<-c;v2.enum_val_com<-c;v1.enum_val_attrs<-attrs_unifyv1.enum_val_attrsv2.enum_val_attrs;v2.enum_val_attrs<-v1.enum_val_attrs)e1.enum_valuese2.enum_values|false,false->());letc=comment_unifye1.enum_come2.enum_comine1.enum_com<-c;e2.enum_com <-clettype_unify=type_unify(Hashtbl.create16)lettype_unify_qual=type_qual_unify(Hashtbl.create16)letenum_unifytargete1e2=enum_unify(Hashtbl.create16)targete1e2;e1letrecord_unifytargetr1r2=record_unify(Hashtbl.create16)targetr1r2;r1lettypedef_unifytargetd1d2=typedef_unify(Hashtbl.create16)targetd1d2;d1(** Type unification. *)letrecis_void((t,_):type_qual)=matchtwith|T_void ->true|T_typedeft->is_voidt.typedef_def|_->false(** {2 Expressions utilities} *)letexpr_type((_,t,_):expr)=t(** Type of an expression. *)letexpr_integer_cstrange(t:integer_type)(cst:Z.t):expr=E_integer_literalcst,(T_integert,no_qual),rangeletexpr_float_cstrange(t:float_type)(cst:float):expr=E_float_literal(string_of_floatcst),(T_floatt,no_qual),rangeletexpr_complex_cst range(t:float_type)(cst:float):expr=E_float_literal(string_of_floatcst),(T_complext,no_qual),rangeletexpr_int_zerorange:expr=expr_integer_cstrangeSIGNED_INTZ.zeroletexpr_int_onerange:expr=expr_integer_cstrangeSIGNED_INTZ.oneletexpr_double_zerorange:expr=expr_float_cstrangeDOUBLE0.letexpr_bool_truerange:expr=E_cast(expr_int_onerange,IMPLICIT),(T_bool,no_qual),rangeletexpr_bool_falserange:expr=E_cast(expr_int_zerorange,IMPLICIT),(T_bool,no_qual),rangeletexpr_nullrange:expr=E_cast(expr_int_zerorange,IMPLICIT),(T_bool,no_qual),range(** (void* )0 *)letexpr_voidrange:expr=E_cast(expr_int_zerorange,IMPLICIT),(T_void,no_qual),range(** (void)0 *)letreczero_initrange(t:typ):init=matchtwith|T_void->invalid_arg"zero_init: void type"|T_bool->I_init_expr(expr_bool_falserange)|T_integeri->I_init_expr(expr_integer_cstrangeiZ.zero)|T_floatf->I_init_expr(expr_float_cstrangef0.)|T_complexf->I_init_expr(expr_complex_cstrangef0.)|T_pointertq->I_init_expr(expr_nullrange)|T_array((t,_),_)->I_init_list([],Some(zero_init ranget))|T_bitfield(t,_)->zero_initranget|T_function_|T_builtin_fn->invalid_arg"zero_init: function type"|T_typedeft->zero_initrange(fstt.typedef_def)|T_recordr->letl=ifr.record_kind =UNION&&r.record_fields<>[||]then[r.record_fields.(0)]elseArray.to_listr.record_fieldsinI_init_list(List.map(funf->zero_initrange(fstf.field_type))l,None)|T_enume->I_init_expr(expr_integer_cstrange(matche.enum_integer_typewith|Somes->s|None->assertfalse)Z.zero)|T_vectorv->I_init_list ([],Some(zero_initrange(fstv.vector_type)))|T_unknown_builtin_->I_init_expr(expr_integer_cstrangeSIGNED_INTZ.zero)|T_attributed(t,_)->zero_initranget(** {2 Statement utilities} *)letmake_block(s:statementlist):block=letv=(* local variables declared in s, but not in sub-blocks *)ListExt.map_filter(function(S_local_declarationv,_)->Somev|_->None)sin{blk_stmts=s;blk_local_vars=v;}(** Creates a block from a list of statements.
Computes the list of local variables declared in the block and not
in sub-blocks.
*)moduleVarSet=SetExt.Make(structtypet=variableletcompareab=comparea.var_uidb.var_uidend)letresolve_scope(b:block):block=letgotos=ref[]andlabels=Hashtbl.create16in(* update a scope updated, give source and destination scopes *)letupdateusrcdst=u.scope_var_added<-VarSet.elements(VarSet.diffdstsrc);u.scope_var_removed<-VarSet.elements(VarSet.diffsrcdst)in(* iterate on statements and expressions;
fix break/continue/return scope;
goto/switch scope are fixed after the iteration
*)letrecstmt((cur,brk,cnt,swt)asctx)(s,r)=matchswith|S_local_declaration_->()|S_expressione->exprctxe|S_blockb->blockctxb|S_if(e,b1,b2)->exprctxe;blockctxb1;blockctxb2|S_while(e,b)|S_do_while(b,e)->(* new scope for break and continue *)letctx=cur,cur,cur,swtinexprctxe;blockctxb|S_for(i,eo1,eo2,b)->blockctxi;(* add the for init variable (if any) to the scope of the for *)letcur=VarSet.unioncur(VarSet.of_listi.blk_local_vars)in(* new scope for break and continue *)letctx=cur,cur,cur,swtinexpr_optctxeo1;expr_optctxeo2;blockctxb|S_jump(S_goto(label,upd))->(* remember gotos to fix them later *)gotos:=(label,r,upd,cur)::(!gotos)|S_jump(S_breakupd)->(* jump from current to break scope *)updateupdcurbrk|S_jump(S_continueupd)->(* jump from current to continue scope *)updateupdcurcnt|S_jump(S_return(_,upd))->(* jump from current to function return (empty scope) *)updateupdcurVarSet.empty|S_jump(S_switch(e,b))->exprctxe;(* new scope for break, remember the scope at switck for cases *)letctx=cur,cur,cnt,curinblockctxb|S_target(S_labellabel)->(* remember label scopes to fix gotos later *)Hashtbl.addlabelslabel cur|S_target(S_case(es,upd))->List.iter(exprctx)es;(* jump from switch point to current scope *)updateupdswtcur|S_target(S_defaultupd)->(* jump from switch point to current scope *)updateupdswtcur|S_asm_->()|S_attributed(s,_)->stmtctxsandblock(cur,brk,cnt,swt)b=List.fold_left(funcursr->stmt(cur,brk,cnt,swt)sr;(* add declated local variables to the scope along the way *)letcur=matchfstsrwith|S_local_declarationv->VarSet.addvcur|_->curincur)curb.blk_stmts|>ignoreandexprctx(e,_,_)=matchewith|E_conditional (e1,e2,e3)->List.iter(exprctx)[e1;e2;e3]|E_binary_conditional(e1,e2)|E_array_subscript(e1,e2)|E_compound_assign(e1,_,_,e2,_)|E_binary(_,e1,e2)|E_assign(e1,e2)|E_comma(e1,e2)|E_atomic(_,e1,e2)->List.iter(exprctx)[e1;e2]|E_member_access(e1,_,_)|E_arrow_access(e1,_,_)|E_unary(_,e1)|E_increment(_,_,e1)|E_address_ofe1|E_derefe1|E_cast(e1,_)|E_var_argse1->exprctxe1|E_call(e,el)->exprctxe;Array.iter(exprctx)el|E_character_literal_|E_integer_literal_|E_float_literal_|E_string_literal_|E_compound_literal_|E_null_ptr|E_variable_|E_function_|E_predefined_->()|E_statementb->blockctxb|E_convert_vectore->exprctxe|E_vector_element(e,_)->exprctxe|E_shuffle_vectorea->Array.iter(exprctx)eaandexpr_optctxeo=matcheowith|None->()|Somee->exprctxein(* update block in-place *)lete=VarSet.emptyinblock(e,e,e,e)b;(* fix goto *)List.iter(fun(lbl,range,upd,src)->tryletdst=Hashtbl.findlabelslblinupdateupdsrcdstwithNot_found->failwith(Printf.sprintf"%s: unknown label '%s'"(Clang_dump.string_of_rangerange)lbl))!gotos;(* return the block *)b(** Fill-in scope_update information in the AST.
The block is modified in-place, and returned.
Call after AST transformations that may change variable scopes.
*)(** {2 Errors} *)leterrorrangemsgarg=failwith(Printf.sprintf"%s: %s: %s"(C.string_of_rangerange)msgarg)letwarningrangemsgarg=(* Printf.eprintf "WARNING %s: %s: %s\n" (C.string_of_range range) msg arg *)()