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