@@ -25,6 +25,9 @@ Date: January 2022
25
25
26
26
#include " utils.h"
27
27
28
+ // / header for log messages
29
+ static const char LOG_HEADER[] = " assigns clause checking: " ;
30
+
28
31
// / Pragma used to mark assignments to static locals that need to be propagated
29
32
static const char PROPAGATE_STATIC_LOCAL_PRAGMA[] =
30
33
" contracts:propagate-static-local" ;
@@ -691,8 +694,9 @@ exprt instrument_spec_assignst::inclusion_check_full(
691
694
}
692
695
693
696
if (allow_null_lhs)
694
- return or_exprt{null_pointer (car.target_start_address ()),
695
- and_exprt{car.valid_var (), disjunction (disjuncts)}};
697
+ return or_exprt{
698
+ null_pointer (car.target_start_address ()),
699
+ and_exprt{car.valid_var (), disjunction (disjuncts)}};
696
700
else
697
701
return and_exprt{car.valid_var (), disjunction (disjuncts)};
698
702
}
@@ -713,6 +717,8 @@ const car_exprt &instrument_spec_assignst::create_car_from_spec_assigns(
713
717
}
714
718
else
715
719
{
720
+ log .debug () << LOG_HEADER << " creating CAR for assigns clause target "
721
+ << format (condition) << " : " << format (target) << messaget::eom;
716
722
from_spec_assigns.insert ({key, create_car_expr (condition, target)});
717
723
return from_spec_assigns.find (key)->second ;
718
724
}
@@ -731,6 +737,8 @@ const car_exprt &instrument_spec_assignst::create_car_from_stack_alloc(
731
737
}
732
738
else
733
739
{
740
+ log .debug () << LOG_HEADER << " creating CAR for stack-allocated target "
741
+ << format (target) << messaget::eom;
734
742
from_stack_alloc.insert ({target, create_car_expr (true_exprt{}, target)});
735
743
return from_stack_alloc.find (target)->second ;
736
744
}
@@ -749,6 +757,8 @@ instrument_spec_assignst::create_car_from_heap_alloc(const exprt &target)
749
757
}
750
758
else
751
759
{
760
+ log .debug () << LOG_HEADER << " creating CAR for heap-allocated target "
761
+ << format (target) << messaget::eom;
752
762
from_heap_alloc.insert ({target, create_car_expr (true_exprt{}, target)});
753
763
return from_heap_alloc.find (target)->second ;
754
764
}
@@ -767,6 +777,8 @@ const car_exprt &instrument_spec_assignst::create_car_from_static_local(
767
777
}
768
778
else
769
779
{
780
+ log .debug () << LOG_HEADER << " creating CAR for static local target "
781
+ << format (target) << messaget::eom;
770
782
from_static_local.insert ({target, create_car_expr (true_exprt{}, target)});
771
783
return from_static_local.find (target)->second ;
772
784
}
@@ -806,44 +818,107 @@ bool instrument_spec_assignst::must_check_assign(
806
818
skip_function_paramst skip_function_params,
807
819
const optionalt<cfg_infot> cfg_info_opt)
808
820
{
809
- if (
810
- const auto &symbol_expr =
811
- expr_try_dynamic_cast <symbol_exprt>(target->assign_lhs ()))
821
+ log . debug (). source_location = target-> source_location ();
822
+
823
+ if (can_cast_expr <symbol_exprt>(target->assign_lhs ()))
812
824
{
825
+ const auto &symbol_expr = to_symbol_expr (target->assign_lhs ());
813
826
if (
814
827
skip_function_params == skip_function_paramst::NO &&
815
- ns.lookup (symbol_expr-> get_identifier ()).is_parameter )
828
+ ns.lookup (symbol_expr. get_identifier ()).is_parameter )
816
829
{
830
+ log .debug () << LOG_HEADER << " checking assignment to function parameter "
831
+ << format (symbol_expr) << messaget::eom;
817
832
return true ;
818
833
}
819
834
820
835
if (cfg_info_opt.has_value ())
821
- return !cfg_info_opt.value ().is_local (symbol_expr->get_identifier ());
836
+ {
837
+ if (cfg_info_opt.value ().is_local (symbol_expr.get_identifier ()))
838
+ {
839
+ log .debug () << LOG_HEADER
840
+ << " skipping checking on assignment to local symbol "
841
+ << format (symbol_expr) << messaget::eom;
842
+ return false ;
843
+ }
844
+ else
845
+ {
846
+ log .debug () << LOG_HEADER << " checking assignment to non-local symbol "
847
+ << format (symbol_expr) << messaget::eom;
848
+ return true ;
849
+ }
850
+ }
851
+ log .debug () << LOG_HEADER << " checking assignment to symbol "
852
+ << format (symbol_expr) << messaget::eom;
853
+ return true ;
854
+ }
855
+ else
856
+ {
857
+ // This is not a mere symbol.
858
+ // Since non-dirty locals are not tracked explicitly in the write set,
859
+ // we need to skip the check if we can verify that the expression describes
860
+ // an access to a non-dirty local symbol or an input parameter,
861
+ // otherwise the check will fail.
862
+ // In addition, the expression shall not contain address_of or dereference
863
+ // operators, regardless of the base symbol/object on which they apply.
864
+ // If the expression contains an address_of operation, the assignment gets
865
+ // checked. If the base object is a local or a parameter, it will also be
866
+ // flagged as dirty and will be tracked explicitly, and the check will pass.
867
+ // If the expression contains a dereference operation, the assignment gets
868
+ // checked. If the dereferenced address was computed from a local object,
869
+ // from a function parameter or returned by a local malloc,
870
+ // then the object will be tracked explicitly and the check will pass.
871
+ // In all other cases (address of a non-local object, or dereference of
872
+ // a non-locally computed address) the location must be given explicitly
873
+ // in the assigns clause to be tracked and we must check the assignment.
874
+ if (
875
+ cfg_info_opt.has_value () &&
876
+ cfg_info_opt.value ().is_local_composite_access (target->assign_lhs ()))
877
+ {
878
+ log .debug ()
879
+ << LOG_HEADER
880
+ << " skipping check on assignment to local composite member expression "
881
+ << format (target->assign_lhs ()) << messaget::eom;
882
+ return false ;
883
+ }
884
+ log .debug () << LOG_HEADER << " checking assignment to expression "
885
+ << format (target->assign_lhs ()) << messaget::eom;
886
+ return true ;
822
887
}
888
+ }
823
889
824
- return true ;
890
+ // / Track the symbol iff we have no cfg_infot, or we have a cfg_infot and the
891
+ // / symbol is not a local or is a dirty local.
892
+ bool instrument_spec_assignst::must_track_decl_or_dead (
893
+ const irep_idt &ident,
894
+ const optionalt<cfg_infot> &cfg_info_opt) const
895
+ {
896
+ return !cfg_info_opt.has_value () ||
897
+ (cfg_info_opt.has_value () &&
898
+ cfg_info_opt.value ().is_not_local_or_dirty_local (ident));
825
899
}
826
900
827
- // / Returns true iff a `DECL x` must be added to the local write set.
828
- // /
829
- // / A variable is called 'dirty' if its address gets taken at some point in
830
- // / the program.
831
- // /
832
- // / Assuming the goto program is obtained from a structured C program that
833
- // / passed C compiler checks, non-dirty variables can only be assigned to
834
- // / directly by name, cannot escape their lexical scope, and are always safe
835
- // / to assign. Hence, we only track dirty variables in the write set.
901
+ // / Returns true iff a `DECL x` must be explicitly tracked in the write set.
836
902
bool instrument_spec_assignst::must_track_decl (
837
903
const goto_programt::const_targett &target,
838
904
const optionalt<cfg_infot> &cfg_info_opt) const
839
905
{
840
- if (cfg_info_opt.has_value ())
906
+ log .debug ().source_location = target->source_location ();
907
+ if (must_track_decl_or_dead (
908
+ target->decl_symbol ().get_identifier (), cfg_info_opt))
841
909
{
842
- return cfg_info_opt.value ().is_not_local_or_dirty_local (
843
- target->decl_symbol ().get_identifier ());
910
+ log .debug () << LOG_HEADER << " explicitly tracking "
911
+ << format (target->decl_symbol ()) << " as assignable"
912
+ << messaget::eom;
913
+ return true ;
914
+ }
915
+ else
916
+ {
917
+ log .debug () << LOG_HEADER << " implicitly tracking "
918
+ << format (target->decl_symbol ())
919
+ << " as assignable (non-dirty local)" << messaget::eom;
920
+ return false ;
844
921
}
845
- // Unless proved non-dirty by the CFG analysis we assume it is dirty.
846
- return true ;
847
922
}
848
923
849
924
// / Returns true iff a `DEAD x` must be processed to upate the local write set.
@@ -852,12 +927,8 @@ bool instrument_spec_assignst::must_track_dead(
852
927
const goto_programt::const_targett &target,
853
928
const optionalt<cfg_infot> &cfg_info_opt) const
854
929
{
855
- // Unless proved non-dirty by the CFG analysis we assume it is dirty.
856
- if (!cfg_info_opt.has_value ())
857
- return true ;
858
-
859
- return cfg_info_opt.value ().is_not_local_or_dirty_local (
860
- target->dead_symbol ().get_identifier ());
930
+ return must_track_decl_or_dead (
931
+ target->dead_symbol ().get_identifier (), cfg_info_opt);
861
932
}
862
933
863
934
void instrument_spec_assignst::instrument_assign_statement (
0 commit comments