123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)openMopsatypecheck+=|CHK_PY_UNCAUGHT_EXCEPTION|CHK_PY_STOPITERATION|CHK_PY_ATTRIBUTEERROR|CHK_PY_ASSERTIONERROR|CHK_PY_INDEXERROR|CHK_PY_KEYERROR|CHK_PY_LOOKUPERROR|CHK_PY_MODULENOTFOUNDERROR|CHK_PY_NAMEERROR|CHK_PY_OVERFLOWERROR|CHK_PY_SYSTEMERROR|CHK_PY_TYPEERROR|CHK_PY_UNBOUNDLOCALERROR|CHK_PY_VALUEERROR|CHK_PY_ZERODIVISIONERRORtypealarm_kind+=A_py_uncaught_exceptionofexpr*string*Universal.Strings.Powerset.StringPower.tletraise_py_uncaught_exception_alarmexnexn_nameexn_messagesrangelatticeflow=letcs=Flow.get_callstackflowinletalarm=mk_alarm(A_py_uncaught_exception(exn,exn_name,exn_messages))csrangeinFlow.raise_alarmalarm~bottom:falselatticeflowletpy_name_to_check=function|"StopIteration"->CHK_PY_STOPITERATION|"AttributeError"->CHK_PY_ATTRIBUTEERROR|"AssertionError"->CHK_PY_ASSERTIONERROR|"IndexError"->CHK_PY_INDEXERROR|"KeyError"->CHK_PY_KEYERROR|"LookUpError"->CHK_PY_LOOKUPERROR|"ModuleNotFoundError"->CHK_PY_MODULENOTFOUNDERROR|"NameError"->CHK_PY_NAMEERROR|"OverflowError"->CHK_PY_OVERFLOWERROR|"SystemError"->CHK_PY_SYSTEMERROR|"TypeError"->CHK_PY_TYPEERROR|"UnboundLocalError"->CHK_PY_UNBOUNDLOCALERROR|"ValueError"->CHK_PY_VALUEERROR|"ZeroDivisionError"->CHK_PY_ZERODIVISIONERROR|_->CHK_PY_UNCAUGHT_EXCEPTIONletpy_check_to_name=function|CHK_PY_UNCAUGHT_EXCEPTION->"Python"|CHK_PY_STOPITERATION->"StopIteration"|CHK_PY_ATTRIBUTEERROR->"AttributeError"|CHK_PY_ASSERTIONERROR->"AssertionError"|CHK_PY_INDEXERROR->"IndexError"|CHK_PY_KEYERROR->"KeyError"|CHK_PY_LOOKUPERROR->"LookupError"|CHK_PY_MODULENOTFOUNDERROR->"ModuleNotFoundError"|CHK_PY_NAMEERROR->"NameError"|CHK_PY_OVERFLOWERROR->"OverflowError"|CHK_PY_SYSTEMERROR->"SystemError"|CHK_PY_TYPEERROR->"TypeError"|CHK_PY_UNBOUNDLOCALERROR->"UnboundLocalError"|CHK_PY_VALUEERROR->"ValueError"|CHK_PY_ZERODIVISIONERROR->"ZeroDivisionError"|_->assertfalselet()=register_check(fundefaultfmta->matchawith|CHK_PY_UNCAUGHT_EXCEPTION|CHK_PY_STOPITERATION|CHK_PY_ATTRIBUTEERROR|CHK_PY_ASSERTIONERROR|CHK_PY_INDEXERROR|CHK_PY_KEYERROR|CHK_PY_LOOKUPERROR|CHK_PY_MODULENOTFOUNDERROR|CHK_PY_NAMEERROR|CHK_PY_OVERFLOWERROR|CHK_PY_SYSTEMERROR|CHK_PY_TYPEERROR|CHK_PY_UNBOUNDLOCALERROR|CHK_PY_VALUEERROR|CHK_PY_ZERODIVISIONERROR->Format.fprintffmt"%s exception"(py_check_to_namea)|_->defaultfmta);register_alarm{check=(funnext->function|A_py_uncaught_exception(_,n,_)->py_name_to_checkn|a->nexta);compare=(fundefaultaa'->matcha,a'with|A_py_uncaught_exception(e,n,m),A_py_uncaught_exception(e',n',m')->Compare.compose[(fun()->compare_expree');(fun()->Stdlib.comparenn');(fun()->Universal.Strings.Powerset.StringPower.comparemm');]|_->defaultaa');print=(fundefaultfmta->matchawith|A_py_uncaught_exception(e,n,m)->Format.fprintffmt"Uncaught Python exception: %s: %a"n(formatUniversal.Strings.Powerset.StringPower.print)m|_->defaultfmta);join=(funnexta1a2->matcha1,a2with|A_py_uncaught_exception_,A_py_uncaught_exception_->ifcompare_alarm_kinda1a2=0thenSomea1elseNone|_->nexta1a2);}(** Flow token for exceptions *)typepy_exc_kind=|Py_exc_unprecise|Py_exc_with_callstackofrange*callstacktypetoken+=|T_py_exceptionofexpr(* the exception *)*string(* type of exception as str *)*Universal.Strings.Powerset.StringPower.t(* exception messages *)*py_exc_kindletmk_py_unprecise_exceptionobjname=T_py_exception(obj,name,Universal.Strings.Powerset.StringPower.empty,Py_exc_unprecise)letmk_py_exceptionobjnamemessages~csrange=T_py_exception(obj,name,messages,Py_exc_with_callstack(range,cs))letpp_py_exc_kindfmt=function|Py_exc_unprecise->()|Py_exc_with_callstack(range,cs)->Format.fprintffmt"%a@,%a"pp_rangerangepp_callstack_shortcslet()=register_token{compare=(funnexttk1tk2->matchtk1,tk2with|T_py_exception(e1,n1,m1,k1),T_py_exception(e2,n2,m2,k2)->Compare.compose[(fun()->compare_expre1e2);(fun()->Stdlib.comparen1n2);(fun()->Universal.Strings.Powerset.StringPower.comparem1m2);(fun()->matchk1,k2with|Py_exc_unprecise,Py_exc_unprecise->0|Py_exc_with_callstack(r1,cs1),Py_exc_with_callstack(r2,cs2)->Compare.compose[(fun()->compare_ranger1r2);(fun()->compare_callstackcs1cs2);]|_->comparek1k2);]|_->nexttk1tk2);print=(funnextfmttk->matchtkwith|T_py_exception(_,name,str,k)->Format.fprintffmt"@[<hv 2>PyExc(%s: %a)@,%a@]"name(formatUniversal.Strings.Powerset.StringPower.print)strpp_py_exc_kindk|_->nextfmttk);}typecheck+=CHK_PY_INVALID_TYPE_ANNOTATIONtypealarm_kind+=A_py_invalid_type_annotationofexpr*exprlet()=register_check(funnextfmt->function|CHK_PY_INVALID_TYPE_ANNOTATION->Format.fprintffmt" Type annotations"|a->nextfmta)let()=register_alarm{check=(funnext->function|A_py_invalid_type_annotation_->CHK_PY_INVALID_TYPE_ANNOTATION|a->nexta);compare=(funnexta1a2->matcha1,a2with|A_py_invalid_type_annotation(v1,a1),A_py_invalid_type_annotation(v2,a2)->Compare.compose[(fun()->compare_exprv1v2);(fun()->compare_expra1a2);]|_->nexta1a2);print=(funnextfmt->function|A_py_invalid_type_annotation(v,annot)->Format.fprintffmt"Variable '%a' does not satisfy annotation '%a'"pp_exprvpp_exprannot|a->nextfmta);join=(funnext->next);}