12
12
#include " goto_check_c.h"
13
13
14
14
#include < algorithm>
15
+ #include < optional>
15
16
16
17
#include < util/arith_tools.h>
17
18
#include < util/array_name.h>
@@ -278,6 +279,22 @@ class goto_check_ct
278
279
bool enable_assumptions;
279
280
bool enable_pointer_primitive_check;
280
281
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
+
281
298
typedef optionst::value_listt error_labelst;
282
299
error_labelst error_labels;
283
300
@@ -288,6 +305,36 @@ class goto_check_ct
288
305
allocationst allocations;
289
306
290
307
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 ;
291
338
};
292
339
293
340
void goto_check_ct::collect_allocations (const goto_functionst &goto_functions)
@@ -1566,6 +1613,8 @@ void goto_check_ct::add_guarded_property(
1566
1613
t->source_location_nonconst ().set_comment (
1567
1614
comment + " in " + source_expr_string);
1568
1615
t->source_location_nonconst ().set_property_class (property_class);
1616
+
1617
+ add_all_disable_named_check_pragmas (t->source_location_nonconst ());
1569
1618
}
1570
1619
}
1571
1620
@@ -1840,11 +1889,13 @@ optionalt<exprt> goto_check_ct::rw_ok_check(exprt expr)
1840
1889
return {};
1841
1890
}
1842
1891
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.
1845
1896
// /
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 .
1848
1899
class flag_resett
1849
1900
{
1850
1901
public:
@@ -1856,24 +1907,50 @@ class flag_resett
1856
1907
// / \brief Store the current value of \p flag and
1857
1908
// / then set its value to \p new_value.
1858
1909
// /
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
1861
1912
void set_flag (bool &flag, bool new_value, const irep_idt &flag_name)
1862
1913
{
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
1864
1919
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 " +
1869
1922
instruction.source_location ().pretty ());
1870
1923
if (flag != new_value)
1871
1924
{
1872
- flags_to_reset. emplace ( &flag, flag) ;
1925
+ flags_to_reset[ &flag] = flag;
1873
1926
flag = new_value;
1874
1927
}
1875
1928
}
1876
1929
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
+
1877
1954
// / \brief Restore the values of all flags that have been
1878
1955
// / modified via `set_flag`.
1879
1956
~flag_resett ()
@@ -1885,6 +1962,7 @@ class flag_resett
1885
1962
private:
1886
1963
const goto_programt::instructiont &instruction;
1887
1964
std::map<bool *, bool > flags_to_reset;
1965
+ std::set<bool *> disabled_flags;
1888
1966
};
1889
1967
1890
1968
void goto_check_ct::goto_check (
@@ -1915,60 +1993,32 @@ void goto_check_ct::goto_check(
1915
1993
const auto &pragmas = i.source_location ().get_pragmas ();
1916
1994
for (const auto &d : pragmas)
1917
1995
{
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
+ }
1970
2017
}
1971
2018
2019
+ // add checked pragmas for all active checks
2020
+ add_active_named_check_pragmas (i.source_location_nonconst ());
2021
+
1972
2022
new_code.clear ();
1973
2023
1974
2024
// we clear all recorded assertions if
@@ -2398,3 +2448,46 @@ void goto_check_c(
2398
2448
const namespacet ns (goto_model.symbol_table );
2399
2449
goto_check_c (ns, options, goto_model.goto_functions , message_handler);
2400
2450
}
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