123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Alarms for C runtime errors *)openMopsaopenFormatopenUniversal.Numeric.CommonopenUniversal.AstopenBaseopenAst(** {2 Utility print functions} *)(** *************************** *)(** Print an interval depending on its cardinal *)letpp_const_or_intervalfmtitv=matchitvwith|Bot.Nb(l,u)whenI.B.eqlu->I.B.fprintfmtl|_->I.fprint_botfmtitv(** Print the not-member operator of an interval, depending on its cardinal *)letpp_const_or_interval_not_eqfmtitv=matchitvwith|Bot.Nb(l,u)whenI.B.eqlu->fprintffmt"∉"|_->fprintffmt"⊈"letpp_interval_plurialfmtitv=matchitvwith|Bot.Nb(I.B.Finitel,I.B.Finiteu)whenZ.(l=u)&&Z.(l=one)->()|_->fprintffmt"s"letpp_interval_cardinal_plurialfmtitv=matchitvwith|Bot.Nb(I.B.Finitel,I.B.Finiteu)whenZ.(l=u)->()|_->fprintffmt"s"letpp_base_verbosefmtbase=matchbase.base_kindwith|Varv->fprintffmt"variable '%a'"(Debug.boldpp_var)v|Addra->fprintffmt"dynamically allocated block"|String(s,k,_)whenString.lengths>20->fprintffmt"string %a\"%s...\""Pp.pp_character_kindk(String.escaped(String.subs020))|String(s,k,_)->fprintffmt"string %a\"%s\""Pp.pp_character_kindk(String.escapeds)(** {2 Checks for invalid memory access} *)(** ************************************ *)typecheck+=CHK_C_INVALID_MEMORY_ACCESSlet()=register_check(funnextfmt->function|CHK_C_INVALID_MEMORY_ACCESS->fprintffmt"Invalid memory access"|a->nextfmta)typealarm_kind+=|A_c_null_derefofexpr(** pointer *)|A_c_invalid_derefofexpr|A_c_out_of_boundofbase(** accessed base *)*int_itv(** base size *)*int_itv(** offset *)*int_itv(** accessed bytes *)|A_c_opaque_accessofbase(** accessed base *)*int(** opaque from *)*int_itv(** offset *)*int_itv(** accessed bytes *)|A_c_dangling_pointer_derefofexpr(** pointer *)*var(** pointed variable *)*range(** return location *)|A_c_use_after_freeofexpr(** pointer *)*range(** deallocation site *)|A_c_modify_read_onlyofexpr(** pointer *)*base(** pointed base *)let()=register_alarm{check=(funnext->function|A_c_null_deref_|A_c_out_of_bound_|A_c_opaque_access_|A_c_invalid_deref_|A_c_dangling_pointer_deref_|A_c_use_after_free_|A_c_modify_read_only_->CHK_C_INVALID_MEMORY_ACCESS|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_null_deref(p1),A_c_null_deref(p2)->compare_exprp1p2|A_c_invalid_deref(p1),A_c_invalid_deref(p2)->compare_exprp1p2|A_c_out_of_bound(b1,s1,o1,e1),A_c_out_of_bound(b2,s2,o2,e2)->Compare.compose[(fun()->compare_baseb1b2);(fun()->compare_int_intervals1s2);(fun()->compare_int_intervalo1o2);(fun()->compare_int_intervale1e2);]|A_c_opaque_access(b1,i1,o1,e1),A_c_opaque_access(b2,i2,o2,e2)->Compare.compose[(fun()->compare_baseb1b2);(fun()->comparei1i2);(fun()->compare_int_intervalo1o2);(fun()->compare_int_intervale1e2);]|A_c_dangling_pointer_deref(p1,v1,r1),A_c_dangling_pointer_deref(p2,v2,r2)->Compare.triplecompare_exprcompare_varcompare_range(p1,v1,r1)(p2,v2,r2)|A_c_use_after_free(p1,r1),A_c_use_after_free(p2,r2)->Compare.paircompare_exprcompare_range(p1,r1)(p2,r2)|A_c_modify_read_only(p1,b1),A_c_modify_read_only(p2,b2)->Compare.paircompare_exprcompare_base(p1,b1)(p2,b2)|_->nexta1a2);print=(funnextfmt->function|A_c_null_deref(pointer)->fprintffmt"pointer '%a' may be null"(Debug.boldpp_expr)pointer|A_c_invalid_deref(pointer)->fprintffmt"pointer '%a' may be invalid"(Debug.boldpp_expr)pointer|A_c_out_of_bound(base,size,offset,elm)->fprintffmt"accessing %a byte%a at offset%a %a of %a of size %a byte%a"pp_const_or_intervalelmpp_interval_plurialelmpp_interval_cardinal_plurialoffsetpp_const_or_intervaloffsetpp_base_verbosebasepp_const_or_intervalsizepp_interval_plurialsize|A_c_opaque_access(base,i,offset,elm)->fprintffmt"opaque access %a byte%a at offset%a %a of %a opaque from offset %d"pp_const_or_intervalelmpp_interval_plurialelmpp_interval_cardinal_plurialoffsetpp_const_or_intervaloffsetpp_base_verbosebasei|A_c_dangling_pointer_deref(p,v,r)->beginmatchv.vkindwith|V_cvar{cvar_scope=Variable_localf}|V_cvar{cvar_scope=Variable_parameterf}->fprintffmt"'%a' points to dangling local variable '%a' of function '%a' deallocated at %a"(Debug.boldpp_expr)p(Debug.boldpp_var)v(Debug.boldpp_print_string)f.c_func_org_namepp_relative_ranger|_->fprintffmt"'%a' points to dangling local variable '%a' deallocated at %a"(Debug.boldpp_expr)p(Debug.boldpp_var)vpp_relative_rangerend|A_c_use_after_free(p,r)->fprintffmt"'%a' points to memory deallocated at %a"(Debug.boldpp_expr)ppp_relative_ranger|A_c_modify_read_only(p,b)->fprintffmt"'%a' points to read-only %a"(Debug.boldpp_expr)ppp_base_verboseb|a->nextfmta);join=(funnexta1a2->matcha1,a2with|A_c_out_of_bound(b1,s1,o1,e1),A_c_out_of_bound(b2,s2,o2,e2)->(* Group alarms if the base is the same *)ifcompare_baseb1b2=0thenlets=I.join_bots1s2inleto=I.join_boto1o2inlete=I.join_bote1e2inSome(A_c_out_of_bound(b1,s,o,e))elseNone|_->nexta1a2);}letraise_c_null_deref_alarm?(bottom=true)pointer?(range=pointer.erange)manflow=letcs=Flow.get_callstackflowinletpointer'=get_orig_exprpointerinletalarm=mk_alarm(A_c_null_deref(pointer'))csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletraise_c_invalid_deref_alarm?(bottom=true)pointer?(range=pointer.erange)manflow=letcs=Flow.get_callstackflowinletpointer'=get_orig_exprpointerinletalarm=mk_alarm(A_c_invalid_deref(pointer'))csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletraise_c_out_bound_alarm?(bottom=true)basesizeoffsettyprangemaninput_flowerror_flow=letcs=Flow.get_callstackerror_flowinletoffset_itv=ask_and_reduceman.ask(mk_int_interval_queryoffset)input_flowinletsize_itv=ask_and_reduceman.ask(mk_int_interval_querysize)input_flowinletelm_itv=Bot.Nb(sizeof_type(void_to_chartyp)input_flow|>I.cst)inletalarm=mk_alarm(A_c_out_of_bound(base,size_itv,offset_itv,elm_itv))csrangeinFlow.raise_alarmalarm~bottomman.latticeerror_flowletraise_c_opaque_access?(bottom=true)baseopaquefromoffsettyprangemaninput_flowerror_flow=letcs=Flow.get_callstackerror_flowinletoffset_itv=ask_and_reduceman.ask(mk_int_interval_queryoffset)input_flowinletelm_itv=Bot.Nb(sizeof_type(void_to_chartyp)input_flow|>I.cst)inletalarm=mk_alarm(A_c_opaque_access(base,opaquefrom,offset_itv,elm_itv))csrangeinFlow.raise_alarmalarm~bottomman.latticeerror_flowletraise_c_dangling_deref_alarm?(bottom=true)ptrvarret_range?(range=ptr.erange)manflow=letcs=Flow.get_callstackflowinletptr'=get_orig_exprptrinletalarm=mk_alarm(A_c_dangling_pointer_deref(ptr',var,untag_rangeret_range))csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletraise_c_use_after_free_alarm?(bottom=true)pointerdealloc_range?(range=pointer.erange)manflow=letcs=Flow.get_callstackflowinletpointer'=get_orig_exprpointerinletalarm=mk_alarm(A_c_use_after_free(pointer',untag_rangedealloc_range))csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletraise_c_modify_read_only_alarm?(bottom=true)ptrbasemanflow=letcs=Flow.get_callstackflowinletalarm=mk_alarm(A_c_modify_read_only(get_orig_exprptr,base))csptr.erangeinFlow.raise_alarmalarm~bottomman.latticeflowletsafe_c_memory_access_checkrangemanflow=Flow.add_safe_checkCHK_C_INVALID_MEMORY_ACCESSrangeflowletunreachable_c_memory_access_checkrangemanflow=Flow.add_unreachable_checkCHK_C_INVALID_MEMORY_ACCESSrangeflowletraise_c_memory_access_warningrangemanflow=Flow.add_warning_checkCHK_C_INVALID_MEMORY_ACCESSrangeflow(** {2 Division by zero} *)(** ******************** *)typecheck+=CHK_C_DIVIDE_BY_ZEROtypealarm_kind+=A_c_divide_by_zeroofexpr(** denominator *)let()=register_check(funnextfmt->function|CHK_C_DIVIDE_BY_ZERO->fprintffmt"Division by zero"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_divide_by_zero_->CHK_C_DIVIDE_BY_ZERO|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_divide_by_zero(e1),A_c_divide_by_zero(e2)->compare_expre1e2|_->nexta1a2);print=(funnextfmt->function|A_c_divide_by_zero(e)->fprintffmt"denominator '%a' may be null"(Debug.boldpp_expr)e|a->nextfmta);join=(funnext->next);}letraise_c_divide_by_zero_alarm?(bottom=true)denominatorrangemanflow=letcs=Flow.get_callstackflowinletdenominator'=get_orig_exprdenominatorinletalarm=mk_alarm(A_c_divide_by_zero(denominator'))csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletsafe_c_divide_by_zero_checkrangemanflow=Flow.add_safe_checkCHK_C_DIVIDE_BY_ZEROrangeflowletunreachable_c_divide_by_zero_checkrangemanflow=Flow.add_unreachable_checkCHK_C_DIVIDE_BY_ZEROrangeflow(** {2 Integer overflow} *)(** ******************** *)typecheck+=CHK_C_INTEGER_OVERFLOWtypealarm_kind+=(** Overflow raised by integer operations *)|A_c_integer_overflowofexpr(** integer expression *)*int_itv(** expression value *)*typ(** overflowed type *)(** Overlow raised by a cast of a pointer to an interger type *)|A_c_pointer_to_integer_overflowofexpr(** pointer expression *)*typ(** cast type*)let()=register_check(funnextfmt->function|CHK_C_INTEGER_OVERFLOW->fprintffmt"Integer overflow"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_integer_overflow_->CHK_C_INTEGER_OVERFLOW|A_c_pointer_to_integer_overflow_->CHK_C_INTEGER_OVERFLOW|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_integer_overflow(e1,v1,t1),A_c_integer_overflow(e2,v2,t2)->Compare.triplecompare_exprcompare_int_intervalcompare_typ(e1,v1,t1)(e2,v2,t2)|A_c_pointer_to_integer_overflow(e1,t1),A_c_pointer_to_integer_overflow(e2,t2)->Compare.paircompare_exprcompare_typ(e1,t1)(e2,t2)|_->nexta1a2);print=(funnextfmt->function|A_c_integer_overflow(e,v,t)->fprintffmt"'%a' has value %a that is larger than the range of '%a'"(Debug.boldpp_expr)epp_const_or_intervalv(Debug.boldpp_typ)t|A_c_pointer_to_integer_overflow(e,t)->fprintffmt"casting pointer '%a' to '%a' may result in an overflow"(Debug.boldpp_expr)e(Debug.boldpp_typ)t|a->nextfmta);join=(funnexta1a2->matcha1,a2with|A_c_integer_overflow(e1,v1,t1),A_c_integer_overflow(e2,v2,t2)->ifcompare_expre1e2=0&&compare_typt1t2=0thenletv=I.join_botv1v2inSome(A_c_integer_overflow(e1,v,t1))elseNone|_->nexta1a2);}letraise_c_integer_overflow_alarm?(warning=false)cexpnexptyprangemaninput_flowerror_flow=letcs=Flow.get_callstackerror_flowinletcexp'=get_orig_exprcexpinletitv=ask_and_reduceman.ask(mk_int_interval_querynexp)input_flowinletalarm=mk_alarm(A_c_integer_overflow(cexp',itv,typ))csrangeinFlow.raise_alarmalarm~bottom:false~warningman.latticeerror_flowletraise_c_pointer_to_integer_overflow_alarm?(warning=true)exptyprangemanflow=letcs=Flow.get_callstackflowinletexp'=get_orig_exprexpinletalarm=mk_alarm(A_c_pointer_to_integer_overflow(exp',typ))csrangeinFlow.raise_alarmalarm~bottom:false~warningman.latticeflowletsafe_c_integer_overflow_checkrangemanflow=Flow.add_safe_checkCHK_C_INTEGER_OVERFLOWrangeflowletunreachable_c_integer_overflow_checkrangemanflow=Flow.add_unreachable_checkCHK_C_INTEGER_OVERFLOWrangeflow(** {2 Invalid shift} *)(** ***************** *)typecheck+=CHK_C_INVALID_SHIFTtypealarm_kind+=A_c_invalid_shiftofexpr(** shifted expression *)*expr(** shift expression *)*int_itv(** shift value *)let()=register_check(funnextfmt->function|CHK_C_INVALID_SHIFT->fprintffmt"Invalid shift"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_invalid_shift_->CHK_C_INVALID_SHIFT|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_invalid_shift(e1,s1,v1),A_c_invalid_shift(e2,s2,v2)->Compare.triplecompare_exprcompare_exprcompare_int_interval(e1,s1,v1)(e2,s2,v2)|_->nexta1a2);print=(funnextfmt->function|A_c_invalid_shift(e,shift,v)->fprintffmt"shift position '%a' = %a %a"(Debug.boldpp_expr)epp_const_or_intervalvpp_const_or_interval_not_eqv|a->nextfmta);join=(funnexta1a2->matcha1,a2with|A_c_invalid_shift(e1,s1,v1),A_c_invalid_shift(e2,s2,v2)->ifcompare_expre1e2=0&&compare_exprs1s2=0thenletv=I.join_botv1v2inSome(A_c_invalid_shift(e1,s1,v))elseNone|_->nexta1a2);}letraise_c_invalid_shift_alarm?(bottom=true)eshiftrangemaninput_flowerror_flow=letcs=Flow.get_callstackerror_flowinletshift'=get_orig_exprshiftinletshift_itv=ask_and_reduceman.ask(mk_int_interval_queryshift)input_flowinletalarm=mk_alarm(A_c_invalid_shift(e,shift',shift_itv))csrangeinFlow.raise_alarmalarm~bottomman.latticeerror_flowletsafe_c_shift_checkrangemanflow=Flow.add_safe_checkCHK_C_INVALID_SHIFTrangeflowletunreachable_c_shift_checkrangemanflow=Flow.add_unreachable_checkCHK_C_INVALID_SHIFTrangeflow(** {2 Invalid pointer comparison} *)(** ****************************** *)typecheck+=CHK_C_INVALID_POINTER_COMPAREtypealarm_kind+=A_c_invalid_pointer_compareofexpr(** first pointer *)*expr(** second pointer *)let()=register_check(funnextfmt->function|CHK_C_INVALID_POINTER_COMPARE->fprintffmt"Invalid pointer comparison"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_invalid_pointer_compare_->CHK_C_INVALID_POINTER_COMPARE|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_invalid_pointer_compare(p1,p2),A_c_invalid_pointer_compare(p1',p2')->Compare.paircompare_exprcompare_expr(p1,p2)(p1',p2')|_->nexta1a2);print=(funnextfmt->function|A_c_invalid_pointer_compare(p1,p2)->fprintffmt"'%a' and '%a' may point to different memory objects"(Debug.boldpp_expr)p1(Debug.boldpp_expr)p2|m->nextfmtm);join=(funnext->next);}letraise_c_invalid_pointer_compare?(bottom=true)p1p2rangemanflow=letcs=Flow.get_callstackflowinletp1'=get_orig_exprp1inletp2'=get_orig_exprp2inletalarm=mk_alarm(A_c_invalid_pointer_compare(p1',p2'))csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletsafe_c_pointer_comparerangemanflow=Flow.add_safe_checkCHK_C_INVALID_POINTER_COMPARErangeflow(** {2 Invalid pointer subtraction} *)(** ******************************* *)typecheck+=CHK_C_INVALID_POINTER_SUBtypealarm_kind+=A_c_invalid_pointer_subofexpr(** first pointer *)*expr(** second pointer *)let()=register_check(funnextfmt->function|CHK_C_INVALID_POINTER_SUB->fprintffmt"Invalid pointer subtraction"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_invalid_pointer_sub_->CHK_C_INVALID_POINTER_SUB|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_invalid_pointer_sub(p1,p2),A_c_invalid_pointer_sub(p1',p2')->Compare.paircompare_exprcompare_expr(p1,p2)(p1',p2')|_->nexta1a2);print=(funnextfmt->function|A_c_invalid_pointer_sub(p1,p2)->fprintffmt"'%a' and '%a' may point to different memory objects"(Debug.boldpp_expr)p1(Debug.boldpp_expr)p2|m->nextfmtm);join=(funnext->next);}letraise_c_invalid_pointer_sub?(bottom=true)p1p2rangemanflow=letcs=Flow.get_callstackflowinletp1'=get_orig_exprp1inletp2'=get_orig_exprp2inletalarm=mk_alarm(A_c_invalid_pointer_sub(p1',p2'))csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletsafe_c_pointer_subrangemanflow=Flow.add_safe_checkCHK_C_INVALID_POINTER_SUBrangeflow(** {2 Double free} *)(** *************** *)typecheck+=CHK_C_DOUBLE_FREEtypealarm_kind+=A_c_double_freeofexpr(** pointer *)*range(** deallocation site *)let()=register_check(funnextfmt->function|CHK_C_DOUBLE_FREE->fprintffmt"Double free"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_double_free_->CHK_C_DOUBLE_FREE|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_double_free(p1,r1),A_c_double_free(p2,r2)->Compare.paircompare_exprcompare_range(p1,r1)(p2,r2)|_->nexta1a2);print=(funnextfmt->function|A_c_double_free(p,r)->fprintffmt"'%a' points to memory already deallocated at %a"(Debug.boldpp_expr)ppp_relative_ranger|m->nextfmtm);join=(funnext->next);}letraise_c_double_free_alarm?(bottom=true)pointerdealloc_range?(range=pointer.erange)manflow=letcs=Flow.get_callstackflowinletpointer'=get_orig_exprpointerinletalarm=mk_alarm(A_c_double_free(pointer',untag_rangedealloc_range))csrangeinFlow.raise_alarmalarm~bottomman.latticeflow(** {2 Insufficient variadic arguments} *)(** *********************************** *)typecheck+=CHK_C_INSUFFICIENT_VARIADIC_ARGStypealarm_kind+=A_c_insufficient_variadic_argsofvar(** va_list variable *)*int_itv(** va_arg call counter *)*int_itv(** number of passed arguments *)let()=register_check(funnextfmt->function|CHK_C_INSUFFICIENT_VARIADIC_ARGS->fprintffmt"Insufficient variadic arguments"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_insufficient_variadic_args_->CHK_C_INSUFFICIENT_VARIADIC_ARGS|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_insufficient_variadic_args(va1,c1,n1),A_c_insufficient_variadic_args(va2,c2,n2)->Compare.triplecompare_varcompare_int_intervalcompare_int_interval(va1,c1,n1)(va2,c2,n2)|_->nexta1a2);print=(funnextfmt->function|A_c_insufficient_variadic_args(va,counter,nargs)->fprintffmt"va_arg called %a time%a on va_list object '%a' with %a argument%a"pp_const_or_intervalcounterpp_interval_plurialcounterpp_varvapp_const_or_intervalnargspp_interval_plurialnargs|a->nextfmta);join=(funnexta1a2->matcha1,a2with|A_c_insufficient_variadic_args(va1,c1,n1),A_c_insufficient_variadic_args(va2,c2,n2)->(* Group messages by va_list variables and compute the
interval of call counter and the number of passed
arguments *)ifcompare_varva1va2=0thenletc=I.join_botc1c2inletn=I.join_botn1n2inSome(A_c_insufficient_variadic_args(va1,c,n))elseNone|_->nexta1a2);}letraise_c_insufficient_variadic_args?(bottom=true)va_listcounterargsrangemaninput_flowerror_flow=letcs=Flow.get_callstackerror_flowinletnargs=List.lengthargsinletcounter_itv=ask_and_reduceman.ask(mk_int_interval_querycounter)input_flowinletnargs_itv=Bot.Nb(I.cst_intnargs)inletalarm=mk_alarm(A_c_insufficient_variadic_args(va_list,counter_itv,nargs_itv))csrangeinFlow.raise_alarmalarm~bottomman.latticeerror_flowletsafe_variadic_args_numberrangemanflow=Flow.add_safe_checkCHK_C_INSUFFICIENT_VARIADIC_ARGSrangeflow(** {2 Insufficient format arguments} *)(** ********************************* *)typecheck+=CHK_C_INSUFFICIENT_FORMAT_ARGStypealarm_kind+=A_c_insufficient_format_argsofint(** number of required arguments *)*int(** number of given arguments *)let()=register_check(funnextfmt->function|CHK_C_INSUFFICIENT_FORMAT_ARGS->fprintffmt"Insufficient format arguments"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_insufficient_format_args_->CHK_C_INSUFFICIENT_FORMAT_ARGS|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_insufficient_format_args(r1,g1),A_c_insufficient_format_args(r2,g2)->Compare.paircomparecompare(r1,g1)(r2,g2)|_->nexta1a2);print=(funnextfmt->function|A_c_insufficient_format_args(required,given)->fprintffmt"%d argument%a given while %d argument%a required"givenDebug.plurial_intgivenrequiredDebug.plurial_intrequired|m->nextfmtm);join=(funnext->next);}letraise_c_insufficient_format_args_alarmrequiredgivenrangemanflow=letcs=Flow.get_callstackflowinletalarm=mk_alarm(A_c_insufficient_format_args(required,given))csrangeinFlow.raise_alarmalarm~bottom:trueman.latticeflowletraise_c_insufficient_format_args_warningrangemanflow=Flow.add_warning_checkCHK_C_INSUFFICIENT_FORMAT_ARGSrangeflowletsafe_c_format_args_numberrangemanflow=Flow.add_safe_checkCHK_C_INSUFFICIENT_FORMAT_ARGSrangeflow(** {2 Invalid type of format argument} *)(** *********************************** *)typecheck+=CHK_C_INVALID_FORMAT_ARG_TYPEtypealarm_kind+=A_c_invalid_format_arg_typeofexpr(** argument *)*typ(** expected type *)let()=register_check(funnextfmt->function|CHK_C_INVALID_FORMAT_ARG_TYPE->fprintffmt"Invalid type of format argument"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_invalid_format_arg_type_->CHK_C_INVALID_FORMAT_ARG_TYPE|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_invalid_format_arg_type(e1,t1),A_c_invalid_format_arg_type(e2,t2)->Compare.paircompare_exprcompare_typ(e1,t1)(e2,t2)|_->nexta1a2);print=(funnextfmt->function|A_c_invalid_format_arg_type(e,t)->fprintffmt"format expects argument of type '%a', but '%a' has type '%a'"(Debug.boldpp_typ)t(Debug.boldpp_expr)e(Debug.boldpp_typ)e.etyp|m->nextfmtm);join=(funnext->next);}letraise_c_invalid_format_arg_type_alarmargtypmanflow=letcs=Flow.get_callstackflowinletalarm=mk_alarm(A_c_invalid_format_arg_type(get_orig_exprarg,typ))csarg.erangeinFlow.raise_alarmalarm~bottom:trueman.latticeflowletraise_c_invalid_format_arg_type_warningrangemanflow=Flow.add_warning_checkCHK_C_INVALID_FORMAT_ARG_TYPErangeflowletsafe_c_format_arg_typerangemanflow=Flow.add_safe_checkCHK_C_INVALID_FORMAT_ARG_TYPErangeflow(** {2 Float errors} *)(** **************** *)typecheck+=CHK_C_INVALID_FLOAT_CLASStypealarm_kind+=A_c_invalid_float_classoffloat_itv(** float value *)*string(** expected class *)let()=register_check(funnextfmt->function|CHK_C_INVALID_FLOAT_CLASS->fprintffmt"Invalid floating-point number class"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_invalid_float_class_->CHK_C_INVALID_FLOAT_CLASS|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_invalid_float_class(f1,m1),A_c_invalid_float_class(f2,m2)->Compare.compose[(fun()->compare_float_intervalf1f2);(fun()->comparem1m2)]|_->nexta1a2);print=(funnextfmt->function|A_c_invalid_float_class(f,msg)->fprintffmt"float '%a' may not be %s"(Debug.bold(F.fprintF.dfl_fmt))fmsg|a->nextfmta);join=(funnext->next);}letraise_c_invalid_float_class_alarm?(bottom=true)floatmsgrangemaninput_flowerror_flow=letcs=Flow.get_callstackerror_flowinletfloat_itv=ask_and_reduceman.ask(mk_float_interval_queryfloat)input_flowinletalarm=mk_alarm(A_c_invalid_float_class(float_itv,msg))csrangeinFlow.raise_alarmalarm~bottomman.latticeerror_flow(** There are five IEEE 754 exceptions.
We only singal include invalid operation, division by zero and
overflow. We don't care about underflow (rounding to 0) and
inexact (rounding).
*)typecheck+=CHK_C_FLOAT_INVALID_OPERATION|CHK_C_FLOAT_DIVISION_BY_ZERO|CHK_C_FLOAT_OVERFLOWlet()=register_check(funnextfmt->function|CHK_C_FLOAT_INVALID_OPERATION->fprintffmt"Invalid floating-point operation"|CHK_C_FLOAT_DIVISION_BY_ZERO->fprintffmt"Floating-point division by zero"|CHK_C_FLOAT_OVERFLOW->fprintffmt"Floating-point overflow"|a->nextfmta)typealarm_kind+=|A_c_float_invalid_operationofexpr(** expression *)*float_itv(** result interval *)*typ(** destination type *)|A_c_float_division_by_zeroofexpr(** denominator *)*float_itv(** denominator interval *)|A_c_float_overflowofexpr(** expression *)*float_itv(** result interval *)*typ(** type *)let()=register_alarm{check=(funnext->function|A_c_float_invalid_operation_->CHK_C_FLOAT_INVALID_OPERATION|A_c_float_division_by_zero_->CHK_C_FLOAT_DIVISION_BY_ZERO|A_c_float_overflow_->CHK_C_FLOAT_OVERFLOW|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_float_invalid_operation(e1,i1,t1),A_c_float_invalid_operation(e2,i2,t2)->Compare.triplecompare_exprcomparecompare_typ(e1,i1,t1)(e2,i2,t2)|A_c_float_division_by_zero(e1,i1),A_c_float_division_by_zero(e2,i2)->Compare.paircompare_exprcompare(e1,i1)(e2,i2)|A_c_float_overflow(e1,i1,t1),A_c_float_overflow(e2,i2,t2)->Compare.triplecompare_exprcomparecompare_typ(e1,i1,t1)(e2,i2,t2)|_->nexta1a2);print=(funnextfmt->function|A_c_float_invalid_operation(e,i,t)->fprintffmt"invalid floating-point operations in expression '%a' with range '%a' and type '%a'"(Debug.boldpp_expr)e(Debug.bold(F.fprintF.dfl_fmt))i(Debug.boldpp_typ)t|A_c_float_division_by_zero(e,i)->fprintffmt"floating-point division by zero on denominator '%a' with range '%a'"(Debug.boldpp_expr)e(Debug.bold(F.fprintF.dfl_fmt))i|A_c_float_overflow(e,i,t)->fprintffmt"floating-point overflow in expression '%a' with range '%a' and type '%a'"(Debug.boldpp_expr)e(Debug.bold(F.fprintF.dfl_fmt))i(Debug.boldpp_typ)t|a->nextfmta);join=(funnext->next);}letraise_c_float_invalid_operation_alarm?(bottom=false)?(warning=true)expitvtyprangemanflow=letcs=Flow.get_callstackflowinletexp'=get_orig_exprexpinletalarm=mk_alarm(A_c_float_invalid_operation(exp',itv,typ))csrangeinFlow.raise_alarmalarm~bottom~warningman.latticeflowletraise_c_float_division_by_zero_alarm?(bottom=true)?(warning=false)denominatoritvrangemanflow=letcs=Flow.get_callstackflowinletdenominator'=get_orig_exprdenominatorinletalarm=mk_alarm(A_c_float_division_by_zero(denominator',itv))csrangeinFlow.raise_alarmalarm~bottom~warningman.latticeflowletraise_c_float_overflow_alarm?(bottom=false)?(warning=true)expitvtrangemanflow=letcs=Flow.get_callstackflowinletexp'=get_orig_exprexpinletalarm=mk_alarm(A_c_float_overflow(exp',itv,t))csrangeinFlow.raise_alarmalarm~bottom~warningman.latticeflowletsafe_c_float_invalid_operation_checkrangemanflow=Flow.add_safe_checkCHK_C_FLOAT_INVALID_OPERATIONrangeflowletsafe_c_float_division_by_zero_checkrangemanflow=Flow.add_safe_checkCHK_C_FLOAT_DIVISION_BY_ZEROrangeflowletsafe_c_float_overflow_checkrangemanflow=Flow.add_safe_checkCHK_C_FLOAT_OVERFLOWrangeflow(** {2 Unfreed/Unreachable memory } *)(** **************** *)typecheck+=CHK_C_UNREACHABLE_MEMORYtypealarm_kind+=A_c_unreachable_memoryofaddrlet()=register_check(funnextfmt->function|CHK_C_UNREACHABLE_MEMORY->fprintffmt"Unreachable allocated memory"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_unreachable_memory_->CHK_C_UNREACHABLE_MEMORY|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_unreachable_memorya1,A_c_unreachable_memorya2->compare_addra1a2|_->nexta1a2);print=(funnextfmt->function|A_c_unreachable_memorya->fprintffmt"Memory %a (allocated at %a) may be unreachable/unfreed"pp_addrapp_addr_partitioning_fulla.addr_partitioning;|a->nextfmta);join=(funnext->next);}letraise_c_unreachable_memoryaddrrangemanflow=letcs=Flow.get_callstackflowinletalarm=mk_alarm(A_c_unreachable_memoryaddr)csrangeinFlow.raise_alarmalarm~bottom:falseman.latticeflow(** {2 Invalid array size} *)(** ********************** *)typecheck+=CHK_C_NEGATIVE_ARRAY_SIZEtypealarm_kind+=A_c_negative_array_sizeofexprlet()=register_check(funnextfmt->function|CHK_C_NEGATIVE_ARRAY_SIZE->fprintffmt"Negative array size"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_c_negative_array_size_->CHK_C_NEGATIVE_ARRAY_SIZE|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_c_negative_array_sizee1,A_c_negative_array_sizee2->compare_expre1e2|_->nexta1a2);print=(funnextfmt->function|A_c_negative_array_sizee->fprintffmt"Array size '%a' may be negative"(Debug.boldpp_expr)e|a->nextfmta);join=(funnext->next);}letraise_c_negative_array_size_alarm?(bottom=true)erangemanflow=letcs=Flow.get_callstackflowinlete'=get_orig_expreinletalarm=mk_alarm(A_c_negative_array_sizee')csrangeinFlow.raise_alarmalarm~bottomman.latticeflowletsafe_c_negative_array_size_checkrangemanflow=Flow.add_safe_checkCHK_C_NEGATIVE_ARRAY_SIZErangeflowletunreachable_c_negative_array_size_checkrangemanflow=Flow.add_unreachable_checkCHK_C_NEGATIVE_ARRAY_SIZErangeflow