@@ -337,6 +337,82 @@ class goto_check_ct
337337 named_check_statust match_named_check (const irep_idt &named_check) const ;
338338};
339339
340+ // / Allows to:
341+ // / - override a Boolean flag with a new value via `set_flag`
342+ // / - set a Boolean flag to false via `disable_flag`, such that
343+ // / previous `set_flag` are overridden and future `set_flag` are ignored.
344+ // /
345+ // / A flag's initial value (before any `set_flag` or `disable_flag`) is restored
346+ // / when the entire object goes out of scope.
347+ class flag_overridet
348+ {
349+ public:
350+ explicit flag_overridet (const source_locationt &source_location)
351+ : source_location(source_location)
352+ {
353+ }
354+
355+ // / \brief Store the current value of \p flag and
356+ // / then set its value to \p new_value.
357+ // /
358+ // / - calling `set_flag` after `disable_flag` is a no-op
359+ // / - calling `set_flag` twice triggers an INVARIANT
360+ void set_flag (bool &flag, bool new_value, const irep_idt &flag_name)
361+ {
362+ // make this a no-op if the flag is disabled
363+ if (disabled_flags.find (&flag) != disabled_flags.end ())
364+ return ;
365+
366+ // detect double sets
367+ INVARIANT (
368+ flags_to_reset.find (&flag) == flags_to_reset.end (),
369+ " Flag " + id2string (flag_name) + " set twice at \n " +
370+ source_location.as_string ());
371+ if (flag != new_value)
372+ {
373+ flags_to_reset[&flag] = flag;
374+ flag = new_value;
375+ }
376+ }
377+
378+ // / Sets the given flag to false, overriding any previous value.
379+ // /
380+ // / - calling `disable_flag` after `set_flag` overrides the set value
381+ // / - calling `disable_flag` twice triggers an INVARIANT
382+ void disable_flag (bool &flag, const irep_idt &flag_name)
383+ {
384+ INVARIANT (
385+ disabled_flags.find (&flag) == disabled_flags.end (),
386+ " Flag " + id2string (flag_name) + " disabled twice at \n " +
387+ source_location.as_string ());
388+
389+ disabled_flags.insert (&flag);
390+
391+ // If the flag has not already been set,
392+ // we store its current value in the reset map.
393+ // Otherwise, the reset map already holds
394+ // the initial value we want to reset it to, keep it as is.
395+ if (flags_to_reset.find (&flag) == flags_to_reset.end ())
396+ flags_to_reset[&flag] = flag;
397+
398+ // set the flag to false in all cases.
399+ flag = false ;
400+ }
401+
402+ // / \brief Restore the values of all flags that have been
403+ // / modified via `set_flag`.
404+ ~flag_overridet ()
405+ {
406+ for (const auto &flag_pair : flags_to_reset)
407+ *flag_pair.first = flag_pair.second ;
408+ }
409+
410+ private:
411+ const source_locationt &source_location;
412+ std::map<bool *, bool > flags_to_reset;
413+ std::set<bool *> disabled_flags;
414+ };
415+
340416static exprt implication (exprt lhs, exprt rhs)
341417{
342418 // rewrite a => (b => c) to (a && b) => c
@@ -1267,6 +1343,32 @@ void goto_check_ct::pointer_overflow_check(
12671343 expr.operands ().size () == 2 ,
12681344 " pointer arithmetic expected to have exactly 2 operands" );
12691345
1346+ // multiplying the offset by the object size must not result in arithmetic
1347+ // overflow
1348+ const typet &object_type = to_pointer_type (expr.type ()).base_type ();
1349+ if (object_type.id () != ID_empty)
1350+ {
1351+ auto size_of_expr_opt = size_of_expr (object_type, ns);
1352+ CHECK_RETURN (size_of_expr_opt.has_value ());
1353+ exprt object_size = size_of_expr_opt.value ();
1354+
1355+ const binary_exprt &binary_expr = to_binary_expr (expr);
1356+ exprt offset_operand = binary_expr.lhs ().type ().id () == ID_pointer
1357+ ? binary_expr.rhs ()
1358+ : binary_expr.lhs ();
1359+ mult_exprt mul{
1360+ offset_operand,
1361+ typecast_exprt::conditional_cast (object_size, offset_operand.type ())};
1362+ mul.add_source_location () = offset_operand.source_location ();
1363+
1364+ flag_overridet override_overflow (offset_operand.source_location ());
1365+ override_overflow.set_flag (
1366+ enable_signed_overflow_check, true , " signed_overflow_check" );
1367+ override_overflow.set_flag (
1368+ enable_unsigned_overflow_check, true , " unsigned_overflow_check" );
1369+ integer_overflow_check (mul, guard);
1370+ }
1371+
12701372 // the result must be within object bounds or one past the end
12711373 const auto size = from_integer (0 , size_type ());
12721374 auto conditions = get_pointer_dereferenceable_conditions (expr, size);
@@ -1927,82 +2029,6 @@ optionalt<exprt> goto_check_ct::rw_ok_check(exprt expr)
19272029 return {};
19282030}
19292031
1930- // / Allows to:
1931- // / - override a Boolean flag with a new value via `set_flag`
1932- // / - set a Boolean flag to false via `disable_flag`, such that
1933- // / previous `set_flag` are overridden and future `set_flag` are ignored.
1934- // /
1935- // / A flag's initial value (before any `set_flag` or `disable_flag`) is restored
1936- // / when the entire object goes out of scope.
1937- class flag_resett
1938- {
1939- public:
1940- explicit flag_resett (const goto_programt::instructiont &_instruction)
1941- : instruction(_instruction)
1942- {
1943- }
1944-
1945- // / \brief Store the current value of \p flag and
1946- // / then set its value to \p new_value.
1947- // /
1948- // / - calling `set_flag` after `disable_flag` is a no-op
1949- // / - calling `set_flag` twice triggers an INVARIANT
1950- void set_flag (bool &flag, bool new_value, const irep_idt &flag_name)
1951- {
1952- // make this a no-op if the flag is disabled
1953- if (disabled_flags.find (&flag) != disabled_flags.end ())
1954- return ;
1955-
1956- // detect double sets
1957- INVARIANT (
1958- flags_to_reset.find (&flag) == flags_to_reset.end (),
1959- " Flag " + id2string (flag_name) + " set twice at \n " +
1960- instruction.source_location ().pretty ());
1961- if (flag != new_value)
1962- {
1963- flags_to_reset[&flag] = flag;
1964- flag = new_value;
1965- }
1966- }
1967-
1968- // / Sets the given flag to false, overriding any previous value.
1969- // /
1970- // / - calling `disable_flag` after `set_flag` overrides the set value
1971- // / - calling `disable_flag` twice triggers an INVARIANT
1972- void disable_flag (bool &flag, const irep_idt &flag_name)
1973- {
1974- INVARIANT (
1975- disabled_flags.find (&flag) == disabled_flags.end (),
1976- " Flag " + id2string (flag_name) + " disabled twice at \n " +
1977- instruction.source_location ().pretty ());
1978-
1979- disabled_flags.insert (&flag);
1980-
1981- // If the flag has not already been set,
1982- // we store its current value in the reset map.
1983- // Otherwise, the reset map already holds
1984- // the initial value we want to reset it to, keep it as is.
1985- if (flags_to_reset.find (&flag) == flags_to_reset.end ())
1986- flags_to_reset[&flag] = flag;
1987-
1988- // set the flag to false in all cases.
1989- flag = false ;
1990- }
1991-
1992- // / \brief Restore the values of all flags that have been
1993- // / modified via `set_flag`.
1994- ~flag_resett ()
1995- {
1996- for (const auto &flag_pair : flags_to_reset)
1997- *flag_pair.first = flag_pair.second ;
1998- }
1999-
2000- private:
2001- const goto_programt::instructiont &instruction;
2002- std::map<bool *, bool > flags_to_reset;
2003- std::set<bool *> disabled_flags;
2004- };
2005-
20062032void goto_check_ct::goto_check (
20072033 const irep_idt &function_identifier,
20082034 goto_functiont &goto_function)
@@ -2027,7 +2053,7 @@ void goto_check_ct::goto_check(
20272053 current_target = it;
20282054 goto_programt::instructiont &i = *it;
20292055
2030- flag_resett resetter (i);
2056+ flag_overridet resetter (i. source_location () );
20312057 const auto &pragmas = i.source_location ().get_pragmas ();
20322058 for (const auto &d : pragmas)
20332059 {
@@ -2110,7 +2136,7 @@ void goto_check_ct::goto_check(
21102136 // Disable enum range checks for left-hand sides as their values are yet
21112137 // to be set (by this assignment).
21122138 {
2113- flag_resett resetter (i);
2139+ flag_overridet resetter (i. source_location () );
21142140 resetter.disable_flag (enable_enum_range_check, " enum_range_check" );
21152141 check (assign_lhs);
21162142 }
0 commit comments