@@ -337,6 +337,82 @@ class goto_check_ct
337
337
named_check_statust match_named_check (const irep_idt &named_check) const ;
338
338
};
339
339
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
+
340
416
static exprt implication (exprt lhs, exprt rhs)
341
417
{
342
418
// rewrite a => (b => c) to (a && b) => c
@@ -1267,6 +1343,32 @@ void goto_check_ct::pointer_overflow_check(
1267
1343
expr.operands ().size () == 2 ,
1268
1344
" pointer arithmetic expected to have exactly 2 operands" );
1269
1345
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
+
1270
1372
// the result must be within object bounds or one past the end
1271
1373
const auto size = from_integer (0 , size_type ());
1272
1374
auto conditions = get_pointer_dereferenceable_conditions (expr, size);
@@ -1927,82 +2029,6 @@ optionalt<exprt> goto_check_ct::rw_ok_check(exprt expr)
1927
2029
return {};
1928
2030
}
1929
2031
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
-
2006
2032
void goto_check_ct::goto_check (
2007
2033
const irep_idt &function_identifier,
2008
2034
goto_functiont &goto_function)
@@ -2027,7 +2053,7 @@ void goto_check_ct::goto_check(
2027
2053
current_target = it;
2028
2054
goto_programt::instructiont &i = *it;
2029
2055
2030
- flag_resett resetter (i);
2056
+ flag_overridet resetter (i. source_location () );
2031
2057
const auto &pragmas = i.source_location ().get_pragmas ();
2032
2058
for (const auto &d : pragmas)
2033
2059
{
@@ -2110,7 +2136,7 @@ void goto_check_ct::goto_check(
2110
2136
// Disable enum range checks for left-hand sides as their values are yet
2111
2137
// to be set (by this assignment).
2112
2138
{
2113
- flag_resett resetter (i);
2139
+ flag_overridet resetter (i. source_location () );
2114
2140
resetter.disable_flag (enable_enum_range_check, " enum_range_check" );
2115
2141
check (assign_lhs);
2116
2142
}
0 commit comments