Skip to content

Commit d8aa948

Browse files
author
Remi Delmas
committed
Adds support for "checked:named-check" pragmas to avoid redudant instrumentation.
When several invocations to goto-instrument/cmbc are performed with named-check flags, the same assertions were generated several times, and assertions generated by a check A in some pass would be instrumented by a check B in some ulterior pass. "checked" pragmas allow to keep track of which checks have been performed on which instructions and are saved in the goto binaries, hence surviving across invocations of the tools. The presente of a "checked" pragma for a given check on an instruction prevents future invocations of the tools to generate again the assertions of that check. We also tag all assertions generated by goto_check with "disable" pragmas to avoid instrumenting instrumentation assertions in ulterior invocations of the tool.
1 parent d42839d commit d8aa948

File tree

1 file changed

+137
-53
lines changed

1 file changed

+137
-53
lines changed

src/analyses/goto_check.cpp

Lines changed: 137 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#include "goto_check.h"
1313

1414
#include <algorithm>
15+
#include <optional>
1516

1617
#include <util/arith_tools.h>
1718
#include <util/array_name.h>
@@ -277,6 +278,23 @@ class goto_checkt
277278
bool enable_assumptions;
278279
bool enable_pointer_primitive_check;
279280

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+
280298
typedef optionst::value_listt error_labelst;
281299
error_labelst error_labels;
282300

@@ -287,6 +305,35 @@ class goto_checkt
287305
allocationst allocations;
288306

289307
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);
290337
};
291338

292339
void goto_checkt::collect_allocations(
@@ -1575,6 +1622,8 @@ void goto_checkt::add_guarded_property(
15751622
t->source_location_nonconst().set_comment(
15761623
comment + " in " + source_expr_string);
15771624
t->source_location_nonconst().set_property_class(property_class);
1625+
1626+
add_all_disable_named_check_pragmas(t->source_location_nonconst());
15781627
}
15791628
}
15801629

@@ -1877,11 +1926,24 @@ class flag_resett
18771926
instruction.source_location().pretty());
18781927
if(flag != new_value)
18791928
{
1880-
flags_to_reset.emplace(&flag, flag);
1929+
flags_to_reset[&flag] = flag;
18811930
flag = new_value;
18821931
}
18831932
}
18841933

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+
18851947
/// \brief Restore the values of all flags that have been
18861948
/// modified via `set_flag`.
18871949
~flag_resett()
@@ -1917,63 +1979,40 @@ void goto_checkt::goto_check(
19171979
goto_programt::instructiont &i=*it;
19181980

19191981
flag_resett resetter(i);
1982+
std::list<bool *> already_checked;
19201983
const auto &pragmas = i.source_location().get_pragmas();
19211984
for(const auto &d : pragmas)
19221985
{
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+
}
19752007
}
19762008

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+
19772016
new_code.clear();
19782017

19792018
// we clear all recorded assertions if
@@ -2453,3 +2492,48 @@ void goto_check(
24532492
const namespacet ns(goto_model.symbol_table);
24542493
goto_check(ns, options, goto_model.goto_functions, message_handler);
24552494
}
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

Comments
 (0)