|
| 1 | +# Shadow Memory |
| 2 | + |
| 3 | +(The original artefact's implementation is outlined in the paper [CBMC-SSM: |
| 4 | +Bounded Model Checking of C Programs with Symbolic Shadow |
| 5 | +Memory](https://dl.acm.org/doi/abs/10.1145/3551349.3559523).) |
| 6 | + |
| 7 | +## Introduction |
| 8 | + |
| 9 | +CBMC contains a component that supports *Symbolic Shadow Memory*. Shadow memory |
| 10 | +allows one to create a parallel memory structure that is maintained by the |
| 11 | +analysis program and that shadows the standard memory of the program. In that |
| 12 | +memory structure, a user can create fields, for which he can later set and |
| 13 | +retrieve values. |
| 14 | + |
| 15 | +By doing so, one can organise his own tracking of metadata related to the code, |
| 16 | +in a way that is then considered by the backend of CBMC during analysis. This |
| 17 | +can be used to implement novel analyses that the CBMC framework itself doesn't |
| 18 | +support - for example, the paper above presents as an example a taint analysis |
| 19 | +implemented with the use of the SSM component described here. |
| 20 | + |
| 21 | +## Usage |
| 22 | + |
| 23 | +A user can interact with the Symbolic Shadow Memory component (from now on |
| 24 | +onwards, SSM) through four CBMC primitives, which allow one to declare shadow |
| 25 | +memory fields, and retrieve/set their corresponding values: |
| 26 | + |
| 27 | +* `__CPROVER_field_decl_local` |
| 28 | +* `__CPROVER_field_decl_global` |
| 29 | +* `__CPROVER_get_field` |
| 30 | +* `__CPROVER_set_field` |
| 31 | + |
| 32 | +More precisely, their signatures (in pseudo-C, because of some constraints that |
| 33 | +we can't express using the type system), along with some small examples of their |
| 34 | +usage, look like this: |
| 35 | + |
| 36 | +### `void __CPROVER_field_decl_local(type1 field_name, SSM_value_type init_value)` |
| 37 | + |
| 38 | +Type constraints: |
| 39 | + |
| 40 | +* `type1`: string literal, such as `"field"`, |
| 41 | +* `SSM_value_type`: value of maximum 8 bits, signed or unsigned or `_Bool`. |
| 42 | + |
| 43 | +Declares a local (working for variable declared in the current function scope) |
| 44 | +shadow memory field called `field_name`, and initialises it with the value |
| 45 | +`init_value`. The field is going to be associated with local-scope objects (i.e. |
| 46 | +a variable on the stack). |
| 47 | + |
| 48 | +```c |
| 49 | +void func() { |
| 50 | + // Sample local object (local variable) |
| 51 | + char x = 0; |
| 52 | + |
| 53 | + // Shadow memory field associated with local objects. |
| 54 | + __CPROVER_field_decl_local("shadow", (_Bool)1); |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +### `void __CPROVER_field_decl_global(type1 field_name, SSM_value_type init_value)` |
| 59 | + |
| 60 | +Type constraints: |
| 61 | + |
| 62 | +* `type1`: string literal, such as `"field"`, |
| 63 | +* `SSM_value_type`: value of maximum 8 bits, signed or unsigned or `_Bool`. |
| 64 | + |
| 65 | +Ditto as above, but the field declared is associated with global objects (i.e. |
| 66 | +global variables or heap allocated objects). |
| 67 | + |
| 68 | +```c |
| 69 | +// Sample global object |
| 70 | +int a = 10; |
| 71 | + |
| 72 | +void func() { |
| 73 | + // Shadow memory field associated with global objects. |
| 74 | + __CPROVER_field_decl_global("shadow", (_Bool)0); |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +### `SSM_VALUE_TYPE __CPROVER_get_field(type1 *p, type2 field_name)` |
| 79 | + |
| 80 | +Type constraints: |
| 81 | + |
| 82 | +* `SSM_VALUE_TYPE`: the type of the value that was used to intialise the field |
| 83 | + with during declaration, |
| 84 | +* `type1 *`: a non-`void` pointer to an object of type `type1`, whose address we |
| 85 | + are going to use for indexing the shadow memory component for the field |
| 86 | + declared, |
| 87 | +* `type2`: a string literal-typed value, denoting the name of the field whose |
| 88 | + value we want to retrieve, such as `"field"`. |
| 89 | + |
| 90 | +Retrieves the value (currently) associated with a SSM field of the given |
| 91 | +pointer. This would be either the value the field was declared to be initialised |
| 92 | +with, or, if there had been subsequent changes to it through a `__CPROVER_set_field`, |
| 93 | +the value that it was last `set` with. |
| 94 | + |
| 95 | +```c |
| 96 | +// Sample global object |
| 97 | +int a = 10; |
| 98 | + |
| 99 | +void func() { |
| 100 | + // Shadow memory field (called "field") associated with global objects. |
| 101 | + __CPROVER_field_decl_global("shadow", (_Bool)0); |
| 102 | + |
| 103 | + _Bool shadow_x = __CPROVER_get_field(&a, "shadow"); |
| 104 | + __CPROVER_assert(shadow_x == 0, "expected success: field initialised with 0"); |
| 105 | + __CPROVER_assert(shadow_x == 1, "expected fail: field initialised with 0"); |
| 106 | +} |
| 107 | +``` |
| 108 | + |
| 109 | +### `void __CPROVER_set_field(type1 *p, type2 field_name, type3 set_value)` |
| 110 | + |
| 111 | +Type constraints: |
| 112 | + |
| 113 | +* `type1 *`: a non-`void` pointer to an object of type `type1`, whose address we |
| 114 | + are going to use for indexing the shadow memory component for the field |
| 115 | + declared, |
| 116 | +* `type2`: a string literal-typed value, denoting the name of the field whose |
| 117 | + value we want to retrieve, such as `"field"`, |
| 118 | +* `type3`: type of the value to be set. This can be `_Bool` or of any integer |
| 119 | + type signed or unsigned. Notice that if this type differs from the type the |
| 120 | + field was declared with (`SSM_VALUE_TYPE` above) it will be implicitly casted |
| 121 | + to it. |
| 122 | + |
| 123 | +Sets the value of an SSM field, using the name supplied by the `field name` as an |
| 124 | +identifier for the field and using the pointer in `p` as the address for the location |
| 125 | +of the value to be changed, to the given value, supplied by the third argument |
| 126 | +`set_value`. This value needs to be of the same type as the type of the value the |
| 127 | +field was originally initialised with. |
| 128 | + |
| 129 | +```c |
| 130 | +// Sample global object |
| 131 | +int a = 10; |
| 132 | + |
| 133 | +void func() { |
| 134 | + // Shadow memory field (called "field") associated with global objects. |
| 135 | + // Originally assigned a value of `1`, of type `_Bool`. |
| 136 | + __CPROVER_field_decl_global("shadow", (_Bool)1); |
| 137 | + |
| 138 | + // Set field "shadow" for the memory location denoted by the address of `a` |
| 139 | + // to a value of 0. |
| 140 | + __CPROVER_set_field(&a, "shadow", 0); |
| 141 | + |
| 142 | + // Retrieve the value of the field named "shadow" associated with the address |
| 143 | + // of the object `a`. |
| 144 | + _Bool shadow_x = __CPROVER_get_field(&a, "shadow"); |
| 145 | + __CPROVER_assert(shadow_x == 0, "expected success: field set to a value of 0"); |
| 146 | + __CPROVER_assert(shadow_x == 1, "expected fail: field set to a value of 0"); |
| 147 | +} |
| 148 | +``` |
0 commit comments