12
12
#include " goto_check.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>
@@ -277,6 +278,23 @@ class goto_checkt
277
278
bool enable_assumptions;
278
279
bool enable_pointer_primitive_check;
279
280
281
+ // / Maps a named-check name to the corresponding boolean flag.
282
+ std::map<irep_idt, bool *> name_to_flag{
283
+ {" no-enum-check" , &no_enum_check},
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
+
280
298
typedef optionst::value_listt error_labelst;
281
299
error_labelst error_labels;
282
300
@@ -287,6 +305,35 @@ class goto_checkt
287
305
allocationst allocations;
288
306
289
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);
312
+
313
+ // / \brief Adds "disable" pragmas for all named checks
314
+ // / on the given source location.
315
+ void add_all_disable_named_check_pragmas (source_locationt &source_location);
316
+
317
+ // / activation statuses for named checks
318
+ typedef enum
319
+ {
320
+ ENABLE,
321
+ DISABLE,
322
+ CHECKED
323
+ } check_statust;
324
+
325
+ // / optional (named-check, status) pair
326
+ typedef optionalt<std::pair<irep_idt, check_statust>> named_check_statust;
327
+
328
+ // / Matches a named-check string of the form
329
+ // /
330
+ // / ```
331
+ // / ("enable"|"disable"|"checked") ":" <named-check>
332
+ // / ```
333
+ // /
334
+ // / \returns a pair (name, status) if the match succeeds
335
+ // / and the name is known, nothing otherwise.
336
+ named_check_statust match_named_check (irep_idt named_check);
290
337
};
291
338
292
339
void goto_checkt::collect_allocations (
@@ -1575,6 +1622,8 @@ void goto_checkt::add_guarded_property(
1575
1622
t->source_location_nonconst ().set_comment (
1576
1623
comment + " in " + source_expr_string);
1577
1624
t->source_location_nonconst ().set_property_class (property_class);
1625
+
1626
+ add_all_disable_named_check_pragmas (t->source_location_nonconst ());
1578
1627
}
1579
1628
}
1580
1629
@@ -1877,11 +1926,24 @@ class flag_resett
1877
1926
instruction.source_location ().pretty ());
1878
1927
if (flag != new_value)
1879
1928
{
1880
- flags_to_reset. emplace ( &flag, flag) ;
1929
+ flags_to_reset[ &flag] = flag;
1881
1930
flag = new_value;
1882
1931
}
1883
1932
}
1884
1933
1934
+ // / \brief Sets the given flag to false, overriding any previous value.
1935
+ // /
1936
+ // / Contrary to \ref set_flag, does not trigger an INVARIANT
1937
+ // / if the flag was already seen before.
1938
+ void disable (bool &flag)
1939
+ {
1940
+ if (flag != false )
1941
+ {
1942
+ flags_to_reset[&flag] = flag;
1943
+ flag = false ;
1944
+ }
1945
+ }
1946
+
1885
1947
// / \brief Restore the values of all flags that have been
1886
1948
// / modified via `set_flag`.
1887
1949
~flag_resett ()
@@ -1917,63 +1979,40 @@ void goto_checkt::goto_check(
1917
1979
goto_programt::instructiont &i=*it;
1918
1980
1919
1981
flag_resett resetter (i);
1982
+ std::list<bool *> already_checked;
1920
1983
const auto &pragmas = i.source_location ().get_pragmas ();
1921
1984
for (const auto &d : pragmas)
1922
1985
{
1923
- if (d.first == " disable:bounds-check" )
1924
- resetter.set_flag (enable_bounds_check, false , d.first );
1925
- else if (d.first == " disable:pointer-check" )
1926
- resetter.set_flag (enable_pointer_check, false , d.first );
1927
- else if (d.first == " disable:memory-leak-check" )
1928
- resetter.set_flag (enable_memory_leak_check, false , d.first );
1929
- else if (d.first == " disable:div-by-zero-check" )
1930
- resetter.set_flag (enable_div_by_zero_check, false , d.first );
1931
- else if (d.first == " disable:enum-range-check" )
1932
- resetter.set_flag (enable_enum_range_check, false , d.first );
1933
- else if (d.first == " disable:signed-overflow-check" )
1934
- resetter.set_flag (enable_signed_overflow_check, false , d.first );
1935
- else if (d.first == " disable:unsigned-overflow-check" )
1936
- resetter.set_flag (enable_unsigned_overflow_check, false , d.first );
1937
- else if (d.first == " disable:pointer-overflow-check" )
1938
- resetter.set_flag (enable_pointer_overflow_check, false , d.first );
1939
- else if (d.first == " disable:float-overflow-check" )
1940
- resetter.set_flag (enable_float_overflow_check, false , d.first );
1941
- else if (d.first == " disable:conversion-check" )
1942
- resetter.set_flag (enable_conversion_check, false , d.first );
1943
- else if (d.first == " disable:undefined-shift-check" )
1944
- resetter.set_flag (enable_undefined_shift_check, false , d.first );
1945
- else if (d.first == " disable:nan-check" )
1946
- resetter.set_flag (enable_nan_check, false , d.first );
1947
- else if (d.first == " disable:pointer-primitive-check" )
1948
- resetter.set_flag (enable_pointer_primitive_check, false , d.first );
1949
- else if (d.first == " enable:bounds-check" )
1950
- resetter.set_flag (enable_bounds_check, true , d.first );
1951
- else if (d.first == " enable:pointer-check" )
1952
- resetter.set_flag (enable_pointer_check, true , d.first );
1953
- else if (d.first == " enable:memory_leak-check" )
1954
- resetter.set_flag (enable_memory_leak_check, true , d.first );
1955
- else if (d.first == " enable:div-by-zero-check" )
1956
- resetter.set_flag (enable_div_by_zero_check, true , d.first );
1957
- else if (d.first == " enable:enum-range-check" )
1958
- resetter.set_flag (enable_enum_range_check, true , d.first );
1959
- else if (d.first == " enable:signed-overflow-check" )
1960
- resetter.set_flag (enable_signed_overflow_check, true , d.first );
1961
- else if (d.first == " enable:unsigned-overflow-check" )
1962
- resetter.set_flag (enable_unsigned_overflow_check, true , d.first );
1963
- else if (d.first == " enable:pointer-overflow-check" )
1964
- resetter.set_flag (enable_pointer_overflow_check, true , d.first );
1965
- else if (d.first == " enable:float-overflow-check" )
1966
- resetter.set_flag (enable_float_overflow_check, true , d.first );
1967
- else if (d.first == " enable:conversion-check" )
1968
- resetter.set_flag (enable_conversion_check, true , d.first );
1969
- else if (d.first == " enable:undefined-shift-check" )
1970
- resetter.set_flag (enable_undefined_shift_check, true , d.first );
1971
- else if (d.first == " enable:nan-check" )
1972
- resetter.set_flag (enable_nan_check, true , d.first );
1973
- else if (d.first == " enable:pointer-primitive-check" )
1974
- resetter.set_flag (enable_pointer_primitive_check, true , d.first );
1986
+ // match named-check related pragmas
1987
+ auto parsed = match_named_check (d.first );
1988
+ if (parsed.has_value ())
1989
+ {
1990
+ auto named_check = parsed.value ();
1991
+ auto name = named_check.first ;
1992
+ auto status = named_check.second ;
1993
+ bool *flag = name_to_flag.find (name)->second ;
1994
+ switch (status)
1995
+ {
1996
+ case check_statust::ENABLE:
1997
+ resetter.set_flag (*flag, true , name);
1998
+ break ;
1999
+ case check_statust::DISABLE:
2000
+ resetter.set_flag (*flag, false , name);
2001
+ break ;
2002
+ case check_statust::CHECKED:
2003
+ already_checked.push_back (flag);
2004
+ break ;
2005
+ }
2006
+ }
1975
2007
}
1976
2008
2009
+ // inhibit already checked checks
2010
+ for (auto flag : already_checked)
2011
+ resetter.disable (*flag);
2012
+
2013
+ // add checked pragmas for all active checks
2014
+ add_active_named_check_pragmas (i.source_location_nonconst ());
2015
+
1977
2016
new_code.clear ();
1978
2017
1979
2018
// we clear all recorded assertions if
@@ -2453,3 +2492,48 @@ void goto_check(
2453
2492
const namespacet ns (goto_model.symbol_table );
2454
2493
goto_check (ns, options, goto_model.goto_functions , message_handler);
2455
2494
}
2495
+
2496
+ void goto_checkt::add_active_named_check_pragmas (
2497
+ source_locationt &source_location)
2498
+ {
2499
+ for (auto it : name_to_flag)
2500
+ if (*(it.second ))
2501
+ source_location.add_pragma (" checked:" + id2string (it.first ));
2502
+ }
2503
+
2504
+ void goto_checkt::add_all_disable_named_check_pragmas (
2505
+ source_locationt &source_location)
2506
+ {
2507
+ for (auto it : name_to_flag)
2508
+ source_location.add_pragma (" disable:" + id2string (it.first ));
2509
+ }
2510
+
2511
+ goto_checkt::named_check_statust
2512
+ goto_checkt::match_named_check (irep_idt named_check)
2513
+ {
2514
+ auto s = id2string (named_check);
2515
+ auto status = check_statust::DISABLE;
2516
+ if (s.find (" enable:" ) == 0 )
2517
+ {
2518
+ status = check_statust::ENABLE;
2519
+ }
2520
+ else if (s.find (" disable:" ) == 0 )
2521
+ {
2522
+ status = check_statust::DISABLE;
2523
+ }
2524
+ else if (s.find (" checked:" ) == 0 )
2525
+ {
2526
+ status = check_statust::CHECKED;
2527
+ }
2528
+ else
2529
+ {
2530
+ return {};
2531
+ }
2532
+
2533
+ auto sep = s.find (" :" );
2534
+ auto name = s.substr (sep + 1 );
2535
+ if (name_to_flag.find (name) == name_to_flag.end ())
2536
+ return {};
2537
+
2538
+ return std::pair<irep_idt, check_statust>{name, status};
2539
+ }
0 commit comments