123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openCil_typestype'aalarm_gen=remove_trivial:bool->on_alarm:(invalid:bool->Alarms.alarm->unit)->'a->unittypebound_kind=Alarms.bound_kind=Lower_bound|Upper_bound(* Tries to evaluate expr as a constant value (Int64.t).
Uses Cil constant folding (e.g. for (-0x7ffffff -1) => Some (-2147483648)) on
32 bits *)letget_expr_valexpr=Cil.constFoldToIntexpr(* Creates [0 <= e] and [e < size] assertions *)letvalid_index~remove_trivial~on_alarmesize=letalarmbk=letb=matchbkwith|Lower_bound->None|Upper_bound->Somesizein(* Do not create upper-bound check on GNU zero-length arrays *)ifnot(bk==Upper_bound&&Cil.isZerosize)thenbeginon_alarm~invalid:false(Alarms.Index_out_of_bound(e,b))endinifremove_trivialthenbegin(* See if the two assertions do not trivially hold. In this
case, do not return then *)letv_e=get_expr_valeinletv_size=get_expr_valsizeinletneg_ok=Option.fold~none:false~some:(Z.leqZ.zero)v_e||Cil.isUnsignedInteger(Cil.typeOfe)inifnotneg_okthenalarmLower_bound;letpos_ok=matchv_e,v_sizewith|Somev_e,Somev_size->Z.ltv_ev_size|None,_|_,None->falseinifnotpos_okthenalarmUpper_boundendelsebeginalarmLower_bound;alarmUpper_bound;end(* returns the assertion associated with an lvalue:
returns non empty assertions only on pointer dereferencing and array access.
The validity assertions are emitted using [valid] if
[~read_only] is false, or with [valid_read] otherwise *)letlval_assertion~read_only~remove_trivial~on_alarmlv=(* For accesses to known arrays we generate an assertions that constrains
the index. This is simpler than the [\valid] assertion *)letreccheck_array_accessdefaultofftypin_struct=matchoffwith|NoOffset->ifdefaultthenon_alarm~invalid:false(Alarms.Memory_access(lv,read_only))|Field(fi,off)->(* Mark that we went through a struct field, then recurse *)check_array_accessdefaultofffi.ftypetrue|Index(e,off)->matchAst_types.unroll_nodetypwith|TArray(bt,Somesize)->ifKernel.SafeArrays.get()||notin_structthenbegin(* Generate an assertion for this access, then go deeper in
case other accesses exist *)valid_index~remove_trivial~on_alarmesize;check_array_accessdefaultoffbtin_structendelse(* Access to an array embedded in a struct with option
[-unsafe-arrays]. Honor the option and generate only
the default [\valid] assertion *)check_array_accesstrueoffbtin_struct|TArray(bt,None)->check_array_accesstrueoffbtin_struct|_->assertfalseinmatchlvwith|Varvi,off->check_array_accessfalseoffvi.vtypefalse|(Mem_aslh),off->ifnot(Ast_types.is_fun(Cil.typeOfLvallv))thencheck_array_accesstrueoff(Cil.typeOfLhostlh)false(* assertion for lvalue initialization *)letlval_initialized_assertion~remove_trivial:_~on_alarmlv=lettyp=Cil.typeOfLvallvinmatchlvwith|Varvi,NoOffset->(* Note: here [lv] has structure/union type or fundamental type.
We exclude structures and unions. And for fundamental types:
- globals (initialized and then only written with initialized values)
- formals (checked at function call)
- temporary variables (initialized during AST normalization)
*)ifnot(vi.vglob||vi.vformal||vi.vtemp)&¬(Ast_types.is_struct_or_uniontyp)thenon_alarm~invalid:false(Alarms.Uninitializedlv)|_->ifnotAst_types.(is_funtyp||is_struct_or_uniontyp)thenon_alarm~invalid:false(Alarms.Uninitializedlv)(* assertion for unary minus signed overflow *)letuminus_assertion~remove_trivial~on_alarmexp=(* - expr overflows if exp is TYPE_MIN *)lett=Ast_types.unroll(Cil.typeOfexp)inletsize=Cil.bitsSizeOftinletmin_ty=Cil.min_signed_numbersizein(* alarm is bound <= exp, hence bound must be MIN_INT+1 *)letbound=Z.succmin_tyinletalarm?(invalid=false)()=leta=Alarms.Overflow(Alarms.Signed,exp,bound,Lower_bound)inon_alarm~invalidainifremove_trivialthenbeginmatchget_expr_valexpwith|None->alarm()|Somea64->(* constant operand *)ifZ.equala64min_tythenalarm~invalid:true()endelsealarm()(* assertions for multiplication/addition/subtraction overflows *)letmult_sub_add_assertion~signed~remove_trivial~on_alarm(exp,op,lexp,rexp)=(* signed multiplication/addition/subtraction:
the expression overflows iff its integer value
is strictly more than [max_ty] or strictly less than [min_ty] *)lett=Ast_types.unroll(Cil.typeOfexp)inletsize=Cil.bitsSizeOftinletmin_ty,max_ty=ifsignedthenCil.min_signed_numbersize,Cil.max_signed_numbersizeelseZ.zero,Cil.max_unsigned_numbersizeinletalarm?(invalid=false)bk=letbound=matchbkwith|Upper_bound->max_ty|Lower_bound->min_tyinletsigned=ifsignedthenAlarms.SignedelseAlarms.Unsignedinon_alarm~invalid(Alarms.Overflow(signed,exp,bound,bk));inletalarms()=alarmLower_bound;alarmUpper_bound;inifremove_trivialthenbeginmatchget_expr_vallexp,get_expr_valrexp,opwith|Somel,Somer,_->(* both operands are constant *)letwarnr=letwarnbk=alarm~invalid:truebkinifZ.gtrmax_tythenwarnUpper_boundelseifZ.ltrmin_tythenwarnLower_boundin(matchopwith|MinusA->warn(Z.sublr)|PlusA->warn(Z.addlr)|Mult->warn(Z.mullr)|_->assertfalse)|_,Somev,PlusA|Somev,_,PlusA->ifZ.(gtvzero)thenalarmUpper_boundelseifZ.(ltvzero)thenalarmLower_bound(* signed only *)|_,Somer,MinusA->ifZ.(gtrzero)thenalarmLower_boundelseifZ.(ltrzero)thenalarmUpper_bound(* signed only *)|Somel,None,MinusA->ifsignedthenbegin(* The possible range for [-r] is [-max_int .. -min_int] i.e.
[min_int+1..max_int+1]; we need to check [l] w.r.t [-1]. *)ifZ.(gtlminus_one)thenalarmUpper_boundelseifZ.(ltlminus_one)thenalarmLower_boundendelsebegin(* Only negative overflows are possible, since r is positive. (TODO:
nothing can happen on [max_int]. *)alarmLower_boundend|Somev,None,Mult|None,Somev,MultwhenZ.is_zerov||Z.is_onev->()|None,None,_|Some_,None,_|None,Some_,_->alarms()endelsealarms()(* assertions for division and modulo (divisor is 0) *)letdivmod_assertion~remove_trivial~on_alarmdivisor=(* division or modulo: overflow occurs when divisor is equal to zero *)letalarm?(invalid=false)()=on_alarm~invalid(Alarms.Division_by_zerodivisor);inifremove_trivialthenbeginmatchget_expr_valdivisorwith|None->(* divisor is not a constant *)alarm();|Somev64->ifZ.is_zerov64then(* divide by 0 *)alarm~invalid:true()(* else divide by constant which is not 0: nothing to assert *)endelsealarm()(* assertion for signed division overflow *)letsigned_div_assertion~remove_trivial~on_alarm(exp,lexp,rexp)=(* Signed division: overflow occurs when dividend is equal to the
the minimum (negative) value for the signed integer type,
and divisor is equal to -1. Under the hypothesis (cf Value) that
integers are represented in two's complement.
*)lett=Ast_types.unroll(Cil.typeOfrexp)inletsize=Cil.bitsSizeOftin(* check dividend_expr / divisor_expr : if constants ... *)(* compute smallest representable "size bits" (signed) integer *)letmax_ty=Cil.max_signed_numbersizeinletalarm?(invalid=false)()=leta=Alarms.Overflow(Alarms.Signed,exp,max_ty,Alarms.Upper_bound)inon_alarm~invalida;inifremove_trivialthenbeginletmin=Cil.min_signed_numbersizeinmatchget_expr_vallexp,get_expr_valrexpwith|Somee1,_whennot(Z.equale1min)->(* dividend is constant, with an unproblematic value *)()|_,Somee2whennot(Z.equale2Z.minus_one)->(* divisor is constant, with an unproblematic value *)()|Some_,Some_->(* invalid constant division *)alarm~invalid:true()|None,Some_|Some_,None|None,None->(* at least one is not constant: cannot conclude *)alarm()endelsealarm()(* Assertions for the left and right operands of left and right shift. *)letshift_assertion~remove_trivial~on_alarm(exp,upper_bound)=letalarm?(invalid=false)()=leta=Alarms.Invalid_shift(exp,upper_bound)inon_alarm~invalida;inifremove_trivialthenbeginmatchget_expr_valexpwith|None->alarm()|Somec64->(* operand is constant:
check it is nonnegative and strictly less than the upper bound (if
any) *)letupper_bound_ok=matchupper_boundwith|None->true|Someu->Z.ltc64(Z.of_intu)inifnot(Z.geqc64Z.zero&&upper_bound_ok)thenalarm~invalid:true()endelsealarm()(* The right operand of shifts should be nonnegative and strictly less than the
width of the promoted left operand. *)letshift_width_assertion~remove_trivial~on_alarm(exp,typ)=letsize=Cil.bitsSizeOftypinshift_assertion~remove_trivial~on_alarm(exp,Somesize)(* The left operand of signed shifts should be nonnegative:
implementation defined for right shift, undefined behavior for left shift. *)letshift_negative_assertion~remove_trivial~on_alarmexp=shift_assertion~remove_trivial~on_alarm(exp,None)(* Assertion for left and right shift overflow: the result should be
representable in the result type. *)letshift_overflow_assertion~signed~remove_trivial~on_alarm(exp,op,lexp,rexp)=lett=Ast_types.unroll(Cil.typeOfexp)inletsize=Cil.bitsSizeOftinifsize<>Cil.bitsSizeOf(Cil.typeOflexp)then(* size of result type should be size of left (promoted) operand *)Options.warning~current:true~once:true"problem with bitsSize of %a: not treated"Printer.pp_expexp;ifop=Shiftltthen(* compute greatest representable "size bits" (signed) integer *)letmaxValResult=ifsignedthenCil.max_signed_numbersizeelseCil.max_unsigned_numbersizeinletoverflow_alarm?(invalid=false)()=letsigned=ifsignedthenAlarms.SignedelseAlarms.Unsignedinleta=Alarms.Overflow(signed,exp,maxValResult,Alarms.Upper_bound)inon_alarm~invalida;inifremove_trivialthenbeginmatchget_expr_vallexp,get_expr_valrexpwith|None,_|_,None->overflow_alarm()|Somelval64,Somerval64->(* both operands are constant: check result is representable in
result type *)ifZ.(rval64>=zero&&(shift_left_zlval64rval64)>=maxValResult)thenoverflow_alarm~invalid:true()endelseoverflow_alarm()(* Assertion for downcasts. *)letdowncast_assertion~remove_trivial~on_alarm(dst_type,exp)=letsrc_type=Cil.typeOfexpinletsrc_signed=Cil.isSignedIntegersrc_typeinletdst_signed=Cil.isSignedIntegerdst_typeinletsrc_size=Cil.bitsSizeOfsrc_typeinletdst_size=Cil.bitsSizeOfBitfielddst_typeinif(dst_size<src_size||dst_size==src_size&&dst_signed<>src_signed)&¬Ast_types.(is_ptrsrc_type&&(is_intptr_tdst_type||is_uintptr_tdst_type))thenletdst_min,dst_max=ifdst_signedthenCil.min_signed_numberdst_size,Cil.max_signed_numberdst_sizeelseZ.zero,Cil.max_unsigned_numberdst_sizeinletoverflow_kind=ifAst_types.is_ptrsrc_typethenAlarms.Pointer_downcastelseifdst_signedthenAlarms.Signed_downcastelseAlarms.Unsigned_downcastinletalarm?(invalid=false)boundbound_kind=leta=Alarms.Overflow(overflow_kind,exp,bound,bound_kind)inon_alarm~invalida;inletalarms()=alarmdst_maxUpper_bound;(* unsigned values cannot overflow in the negative *)ifsrc_signedthenalarmdst_minLower_bound;inmatchremove_trivial,get_expr_valexpwith|true,Somea64->letinvalid=trueinifZ.lta64dst_minthenalarm~invaliddst_minLower_boundelseifZ.gta64dst_maxthenalarm~invaliddst_maxUpper_bound|_->alarms()(* assertion for casting a floating-point value to an integer *)letfloat_to_int_assertion~remove_trivial~on_alarm(ty,exp)=lete_typ=Ast_types.unroll(Cil.typeOfexp)inmatche_typ.tnode,ty.tnodewith|TFloat_,TIntikind->letsigned=Cil.isSignedikindinletsize=Cil.bitsSizeOfBitfieldtyinletlargest=Cil.max_unsigned_numbersizeinletmax_ty=ifsignedthenCil.max_signed_numbersizeelselargestinletmin_ty=ifsignedthenCil.min_signed_numbersizeelseZ.zeroinletbound=functionLower_bound->min_ty|Upper_bound->max_tyinletbuild_alarmb=Alarms.Float_to_int(exp,boundb,b)inletalarm?(invalid=false)b=on_alarm~invalid(build_alarmb)inletnumber=matchexp.enodewith|Const(CReal(f,fk,_))->Some(f,fk)|UnOp(Neg,{enode=Const(CReal(f,fk,_))},_)->Some(-.f,fk)|_->Noneinbeginmatchremove_trivial,numberwith|false,_|true,None->alarmUpper_bound;alarmLower_bound|true,Some(f,_)->matchFloating_point.truncate_to_integerfwith|Underflow->alarmLower_bound|Overflow->alarmUpper_bound|IntegeriwhenZ.ltimin_ty->alarm~invalid:trueLower_bound|IntegeriwhenZ.gtimax_ty->alarm~invalid:trueUpper_bound|Integer_->()end|_->()(* assertion for checking only finite float are used *)letfinite_float_assertion~remove_trivial:_~on_alarm(fkind,exp)=letinvalid=falseinmatchKernel.SpecialFloat.get()with|"none"->()|"nan"->on_alarm~invalid(Alarms.Is_nan(exp,fkind))|"non-finite"->on_alarm~invalid(Alarms.Is_nan_or_infinite(exp,fkind))|_->assertfalse(* assertion for a pointer call [( *e )(args)]. *)letpointer_call~remove_trivial:_~on_alarm(e,args)=on_alarm~invalid:false(Alarms.Function_pointer(e,Someargs))letrecis_safe_offset=function|NoOffset->true|Field(fi,o)->fi.fcomp.cstruct&¬fi.faddrof&&is_safe_offseto|Index(_,o)->is_safe_offsetoletis_safe_pointer_value=function|Lval(Varvi,offset)->(* Reading a pointer variable must emit an alarm if an invalid pointer value
could have been written without previous alarm, through:
- an union type, in which case [offset] is not NoOffset;
- an untyped write, in which case the address of [vi] is taken. *)notvi.vaddrof&&is_safe_offsetoffset|AddrOf(_,NoOffset)|StartOf(_,NoOffset)->true|CastE(_typ,e)->(* 0 can always be converted into a NULL pointer. *)letv=get_expr_valeinOption.fold~none:false~some:Z.(equalzero)v|_->falseletpointer_value~remove_trivial~on_alarmexpr=ifnot(remove_trivial&&is_safe_pointer_valueexpr.enode)thenon_alarm~invalid:false(Alarms.Invalid_pointerexpr)typeverdict=Yes|No|Maybelettrivially_aligned(expr:Cil_types.exp)target=ifAst_types.is_voidtarget||Ast_types.is_funtargetthen(* - From an alignment point of view, casting to void* is always OK
(except for function pointers, but anyway, the problem is not
alignment)
- Alignment does not make sense for functions *)Yeselse(* we can safely compute this now *)lett_align=Cil.bytesAlignOftargetinletexpr=Cil.stripCastsexprinletorig_t=Cil.typeOfexprinifAst_types.is_void_ptrorig_t||Ast_types.is_fun_ptrorig_tthenMaybeelseifAst_types.is_integralorig_tthenmatchCil.constFoldToIntexprwith|None->Maybe|SomevaluewhenZ.(zero=(valuemodof_intt_align))->Yes|_->Noelsematchexpr.enodewith|Lval(Varvi,NoOffset)whennotvi.vglob&¬vi.vaddrof->(* This optimization can be generalized if we check strict aliasing *)ift_align<=Cil.bytesAlignOf@@Ast_types.direct_pointed_typeorig_tthenYeselseMaybe|AddrOf(Varvi,NoOffset)|StartOf(Varvi,NoOffset)->if0=Cil.bytesAlignOfVarinfovimodt_alignthenYeselseMaybe|_->(* probably more cases to optimize here *)Maybeletpointer_alignment~remove_trivial~on_alarm(expr,t)=assert(Ast_types.is_ptrt);letpointed_to=Ast_types.direct_pointed_typetinletexpr=Cil.stripCastsexprinmatchtrivially_alignedexprpointed_towith|Yes->ifnotremove_trivialthenon_alarm~invalid:false(Alarms.Unaligned_pointer(expr,pointed_to))|No->on_alarm~invalid:true(Alarms.Unaligned_pointer(expr,pointed_to))|Maybe->on_alarm~invalid:false(Alarms.Unaligned_pointer(expr,pointed_to))letbool_value~remove_trivial~on_alarmlv=matchremove_trivial,lvwith|true,(Varvi,NoOffset)(* This optimization can be generalized if we check strict aliasing *)when(* consider as trivial accesses to ... *)(notvi.vglob)&&(* local variable or formal parameter when ... *)(notvi.vaddrof)(* their address is not taken *)->()|_->on_alarm~invalid:false(Alarms.Invalid_boollv)