Skip to content

Gather shadow memory fields #7535

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions regression/cbmc-shadow-memory/declarations1/bad1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
void bad_declaration1()
{
__CPROVER_field_decl_local("field1", (int)0);
}
8 changes: 8 additions & 0 deletions regression/cbmc-shadow-memory/declarations1/bad2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
void bad_declaration2()
{
struct STRUCT
{
char x;
} s;
__CPROVER_field_decl_global("field2", s);
}
5 changes: 5 additions & 0 deletions regression/cbmc-shadow-memory/declarations1/good.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
void good_declarations()
{
__CPROVER_field_decl_local("field1", (_Bool)0);
__CPROVER_field_decl_global("field2", (unsigned __CPROVER_bitvector[6])0);
}
9 changes: 9 additions & 0 deletions regression/cbmc-shadow-memory/declarations1/test_bad1.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
bad1.c
--function bad_declaration1 --verbosity 10
^EXIT=6$
^SIGNAL=0$
^A shadow memory field must not be larger than 8 bits.
--
--
Test that a shadow memory declaration of a too large type is rejected.
9 changes: 9 additions & 0 deletions regression/cbmc-shadow-memory/declarations1/test_bad2.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
bad2.c
--function bad_declaration2 --verbosity 10
^EXIT=6$
^SIGNAL=0$
^A shadow memory field must be of a bitvector type.
--
--
Test that a shadow memory declaration of a non-bitvector type is rejected.
12 changes: 12 additions & 0 deletions regression/cbmc-shadow-memory/declarations1/test_good.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CORE
good.c
--function good_declarations --verbosity 10
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
^Shadow memory: declare local field field1 of type c_bool\[8\]
^Shadow memory: declare global field field2 of type unsignedbv\[6\]
--
^A shadow memory field must
--
Test that shadow memory declarations are correctly gathered.
1 change: 1 addition & 0 deletions src/goto-symex/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ SRC = auto_objects.cpp \
precondition.cpp \
renaming_level.cpp \
shadow_memory.cpp \
shadow_memory_util.cpp \
show_program.cpp \
show_vcc.cpp \
slice.cpp \
Expand Down
81 changes: 75 additions & 6 deletions src/goto-symex/shadow_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ Author: Peter Schrammel

#include "shadow_memory.h"

#include <util/bitvector_types.h>
#include <util/format_type.h>
#include <util/fresh_symbol.h>

#include <langapi/language_util.h>

#include "goto_symex_state.h"
#include "shadow_memory_util.h"

void shadow_memoryt::initialize_shadow_memory(
goto_symex_statet &state,
Expand Down Expand Up @@ -95,17 +98,83 @@ void shadow_memoryt::symex_field_dynamic_init(
}

shadow_memory_field_definitionst shadow_memoryt::gather_field_declarations(
abstract_goto_modelt &goto_model,
const abstract_goto_modelt &goto_model,
message_handlert &message_handler)
{
// To be implemented

return shadow_memory_field_definitionst();
shadow_memory_field_definitionst field_definitions;

// Gather shadow memory declarations from goto model
for(const auto &goto_function : goto_model.get_goto_functions().function_map)
{
const auto &goto_program = goto_function.second.body;
forall_goto_program_instructions(target, goto_program)
{
if(!target->is_function_call())
continue;

const auto &code_function_call = to_code_function_call(target->code());
const exprt &function = code_function_call.function();

if(function.id() != ID_symbol)
continue;

const irep_idt &identifier = to_symbol_expr(function).get_identifier();

if(
identifier ==
CPROVER_PREFIX SHADOW_MEMORY_FIELD_DECL SHADOW_MEMORY_GLOBAL_SCOPE)
{
convert_field_declaration(
code_function_call,
field_definitions.global_fields,
true,
message_handler);
}
else if(
identifier ==
CPROVER_PREFIX SHADOW_MEMORY_FIELD_DECL SHADOW_MEMORY_LOCAL_SCOPE)
{
convert_field_declaration(
code_function_call,
field_definitions.local_fields,
false,
message_handler);
}
}
}
return field_definitions;
}

void shadow_memoryt::convert_field_declaration(
const code_function_callt &code_function_call,
shadow_memory_field_definitionst::field_definitiont &fields)
shadow_memory_field_definitionst::field_definitiont &fields,
bool is_global,
message_handlert &message_handler)
{
// To be implemented
INVARIANT(
code_function_call.arguments().size() == 2,
std::string(CPROVER_PREFIX) + SHADOW_MEMORY_FIELD_DECL +
(is_global ? SHADOW_MEMORY_GLOBAL_SCOPE : SHADOW_MEMORY_LOCAL_SCOPE) +
" requires 2 arguments");
irep_idt field_name = extract_field_name(code_function_call.arguments()[0]);

exprt expr = code_function_call.arguments()[1];

messaget log(message_handler);
log.debug() << "Shadow memory: declare " << (is_global ? "global " : "local ")
<< "field " << id2string(field_name) << " of type "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: no need for id2string here.

<< format(expr.type()) << messaget::eom;
if(!can_cast_type<bitvector_typet>(expr.type()))
{
throw unsupported_operation_exceptiont(
"A shadow memory field must be of a bitvector type.");
}
if(to_bitvector_type(expr.type()).get_width() > 8)
{
throw unsupported_operation_exceptiont(
"A shadow memory field must not be larger than 8 bits.");
}
Comment on lines +167 to +176
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we please catch this in the front-end and just have a DATA_INVARIANT here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be doable, but it would mean splitting up the logic over multiple modules, i.e. there will be shadow memory-specific logic in the front end - I tried to avoid that by postponing these checks, but I can of course change this if preferred.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be more user-friendly to catch problems early. If the front-end can tell the user that something will necessarily fail then IMHO it should do so.


// record the field's initial value (and type)
fields[field_name] = expr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a matter of style, but I'd prefer this method to return a pair (field_name, expr) and have the caller put this in place (the caller might choose insert or firmly replace).

}
10 changes: 7 additions & 3 deletions src/goto-symex/shadow_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class shadow_memoryt
/// \param message_handler For logging
/// \return The field definitions
static shadow_memory_field_definitionst gather_field_declarations(
abstract_goto_modelt &goto_model,
const abstract_goto_modelt &goto_model,
message_handlert &message_handler);

/// Initialize global-scope shadow memory for global/static variables.
Expand Down Expand Up @@ -100,9 +100,13 @@ class shadow_memoryt
/// Converts a field declaration
/// \param code_function_call The __CPROVER_field_decl_* call
/// \param fields The field declaration to be extended
void convert_field_declaration(
/// \param is_global True if the declaration is global
/// \param message_handler For logging
static void convert_field_declaration(
const code_function_callt &code_function_call,
shadow_memory_field_definitionst::field_definitiont &fields);
shadow_memory_field_definitionst::field_definitiont &fields,
bool is_global,
message_handlert &message_handler);

/// Allocates and initializes a shadow memory field for the given original
/// memory.
Expand Down
32 changes: 32 additions & 0 deletions src/goto-symex/shadow_memory_util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*******************************************************************\

Module: Symex Shadow Memory Instrumentation

Author: Peter Schrammel

\*******************************************************************/

/// \file
/// Symex Shadow Memory Instrumentation Utilities

#include "shadow_memory_util.h"

#include <util/invariant.h>
#include <util/pointer_expr.h>
#include <util/std_expr.h>

irep_idt extract_field_name(const exprt &string_expr)
{
if(string_expr.id() == ID_typecast)
return extract_field_name(to_typecast_expr(string_expr).op());
else if(string_expr.id() == ID_address_of)
return extract_field_name(to_address_of_expr(string_expr).object());
else if(string_expr.id() == ID_index)
return extract_field_name(to_index_expr(string_expr).array());
else if(string_expr.id() == ID_string_constant)
{
return string_expr.get(ID_value);
}
Comment on lines +26 to +29
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: is there a reason for using braces (just!) here?

else
UNREACHABLE;
}
25 changes: 25 additions & 0 deletions src/goto-symex/shadow_memory_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************\

Module: Symex Shadow Memory Instrumentation

Author: Peter Schrammel

\*******************************************************************/

/// \file
/// Symex Shadow Memory Instrumentation Utilities

#ifndef CPROVER_GOTO_SYMEX_SHADOW_MEMORY_UTIL_H
#define CPROVER_GOTO_SYMEX_SHADOW_MEMORY_UTIL_H

#include <util/irep.h>

class exprt;

/// Extracts the field name identifier from a string expression,
/// e.g. as passed as argument to a __CPROVER_field_decl_local call.
/// \param string_expr The string argument expression
/// \return The identifier denoted by the string argument expression
irep_idt extract_field_name(const exprt &string_expr);

#endif // CPROVER_GOTO_SYMEX_SHADOW_MEMORY_STATE_H