@@ -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,91 @@ 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. We skip the check only if we can verify that
858
+ // this is an access to a locally declared symbol
859
+ if (
860
+ cfg_info_opt.has_value () &&
861
+ cfg_info_opt.value ().is_access_to_local_composite (target->assign_lhs ()))
862
+ {
863
+ log .debug () << LOG_HEADER
864
+ << " skipping check on assignment to local expression "
865
+ << format (target->assign_lhs ()) << messaget::eom;
866
+ return false ;
867
+ }
868
+ log .debug () << LOG_HEADER << " checking assignment to expression "
869
+ << format (target->assign_lhs ()) << messaget::eom;
870
+ return true ;
822
871
}
872
+ }
823
873
824
- return true ;
874
+ // / Track the symbol iff we have no cfg_infot, or we have a cfg_infot and the
875
+ // / symbol is not a local or is a dirty local.
876
+ bool instrument_spec_assignst::must_track_decl_or_dead (
877
+ const irep_idt &ident,
878
+ const optionalt<cfg_infot> &cfg_info_opt) const
879
+ {
880
+ return !cfg_info_opt.has_value () ||
881
+ (cfg_info_opt.has_value () &&
882
+ cfg_info_opt.value ().is_not_local_or_dirty_local (ident));
825
883
}
826
884
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.
885
+ // / Returns true iff a `DECL x` must be explicitly tracked in the write set.
836
886
bool instrument_spec_assignst::must_track_decl (
837
887
const goto_programt::const_targett &target,
838
888
const optionalt<cfg_infot> &cfg_info_opt) const
839
889
{
840
- if (cfg_info_opt.has_value ())
890
+ log .debug ().source_location = target->source_location ();
891
+ if (must_track_decl_or_dead (
892
+ target->decl_symbol ().get_identifier (), cfg_info_opt))
841
893
{
842
- return cfg_info_opt.value ().is_not_local_or_dirty_local (
843
- target->decl_symbol ().get_identifier ());
894
+ log .debug () << LOG_HEADER << " explicitly tracking "
895
+ << format (target->decl_symbol ()) << " as assignable"
896
+ << messaget::eom;
897
+ return true ;
898
+ }
899
+ else
900
+ {
901
+ log .debug () << LOG_HEADER << " implicitly tracking "
902
+ << format (target->decl_symbol ())
903
+ << " as assignable (non-dirty local)" << messaget::eom;
904
+ return false ;
844
905
}
845
- // Unless proved non-dirty by the CFG analysis we assume it is dirty.
846
- return true ;
847
906
}
848
907
849
908
// / Returns true iff a `DEAD x` must be processed to upate the local write set.
@@ -852,12 +911,8 @@ bool instrument_spec_assignst::must_track_dead(
852
911
const goto_programt::const_targett &target,
853
912
const optionalt<cfg_infot> &cfg_info_opt) const
854
913
{
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 ());
914
+ return must_track_decl_or_dead (
915
+ target->dead_symbol ().get_identifier (), cfg_info_opt);
861
916
}
862
917
863
918
void instrument_spec_assignst::instrument_assign_statement (
0 commit comments