@@ -12,6 +12,7 @@ Author: Daniel Kroening, kroening@kroening.com
1212#include " goto_check_c.h"
1313
1414#include < algorithm>
15+ #include < optional>
1516
1617#include < util/arith_tools.h>
1718#include < util/array_name.h>
@@ -278,6 +279,22 @@ class goto_check_ct
278279 bool enable_assumptions;
279280 bool enable_pointer_primitive_check;
280281
282+ // / Maps a named-check name to the corresponding boolean flag.
283+ std::map<irep_idt, bool *> name_to_flag{
284+ {" bounds-check" , &enable_bounds_check},
285+ {" pointer-check" , &enable_pointer_check},
286+ {" memory-leak-check" , &enable_memory_leak_check},
287+ {" div-by-zero-check" , &enable_div_by_zero_check},
288+ {" enum-range-check" , &enable_enum_range_check},
289+ {" signed-overflow-check" , &enable_signed_overflow_check},
290+ {" unsigned-overflow-check" , &enable_unsigned_overflow_check},
291+ {" pointer-overflow-check" , &enable_pointer_overflow_check},
292+ {" conversion-check" , &enable_conversion_check},
293+ {" undefined-shift-check" , &enable_undefined_shift_check},
294+ {" float-overflow-check" , &enable_float_overflow_check},
295+ {" nan-check" , &enable_nan_check},
296+ {" pointer-primitive-check" , &enable_pointer_primitive_check}};
297+
281298 typedef optionst::value_listt error_labelst;
282299 error_labelst error_labels;
283300
@@ -288,6 +305,36 @@ class goto_check_ct
288305 allocationst allocations;
289306
290307 irep_idt mode;
308+
309+ // / \brief Adds "checked" pragmas for all currently active named checks
310+ // / on the given source location.
311+ void add_active_named_check_pragmas (source_locationt &source_location) const ;
312+
313+ // / \brief Adds "disable" pragmas for all named checks
314+ // / on the given source location.
315+ void
316+ add_all_disable_named_check_pragmas (source_locationt &source_location) const ;
317+
318+ // / activation statuses for named checks
319+ typedef enum
320+ {
321+ ENABLE,
322+ DISABLE,
323+ CHECKED
324+ } check_statust;
325+
326+ // / optional (named-check, status) pair
327+ using named_check_statust = optionalt<std::pair<irep_idt, check_statust>>;
328+
329+ // / Matches a named-check string of the form
330+ // /
331+ // / ```
332+ // / ("enable"|"disable"|"checked") ":" <named-check>
333+ // / ```
334+ // /
335+ // / \returns a pair (name, status) if the match succeeds
336+ // / and the name is known, nothing otherwise.
337+ named_check_statust match_named_check (const irep_idt &named_check) const ;
291338};
292339
293340void goto_check_ct::collect_allocations (const goto_functionst &goto_functions)
@@ -1566,6 +1613,8 @@ void goto_check_ct::add_guarded_property(
15661613 t->source_location_nonconst ().set_comment (
15671614 comment + " in " + source_expr_string);
15681615 t->source_location_nonconst ().set_property_class (property_class);
1616+
1617+ add_all_disable_named_check_pragmas (t->source_location_nonconst ());
15691618 }
15701619}
15711620
@@ -1840,11 +1889,13 @@ optionalt<exprt> goto_check_ct::rw_ok_check(exprt expr)
18401889 return {};
18411890}
18421891
1843- // / \brief Set a Boolean flag to a new value (via `set_flag`) and restore
1844- // / the previous value when the entire object goes out of scope.
1892+ // / Allows to:
1893+ // / - override a Boolean flag with a new value via `set_flag`
1894+ // / - set a Boolean flag to false via `disable_flag`, such that
1895+ // / previous `set_flag` are overridden and future `set_flag` are ignored.
18451896// /
1846- // / \remarks Calls to set_value are tracked to allow detecting doubles sets
1847- // / with different values and trigger an INVARIANT .
1897+ // / A flag's initial value (before any `set_flag` or `disable_flag`) is restored
1898+ // / when the entire object goes out of scope .
18481899class flag_resett
18491900{
18501901public:
@@ -1856,24 +1907,50 @@ class flag_resett
18561907 // / \brief Store the current value of \p flag and
18571908 // / then set its value to \p new_value.
18581909 // /
1859- // / \remarks an INVARIANT triggers iff the flag is set
1860- // / more than once with different values.
1910+ // / - calling `set_flag` after `disable_flag` is a no-op
1911+ // / - calling `set_flag` twice triggers an INVARIANT
18611912 void set_flag (bool &flag, bool new_value, const irep_idt &flag_name)
18621913 {
1863- bool seen = flags_to_reset.find (&flag) != flags_to_reset.end ();
1914+ // make this a no-op if the flag is disabled
1915+ if (disabled_flags.find (&flag) != disabled_flags.end ())
1916+ return ;
1917+
1918+ // detect double sets
18641919 INVARIANT (
1865- !(seen && flag != new_value),
1866- " Flag " + id2string (flag_name) +
1867- " set twice with incompatible values "
1868- " at \n " +
1920+ flags_to_reset.find (&flag) == flags_to_reset.end (),
1921+ " Flag " + id2string (flag_name) + " set twice at \n " +
18691922 instruction.source_location ().pretty ());
18701923 if (flag != new_value)
18711924 {
1872- flags_to_reset. emplace ( &flag, flag) ;
1925+ flags_to_reset[ &flag] = flag;
18731926 flag = new_value;
18741927 }
18751928 }
18761929
1930+ // / Sets the given flag to false, overriding any previous value.
1931+ // /
1932+ // / - calling `disable_flag` after `set_flag` overrides the set value
1933+ // / - calling `disable_flag` twice triggers an INVARIANT
1934+ void disable_flag (bool &flag, const irep_idt &flag_name)
1935+ {
1936+ INVARIANT (
1937+ disabled_flags.find (&flag) == disabled_flags.end (),
1938+ " Flag " + id2string (flag_name) + " disabled twice at \n " +
1939+ instruction.source_location ().pretty ());
1940+
1941+ disabled_flags.insert (&flag);
1942+
1943+ // If the flag has not already been set,
1944+ // we store its current value in the reset map.
1945+ // Otherwise, the reset map already holds
1946+ // the initial value we want to reset it to, keep it as is.
1947+ if (flags_to_reset.find (&flag) == flags_to_reset.end ())
1948+ flags_to_reset[&flag] = flag;
1949+
1950+ // set the flag to false in all cases.
1951+ flag = false ;
1952+ }
1953+
18771954 // / \brief Restore the values of all flags that have been
18781955 // / modified via `set_flag`.
18791956 ~flag_resett ()
@@ -1885,6 +1962,7 @@ class flag_resett
18851962private:
18861963 const goto_programt::instructiont &instruction;
18871964 std::map<bool *, bool > flags_to_reset;
1965+ std::set<bool *> disabled_flags;
18881966};
18891967
18901968void goto_check_ct::goto_check (
@@ -1915,60 +1993,32 @@ void goto_check_ct::goto_check(
19151993 const auto &pragmas = i.source_location ().get_pragmas ();
19161994 for (const auto &d : pragmas)
19171995 {
1918- if (d.first == " disable:bounds-check" )
1919- resetter.set_flag (enable_bounds_check, false , d.first );
1920- else if (d.first == " disable:pointer-check" )
1921- resetter.set_flag (enable_pointer_check, false , d.first );
1922- else if (d.first == " disable:memory-leak-check" )
1923- resetter.set_flag (enable_memory_leak_check, false , d.first );
1924- else if (d.first == " disable:div-by-zero-check" )
1925- resetter.set_flag (enable_div_by_zero_check, false , d.first );
1926- else if (d.first == " disable:enum-range-check" )
1927- resetter.set_flag (enable_enum_range_check, false , d.first );
1928- else if (d.first == " disable:signed-overflow-check" )
1929- resetter.set_flag (enable_signed_overflow_check, false , d.first );
1930- else if (d.first == " disable:unsigned-overflow-check" )
1931- resetter.set_flag (enable_unsigned_overflow_check, false , d.first );
1932- else if (d.first == " disable:pointer-overflow-check" )
1933- resetter.set_flag (enable_pointer_overflow_check, false , d.first );
1934- else if (d.first == " disable:float-overflow-check" )
1935- resetter.set_flag (enable_float_overflow_check, false , d.first );
1936- else if (d.first == " disable:conversion-check" )
1937- resetter.set_flag (enable_conversion_check, false , d.first );
1938- else if (d.first == " disable:undefined-shift-check" )
1939- resetter.set_flag (enable_undefined_shift_check, false , d.first );
1940- else if (d.first == " disable:nan-check" )
1941- resetter.set_flag (enable_nan_check, false , d.first );
1942- else if (d.first == " disable:pointer-primitive-check" )
1943- resetter.set_flag (enable_pointer_primitive_check, false , d.first );
1944- else if (d.first == " enable:bounds-check" )
1945- resetter.set_flag (enable_bounds_check, true , d.first );
1946- else if (d.first == " enable:pointer-check" )
1947- resetter.set_flag (enable_pointer_check, true , d.first );
1948- else if (d.first == " enable:memory_leak-check" )
1949- resetter.set_flag (enable_memory_leak_check, true , d.first );
1950- else if (d.first == " enable:div-by-zero-check" )
1951- resetter.set_flag (enable_div_by_zero_check, true , d.first );
1952- else if (d.first == " enable:enum-range-check" )
1953- resetter.set_flag (enable_enum_range_check, true , d.first );
1954- else if (d.first == " enable:signed-overflow-check" )
1955- resetter.set_flag (enable_signed_overflow_check, true , d.first );
1956- else if (d.first == " enable:unsigned-overflow-check" )
1957- resetter.set_flag (enable_unsigned_overflow_check, true , d.first );
1958- else if (d.first == " enable:pointer-overflow-check" )
1959- resetter.set_flag (enable_pointer_overflow_check, true , d.first );
1960- else if (d.first == " enable:float-overflow-check" )
1961- resetter.set_flag (enable_float_overflow_check, true , d.first );
1962- else if (d.first == " enable:conversion-check" )
1963- resetter.set_flag (enable_conversion_check, true , d.first );
1964- else if (d.first == " enable:undefined-shift-check" )
1965- resetter.set_flag (enable_undefined_shift_check, true , d.first );
1966- else if (d.first == " enable:nan-check" )
1967- resetter.set_flag (enable_nan_check, true , d.first );
1968- else if (d.first == " enable:pointer-primitive-check" )
1969- resetter.set_flag (enable_pointer_primitive_check, true , d.first );
1996+ // match named-check related pragmas
1997+ auto matched = match_named_check (d.first );
1998+ if (matched.has_value ())
1999+ {
2000+ auto named_check = matched.value ();
2001+ auto name = named_check.first ;
2002+ auto status = named_check.second ;
2003+ bool *flag = name_to_flag.find (name)->second ;
2004+ switch (status)
2005+ {
2006+ case check_statust::ENABLE:
2007+ resetter.set_flag (*flag, true , name);
2008+ break ;
2009+ case check_statust::DISABLE:
2010+ resetter.set_flag (*flag, false , name);
2011+ break ;
2012+ case check_statust::CHECKED:
2013+ resetter.disable_flag (*flag, name);
2014+ break ;
2015+ }
2016+ }
19702017 }
19712018
2019+ // add checked pragmas for all active checks
2020+ add_active_named_check_pragmas (i.source_location_nonconst ());
2021+
19722022 new_code.clear ();
19732023
19742024 // we clear all recorded assertions if
@@ -2398,3 +2448,46 @@ void goto_check_c(
23982448 const namespacet ns (goto_model.symbol_table );
23992449 goto_check_c (ns, options, goto_model.goto_functions , message_handler);
24002450}
2451+
2452+ void goto_check_ct::add_active_named_check_pragmas (
2453+ source_locationt &source_location) const
2454+ {
2455+ for (const auto &entry : name_to_flag)
2456+ if (*(entry.second ))
2457+ source_location.add_pragma (" checked:" + id2string (entry.first ));
2458+ }
2459+
2460+ void goto_check_ct::add_all_disable_named_check_pragmas (
2461+ source_locationt &source_location) const
2462+ {
2463+ for (const auto &entry : name_to_flag)
2464+ source_location.add_pragma (" disable:" + id2string (entry.first ));
2465+ }
2466+
2467+ goto_check_ct::named_check_statust
2468+ goto_check_ct::match_named_check (const irep_idt &named_check) const
2469+ {
2470+ auto s = id2string (named_check);
2471+ auto col = s.find (" :" );
2472+
2473+ if (col == std::string::npos)
2474+ return {}; // separator not found
2475+
2476+ auto name = s.substr (col + 1 );
2477+
2478+ if (name_to_flag.find (name) == name_to_flag.end ())
2479+ return {}; // name unknown
2480+
2481+ check_statust status;
2482+ if (!s.compare (0 , 6 , " enable" ))
2483+ status = check_statust::ENABLE;
2484+ else if (!s.compare (0 , 7 , " disable" ))
2485+ status = check_statust::DISABLE;
2486+ else if (!s.compare (0 , 7 , " checked" ))
2487+ status = check_statust::CHECKED;
2488+ else
2489+ return {}; // prefix unknow
2490+
2491+ // success
2492+ return std::pair<irep_idt, check_statust>{name, status};
2493+ }
0 commit comments