Skip to content

Commit 6f275f7

Browse files
Deprecate __CPROVER_allocated_memory in favour of --mmio-region
Emit a warning at analysis time when __CPROVER_allocated_memory is encountered, directing users to --mmio-region instead. Update the CProver manual to list --mmio-region as the recommended mechanism and mark __CPROVER_allocated_memory as deprecated. Remove the dead code branch in linker_script_merge.cpp that used __CPROVER_allocated_memory. The active implementation already creates proper array symbols without relying on the deprecated function. Co-authored-by: Kiro (autonomous agent) <kiro-agent@users.noreply.github.com>
1 parent 9681603 commit 6f275f7

File tree

5 files changed

+38
-123
lines changed

5 files changed

+38
-123
lines changed

doc/cprover-manual/modeling-mmio.md

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,26 @@ as an out-of-bounds memory reference. This is an example of
2828
implementation-defined behavior that must be modeled to avoid reporting false
2929
positives.
3030

31-
CBMC uses the built-in function `__CPROVER_allocated_memory(address, size)` to
32-
mark ranges of memory as valid. Accesses within this region are exempt from the
33-
out-of-bounds assertion checking that CBMC would normally do. The function
34-
declares the half-open interval [address, address + size) as valid memory that
35-
can be read and written.
36-
37-
This function can be used anywhere in the source code, but is most commonly used
38-
in the verification harness. Note that there is no flow sensitivity or scope
39-
restriction: CBMC considers accesses to memory regions marked as above valid for
40-
read or write access even before the call to the built-in function is
41-
encountered.
31+
CBMC provides two mechanisms for declaring memory-mapped I/O regions:
32+
33+
1. **`--mmio-region address:size` (recommended):** Declare regions on the
34+
command line. Each region becomes a byte-array object in the symbol table.
35+
Reads and writes to addresses within a declared region are redirected to the
36+
corresponding array element. See the
37+
[per-region object model](#per-region-object-model-recommended) section below.
38+
39+
2. **`__CPROVER_allocated_memory(address, size)` (deprecated):** A built-in
40+
function that marks the half-open interval [address, address + size) as valid
41+
memory. Accesses within this region are exempt from out-of-bounds assertion
42+
checking. This function can be used anywhere in the source code, but is most
43+
commonly used in the verification harness. Note that there is no flow
44+
sensitivity or scope restriction: CBMC considers accesses to memory regions
45+
marked as above valid for read or write access even before the call to the
46+
built-in function is encountered.
47+
48+
> **Deprecation notice:** `__CPROVER_allocated_memory` is deprecated. Use
49+
> `--mmio-region` instead, which provides better scalability and does not
50+
> require source-code changes.
4251
4352
### Device behavior
4453

regression/cbmc/memory_allocation2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ main.c
44
^EXIT=10$
55
^SIGNAL=0$
66
^\[main\.array_bounds\.[1-2]\] .*: SUCCESS$
7-
^\[main\.array_bounds\.3\] line 38 array.buffer (dynamic object )?upper bound in buffers\[(\(signed long (long )?int\))?0\]->buffer\[(\(signed long (long )?int\))?100\]: FAILURE$
7+
^\[main\.array_bounds\.3\] line 40 array.buffer (dynamic object )?upper bound in buffers\[(\(signed long (long )?int\))?0\]->buffer\[(\(signed long (long )?int\))?100\]: FAILURE$
88
^\*\* 1 of \d failed
99
^VERIFICATION FAILED$
1010
--

regression/cbmc/union12/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33

44
^EXIT=10$
55
^SIGNAL=0$
6-
^\[main\.assertion\.2\] line 20 should fail: FAILURE$
6+
^\[main\.assertion\.2\] line 22 should fail: FAILURE$
77
^\*\* 1 of \d+ failed
88
^VERIFICATION FAILED$
99
--

src/ansi-c/goto-conversion/goto_check_c.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,12 @@ void goto_check_ct::collect_allocations(const goto_functionst &goto_functions)
457457
throw "expected two unsigned arguments to " CPROVER_PREFIX
458458
"allocated_memory";
459459

460+
log.warning()
461+
<< instruction.source_location().as_string() << ": "
462+
<< "__CPROVER_allocated_memory is deprecated, "
463+
<< "use --mmio-region on the command line instead"
464+
<< messaget::eom;
465+
460466
DATA_INVARIANT(
461467
args[0].type() == args[1].type(),
462468
"arguments of allocated_memory must have same type");

src/goto-cc/linker_script_merge.cpp

Lines changed: 10 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -358,58 +358,21 @@ void linker_script_merget::symbols_to_pointerize(
358358
symbols_to_pointerize(linker_values, op, to_pointerize);
359359
}
360360

361-
#if 0
362-
The current implementation of this function is less precise than the
363-
commented-out version below. To understand the difference between these
364-
implementations, consider the following example:
365-
366-
Suppose we have a section in the linker script, 100 bytes long, where the
367-
address of the symbol sec_start is the start of the section (value 4096) and the
368-
address of sec_end is the end of that section (value 4196).
369-
370-
The current implementation synthesizes the goto-version of the following C:
371-
372-
char __sec_array[100];
373-
char *sec_start=(&__sec_array[0]);
374-
char *sec_end=((&__sec_array[0])+100);
375-
// Yes, it is 100 not 99. We're pointing to the end of the memory occupied
376-
// by __sec_array, not the last element of __sec_array.
377-
378-
This is imprecise for the following reason: the actual address of the array and
379-
the pointers shall be some random CBMC-internal address, instead of being 4096
380-
and 4196. The linker script, on the other hand, would have specified the exact
381-
position of the section, and we even know what the actual values of sec_start
382-
and sec_end are from the object file (these values are in the `addresses` list
383-
of the `data` argument to this function). If the correctness of the code depends
384-
on these actual values, then CBMCs model of the code is too imprecise to verify
385-
this.
386-
387-
The commented-out version of this function below synthesizes the following:
388-
389-
char *sec_start=4096;
390-
char *sec_end=4196;
391-
__CPROVER_allocated_memory(4096, 100);
392-
393-
This code has both the actual addresses of the start and end of the section and
394-
tells CBMC that the intermediate region is valid. However, the allocated_memory
395-
macro does not currently allocate an actual object at the address 4096, so
396-
symbolic execution can fail. In particular, the 'allocated memory' is part of
397-
__CPROVER_memory, which does not have a bounded size; this means that (for
398-
example) calls to memcpy or memset fail, because the first and third arguments
399-
do not have know n size. The commented-out implementation should be reinstated
400-
once this limitation of __CPROVER_allocated_memory has been fixed.
401-
402-
In either case, no other changes to the rest of the code (outside this function)
403-
should be necessary. The rest of this file converts expressions containing the
404-
linker-defined symbol into pointer types if they were not already, and this is
405-
the right behaviour for both implementations.
406-
#endif
361+
// The implementation of ls_data2instructions synthesizes the goto-version of:
362+
//
363+
// char __sec_array[100];
364+
// char *sec_start=(&__sec_array[0]);
365+
// char *sec_end=((&__sec_array[0])+100);
366+
//
367+
// This is imprecise because the actual address of the array will be a
368+
// CBMC-internal address rather than the real address from the linker script.
369+
// If the correctness of the code depends on the actual numeric addresses,
370+
// CBMC's model is too imprecise to verify this.
407371
int linker_script_merget::ls_data2instructions(
408372
jsont &data,
409373
const std::string &linker_script,
410374
symbol_tablet &symbol_table,
411375
linker_valuest &linker_values)
412-
#if 1
413376
{
414377
std::map<irep_idt, std::size_t> truncated_symbols;
415378
for(auto &d : to_json_array(data["regions"]))
@@ -596,69 +559,6 @@ int linker_script_merget::ls_data2instructions(
596559
}
597560
return 0;
598561
}
599-
#else
600-
{
601-
goto_programt::instructionst initialize_instructions=gp.instructions;
602-
for(const auto &d : to_json_array(data["regions"]))
603-
{
604-
unsigned start=safe_string2unsigned(d["start"].value);
605-
unsigned size=safe_string2unsigned(d["size"].value);
606-
constant_exprt first=from_integer(start, size_type());
607-
constant_exprt second=from_integer(size, size_type());
608-
const code_typet void_t({}, empty_typet());
609-
code_function_callt f(
610-
symbol_exprt(CPROVER_PREFIX "allocated_memory", void_t), {first, second});
611-
612-
source_locationt loc;
613-
loc.set_file(linker_script);
614-
loc.set_comment("linker script-defined region:\n"+d["commt"].value+":\n"+
615-
d["annot"].value);
616-
f.add_source_location()=loc;
617-
618-
goto_programt::instructiont i;
619-
i.make_function_call(f);
620-
initialize_instructions.push_front(i);
621-
}
622-
623-
if(!symbol_table.has_symbol(CPROVER_PREFIX "allocated_memory"))
624-
{
625-
symbolt sym{
626-
CPROVER_PREFIX "allocated_memory",
627-
code_typet({}, empty_typet()),
628-
ID_C} sym.pretty_name = CPROVER_PREFIX "allocated_memory";
629-
sym.is_lvalue=sym.is_static_lifetime=true;
630-
symbol_table.add(sym);
631-
}
632-
633-
for(const auto &d : to_json_array(data["addresses"]))
634-
{
635-
source_locationt loc;
636-
loc.set_file(linker_script);
637-
loc.set_comment("linker script-defined symbol: char *"+
638-
d["sym"].value+"="+"(char *)"+d["val"].value+"u;");
639-
640-
symbol_exprt lhs(d["sym"].value, pointer_type(char_type()));
641-
642-
constant_exprt rhs;
643-
rhs.set_value(integer2bvrep(
644-
string2integer(d["val"].value), unsigned_int_type().get_width()));
645-
rhs.type()=unsigned_int_type();
646-
647-
exprt rhs_tc =
648-
typecast_exprt::conditional_cast(rhs, pointer_type(char_type()));
649-
650-
linker_values.emplace(
651-
irep_idt(d["sym"].value), std::make_pair(lhs, rhs_tc));
652-
653-
code_assignt assign(lhs, rhs_tc);
654-
assign.add_source_location()=loc;
655-
goto_programt::instructiont assign_i;
656-
assign_i.make_assignment(assign);
657-
initialize_instructions.push_front(assign_i);
658-
}
659-
return 0;
660-
}
661-
#endif
662562

663563
int linker_script_merget::get_linker_script_data(
664564
std::list<irep_idt> &linker_defined_symbols,

0 commit comments

Comments
 (0)